From 3dab5550407a2c2fe70a762acfdfde93311148de Mon Sep 17 00:00:00 2001 From: godofredoc Date: Fri, 12 Nov 2021 11:50:00 -0800 Subject: [PATCH 01/41] [flutter_releases] Flutter beta 2.8.0-3.1.pre Framework Cherrypicks (#93448) * Added SharedAppData to the widgets library (#93175) * 'add branch flutter-2.8-candidate.3 to enabled_branches in .ci.yaml' * 'Update Engine revision to 09f1520e8b9585d133faf1eccced9357670c6d11 for beta release 2.8.0-3.1.pre' * Pin to specific plugin version in multidex test (#93148) Co-authored-by: Hans Muller Co-authored-by: Emmanuel Garcia --- .ci.yaml | 1 + bin/internal/engine.version | 2 +- .../shared_app_data/shared_app_data.0.dart | 75 +++++++ .../shared_app_data/shared_app_data.1.dart | 66 ++++++ packages/flutter/lib/src/widgets/app.dart | 27 ++- .../lib/src/widgets/shared_app_data.dart | 201 +++++++++++++++++ packages/flutter/lib/widgets.dart | 1 + .../flutter/test/material/debug_test.dart | 2 + .../test/widgets/shared_app_data_test.dart | 205 ++++++++++++++++++ .../test_data/multidex_project.dart | 5 +- 10 files changed, 570 insertions(+), 15 deletions(-) create mode 100644 examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart create mode 100644 examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart create mode 100644 packages/flutter/lib/src/widgets/shared_app_data.dart create mode 100644 packages/flutter/test/widgets/shared_app_data_test.dart diff --git a/.ci.yaml b/.ci.yaml index 62e48dcfbdcbe..3be70a9db8e67 100755 --- a/.ci.yaml +++ b/.ci.yaml @@ -6,6 +6,7 @@ # More information at: # * https://github.com/flutter/cocoon/blob/main/CI_YAML.md enabled_branches: + - flutter-2.8-candidate.3 - main - master - dev diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c0b9666e20db0..d2dd5b33c323e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -43561d8820e03e08959f791bfbb3097ce6be5756 +09f1520e8b9585d133faf1eccced9357670c6d11 diff --git a/examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart b/examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart new file mode 100644 index 0000000000000..04a9d3e40c9bb --- /dev/null +++ b/examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart @@ -0,0 +1,75 @@ +// 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. + +// Flutter code sample for SharedAppData + +import 'package:flutter/material.dart'; + +class ShowSharedValue extends StatelessWidget { + const ShowSharedValue({ Key? key, required this.appDataKey }) : super(key: key); + + final String appDataKey; + + @override + Widget build(BuildContext context) { + // The SharedAppData.getValue() call here causes this widget to depend + // on the value of the SharedAppData's 'foo' key. If it's changed, with + // SharedAppData.setValue(), then this widget will be rebuilt. + final String value = SharedAppData.getValue(context, appDataKey, () => 'initial'); + return Text('$appDataKey: $value'); + } +} + +// Demonstrates that changes to the SharedAppData _only_ cause the dependent widgets +// to be rebuilt. In this case that's the ShowSharedValue widget that's +// displaying the value of a key whose value has been updated. +class Home extends StatefulWidget { + const Home({ Key? key }) : super(key: key); + + @override + State createState() => _HomeState(); +} + +class _HomeState extends State { + int _fooVersion = 0; + int _barVersion = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const ShowSharedValue(appDataKey: 'foo'), + const SizedBox(height: 16), + const ShowSharedValue(appDataKey: 'bar'), + const SizedBox(height: 16), + ElevatedButton( + child: const Text('change foo'), + onPressed: () { + _fooVersion += 1; + // Changing the SharedAppData's value for 'foo' causes the widgets that + // depend on 'foo' to be rebuilt. + SharedAppData.setValue(context, 'foo', 'FOO $_fooVersion'); // note: no setState() + }, + ), + const SizedBox(height: 16), + ElevatedButton( + child: const Text('change bar'), + onPressed: () { + _barVersion += 1; + SharedAppData.setValue(context, 'bar', 'BAR $_barVersion'); // note: no setState() + }, + ), + ], + ), + ), + ); + } +} + +void main() { + runApp(const MaterialApp(home: Home())); +} diff --git a/examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart b/examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart new file mode 100644 index 0000000000000..03bb83ba0ab88 --- /dev/null +++ b/examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart @@ -0,0 +1,66 @@ +// 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. + +// Flutter code sample for SharedAppData + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +// A single lazily constructed object that's shared with the entire +// application via `SharedObject.of(context)`. The value of the object +// can be changed with `SharedObject.reset(context)`. Resetting the value +// will cause all of the widgets that depend on it to be rebuilt. +class SharedObject { + SharedObject._(); + + static final Object _sharedObjectKey = Object(); + + @override + String toString() => describeIdentity(this); + + static void reset(BuildContext context) { + // Calling SharedAppData.setValue() causes dependent widgets to be rebuilt. + SharedAppData.setValue(context, _sharedObjectKey, SharedObject._()); + } + + static SharedObject of(BuildContext context) { + // If a value for _sharedObjectKey has never been set then the third + // callback parameter is used to generate an initial value. + return SharedAppData.getValue(context, _sharedObjectKey, () => SharedObject._()); + } +} + +// An example of a widget which depends on the SharedObject's value, +// which might be provided - along with SharedObject - in a Dart package. +class CustomWidget extends StatelessWidget { + const CustomWidget({ Key? key }) : super(key: key); + + @override + Widget build(BuildContext context) { + // Will be rebuilt if the shared object's value is changed. + return ElevatedButton( + child: Text('Replace ${SharedObject.of(context)}'), + onPressed: () { + SharedObject.reset(context); + }, + ); + } +} + +class Home extends StatelessWidget { + const Home({ Key? key }) : super(key: key); + + @override + Widget build(BuildContext context) { + return const Scaffold( + body: Center( + child: CustomWidget() + ), + ); + } +} + +void main() { + runApp(const MaterialApp(home: Home())); +} diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index 96acb7796e93d..9b8a14112a808 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -25,6 +25,7 @@ import 'restoration.dart'; import 'router.dart'; import 'scrollable.dart'; import 'semantics_debugger.dart'; +import 'shared_app_data.dart'; import 'shortcuts.dart'; import 'text.dart'; import 'title.dart'; @@ -1668,18 +1669,20 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { return RootRestorationScope( restorationId: widget.restorationScopeId, - child: Shortcuts( - debugLabel: '', - shortcuts: widget.shortcuts ?? WidgetsApp.defaultShortcuts, - // DefaultTextEditingShortcuts is nested inside Shortcuts so that it can - // fall through to the defaultShortcuts. - child: DefaultTextEditingShortcuts( - child: Actions( - actions: widget.actions ?? WidgetsApp.defaultActions, - child: DefaultTextEditingActions( - child: FocusTraversalGroup( - policy: ReadingOrderTraversalPolicy(), - child: child, + child: SharedAppData( + child: Shortcuts( + debugLabel: '', + shortcuts: widget.shortcuts ?? WidgetsApp.defaultShortcuts, + // DefaultTextEditingShortcuts is nested inside Shortcuts so that it can + // fall through to the defaultShortcuts. + child: DefaultTextEditingShortcuts( + child: Actions( + actions: widget.actions ?? WidgetsApp.defaultActions, + child: DefaultTextEditingActions( + child: FocusTraversalGroup( + policy: ReadingOrderTraversalPolicy(), + child: child, + ), ), ), ), diff --git a/packages/flutter/lib/src/widgets/shared_app_data.dart b/packages/flutter/lib/src/widgets/shared_app_data.dart new file mode 100644 index 0000000000000..58666cbcbe08c --- /dev/null +++ b/packages/flutter/lib/src/widgets/shared_app_data.dart @@ -0,0 +1,201 @@ +// 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 'package:flutter/foundation.dart'; + +import 'framework.dart'; +import 'inherited_model.dart'; + +/// The type of the [SharedAppData.getValue] `init` parameter. +/// +/// This callback is used to lazily create the initial value for +/// a [SharedAppData] keyword. +typedef SharedAppDataInitCallback = T Function(); + +/// Enables sharing key/value data with its `child` and all of the +/// child's descendants. +/// +/// - `SharedAppData.getValue(context, key, initCallback)` creates a dependency +/// on the key and returns the value for the key from the shared data table. +/// If no value exists for key then the initCallback is used to create +/// the initial value. +/// +/// - `SharedAppData.setValue(context, key, value)` changes the value of an entry +/// in the shared data table and forces widgets that depend on that entry +/// to be rebuilt. +/// +/// A widget whose build method uses SharedAppData.getValue(context, +/// keyword, initCallback) creates a dependency on the SharedAppData. When +/// the value of keyword changes with SharedAppData.setValue(), the widget +/// will be rebuilt. The values managed by the SharedAppData are expected +/// to be immutable: intrinsic changes to values will not cause +/// dependent widgets to be rebuilt. +/// +/// An instance of this widget is created automatically by [WidgetsApp]. +/// +/// There are many ways to share data with a widget subtree. This +/// class is based on [InheritedModel], which is an [InheritedWidget]. +/// It's intended to be used by packages that need to share a modest +/// number of values among their own components. +/// +/// SharedAppData is not intended to be a substitute for Provider or any of +/// the other general purpose application state systems. SharedAppData is +/// for situations where a package's custom widgets need to share one +/// or a handful of immutable data objects that can be lazily +/// initialized. It exists so that packages like that can deliver +/// custom widgets without requiring the developer to add a +/// package-specific umbrella widget to their application. +/// +/// A good way to create an SharedAppData key that avoids potential +/// collisions with other packages is to use a static `Object()` value. +/// The `SharedObject` example below does this. +/// +/// {@tool dartpad} +/// The following sample demonstrates using the automatically created +/// `SharedAppData`. Button presses cause changes to the values for keys +/// 'foo', and 'bar', and those changes only cause the widgets that +/// depend on those keys to be rebuilt. +/// +/// ** See code in examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart ** +/// {@end-tool} +/// +/// {@tool dartpad} +/// The following sample demonstrates how a single lazily computed +/// value could be shared within an app. A Flutter package that +/// provided custom widgets might use this approach to share a (possibly +/// private) value with instances of those widgets. +/// +/// ** See code in examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart ** +/// {@end-tool} +class SharedAppData extends StatefulWidget { + /// Creates a widget based on [InheritedModel] that supports build + /// dependencies qualified by keywords. Descendant widgets create + /// such dependencies with [SharedAppData.getValue] and they trigger + /// rebuilds with [SharedAppData.setValue]. + /// + /// This widget is automatically created by the [WidgetsApp]. + const SharedAppData({ Key? key, required this.child }) : super(key: key); + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.ProxyWidget.child} + final Widget child; + + @override + State createState() => _SharedAppDataState(); + + /// Returns the app model's value for `key` and ensures that each + /// time the value of `key` is changed with [SharedAppData.setValue], the + /// specified context will be rebuilt. + /// + /// If no value for `key` exists then the `init` callback is used to + /// generate an initial value. The callback is expected to return + /// an immutable value because intrinsic changes to the value will + /// not cause dependent widgets to be rebuilt. + /// + /// A widget that depends on the app model's value for `key` should use + /// this method in their `build` methods to ensure that they are rebuilt + /// if the value changes. + /// + /// The type parameter `K` is the type of the keyword and `V` + /// is the type of the value. + static V getValue(BuildContext context, K key, SharedAppDataInitCallback init) { + final _SharedAppModel? model = InheritedModel.inheritFrom<_SharedAppModel>(context, aspect: key); + assert(_debugHasSharedAppData(model, context, 'getValue')); + return model!.sharedAppDataState.getValue(key, init); + } + + /// Changes the app model's `value` for `key` and rebuilds any widgets + /// that have created a dependency on `key` with [SharedAppData.getValue]. + /// + /// If `value` is `==` to the current value of `key` then nothing + /// is rebuilt. + /// + /// The `value` is expected to be immutable because intrinsic + /// changes to the value will not cause dependent widgets to be + /// rebuilt. + /// + /// Unlike [SharedAppData.getValue], this method does _not_ create a dependency + /// between `context` and `key`. + /// + /// The type parameter `K` is the type of the value's keyword and `V` + /// is the type of the value. + static void setValue(BuildContext context, K key, V value) { + final _SharedAppModel? model = context.getElementForInheritedWidgetOfExactType<_SharedAppModel>()?.widget as _SharedAppModel?; + assert(_debugHasSharedAppData(model, context, 'setValue')); + model!.sharedAppDataState.setValue(key, value); + } + + static bool _debugHasSharedAppData(_SharedAppModel? model, BuildContext context, String methodName) { + assert(() { + if (model == null) { + throw FlutterError.fromParts( + [ + ErrorSummary('No SharedAppData widget found.'), + ErrorDescription('SharedAppData.$methodName requires an SharedAppData widget ancestor.\n'), + context.describeWidget('The specific widget that could not find an SharedAppData ancestor was'), + context.describeOwnershipChain('The ownership chain for the affected widget is'), + ErrorHint( + 'Typically, the SharedAppData widget is introduced by the MaterialApp ' + 'or WidgetsApp widget at the top of your application widget tree. It ' + 'provides a key/value map of data that is shared with the entire ' + 'application.', + ), + ], + ); + } + return true; + }()); + return true; + } +} + +class _SharedAppDataState extends State { + late Map data = {}; + + @override + Widget build(BuildContext context) { + return _SharedAppModel(sharedAppDataState: this, child: widget.child); + } + + V getValue(K key, SharedAppDataInitCallback init) { + data[key] ??= init(); + return data[key] as V; + } + + void setValue(K key, V value) { + if (data[key] != value) { + setState(() { + data = Map.from(data); + data[key] = value; + }); + } + } +} + +class _SharedAppModel extends InheritedModel { + _SharedAppModel({ + Key? key, + required this.sharedAppDataState, + required Widget child + }) : data = sharedAppDataState.data, super(key: key, child: child); + + final _SharedAppDataState sharedAppDataState; + final Map data; + + @override + bool updateShouldNotify(_SharedAppModel old) { + return data != old.data; + } + + @override + bool updateShouldNotifyDependent(_SharedAppModel old, Set keys) { + for (final Object key in keys) { + if (data[key] != old.data[key]) { + return true; + } + } + return false; + } +} diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index db20cccf2dc30..b58c40f9c1820 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -108,6 +108,7 @@ export 'src/widgets/scroll_view.dart'; export 'src/widgets/scrollable.dart'; export 'src/widgets/scrollbar.dart'; export 'src/widgets/semantics_debugger.dart'; +export 'src/widgets/shared_app_data.dart'; export 'src/widgets/shortcuts.dart'; export 'src/widgets/single_child_scroll_view.dart'; export 'src/widgets/size_changed_layout_notifier.dart'; diff --git a/packages/flutter/test/material/debug_test.dart b/packages/flutter/test/material/debug_test.dart index 934dd92db2af5..246b57521ced8 100644 --- a/packages/flutter/test/material/debug_test.dart +++ b/packages/flutter/test/material/debug_test.dart @@ -202,6 +202,8 @@ void main() { ' _FocusMarker\n' ' Focus\n' ' Shortcuts\n' + ' _SharedAppModel\n' + ' SharedAppData\n' ' UnmanagedRestorationScope\n' ' RestorationScope\n' ' UnmanagedRestorationScope\n' diff --git a/packages/flutter/test/widgets/shared_app_data_test.dart b/packages/flutter/test/widgets/shared_app_data_test.dart new file mode 100644 index 0000000000000..6d57734d4b1b3 --- /dev/null +++ b/packages/flutter/test/widgets/shared_app_data_test.dart @@ -0,0 +1,205 @@ +// 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 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('SharedAppData basics', (WidgetTester tester) async { + int columnBuildCount = 0; + int child1BuildCount = 0; + int child2BuildCount = 0; + late void Function(BuildContext context) setSharedAppDataValue; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: SharedAppData( + child: Builder( + builder: (BuildContext context) { + columnBuildCount += 1; + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setSharedAppDataValue.call(context); + }, + child: Column( + children: [ + Builder( + builder: (BuildContext context) { + child1BuildCount += 1; + return Text(SharedAppData.getValue(context, 'child1Text', () => 'null')); + }, + ), + Builder( + builder: (BuildContext context) { + child2BuildCount += 1; + return Text(SharedAppData.getValue(context, 'child2Text', () => 'null')); + } + ), + ], + ), + ); + }, + ), + ), + ), + ); + + expect(columnBuildCount, 1); + expect(child1BuildCount, 1); + expect(child2BuildCount, 1); + expect(find.text('null').evaluate().length, 2); + + // SharedAppData.setValue(context, 'child1Text', 'child1') + // causes the first Text widget to be rebuilt with its text to be + // set to 'child1'. Nothing else is rebuilt. + setSharedAppDataValue = (BuildContext context) { + SharedAppData.setValue(context, 'child1Text', 'child1'); + }; + await tester.tap(find.byType(GestureDetector)); + await tester.pump(); + expect(columnBuildCount, 1); + expect(child1BuildCount, 2); + expect(child2BuildCount, 1); + expect(find.text('child1'), findsOneWidget); + expect(find.text('null'), findsOneWidget); + + // SharedAppData.setValue(context, 'child2Text', 'child1') + // causes the second Text widget to be rebuilt with its text to be + // set to 'child2'. Nothing else is rebuilt. + setSharedAppDataValue = (BuildContext context) { + SharedAppData.setValue(context, 'child2Text', 'child2'); + }; + await tester.tap(find.byType(GestureDetector)); + await tester.pump(); + expect(columnBuildCount, 1); + expect(child1BuildCount, 2); + expect(child2BuildCount, 2); + expect(find.text('child1'), findsOneWidget); + expect(find.text('child2'), findsOneWidget); + + // Resetting a key's value to the same value does not + // cause any widgets to be rebuilt. + setSharedAppDataValue = (BuildContext context) { + SharedAppData.setValue(context, 'child1Text', 'child1'); + SharedAppData.setValue(context, 'child2Text', 'child2'); + }; + await tester.tap(find.byType(GestureDetector)); + await tester.pump(); + expect(columnBuildCount, 1); + expect(child1BuildCount, 2); + expect(child2BuildCount, 2); + + // More of the same, resetting the values to null.. + + setSharedAppDataValue = (BuildContext context) { + SharedAppData.setValue(context, 'child1Text', 'null'); + }; + await tester.tap(find.byType(GestureDetector)); + await tester.pump(); + expect(columnBuildCount, 1); + expect(child1BuildCount, 3); + expect(child2BuildCount, 2); + expect(find.text('null'), findsOneWidget); + expect(find.text('child2'), findsOneWidget); + + setSharedAppDataValue = (BuildContext context) { + SharedAppData.setValue(context, 'child2Text', 'null'); + }; + await tester.tap(find.byType(GestureDetector)); + await tester.pump(); + expect(columnBuildCount, 1); + expect(child1BuildCount, 3); + expect(child2BuildCount, 3); + expect(find.text('null').evaluate().length, 2); + }); + + testWidgets('WidgetsApp SharedAppData ', (WidgetTester tester) async { + int parentBuildCount = 0; + int childBuildCount = 0; + + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xff00ff00), + builder: (BuildContext context, Widget? child) { + parentBuildCount += 1; + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + SharedAppData.setValue(context, 'childText', 'child'); + }, + child: Center( + child: Builder( + builder: (BuildContext context) { + childBuildCount += 1; + return Text(SharedAppData.getValue(context, 'childText', () => 'null')); + }, + ), + ), + ); + }, + ), + ); + + expect(find.text('null'), findsOneWidget); + expect(parentBuildCount, 1); + expect(childBuildCount, 1); + + await tester.tap(find.byType(GestureDetector)); + await tester.pump(); + expect(parentBuildCount, 1); + expect(childBuildCount, 2); + expect(find.text('child'), findsOneWidget); + }); + + testWidgets('WidgetsApp SharedAppData Shadowing', (WidgetTester tester) async { + int innerTapCount = 0; + int outerTapCount = 0; + + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xff00ff00), + builder: (BuildContext context, Widget? child) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + outerTapCount += 1; + SharedAppData.setValue(context, 'childText', 'child'); + }, + child: Center( + child: SharedAppData( + child: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + innerTapCount += 1; + SharedAppData.setValue(context, 'childText', 'child'); + }, + child: Text(SharedAppData.getValue(context, 'childText', () => 'null')), + ); + }, + ), + ), + ), + ); + }, + ), + ); + + expect(find.text('null'), findsOneWidget); + + await tester.tapAt(const Offset(10, 10)); + await tester.pump(); + expect(outerTapCount, 1); + expect(innerTapCount, 0); + expect(find.text('null'), findsOneWidget); + + await tester.tap(find.text('null')); + await tester.pump(); + expect(outerTapCount, 1); + expect(innerTapCount, 1); + expect(find.text('child'), findsOneWidget); + }); +} diff --git a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart index 3bd3f82662226..7db55f9bd81be 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart @@ -61,8 +61,9 @@ class MultidexProject extends Project { dependencies: flutter: sdk: flutter - cloud_firestore: ^2.5.3 - firebase_core: ^1.6.0 + # Pin to specific plugin versions to avoid out-of-band failures. + cloud_firestore: 2.5.3 + firebase_core: 1.6.0 '''; @override From 2901cd720879ba3d7ba7cbd7d447ec9e80f937b6 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Thu, 18 Nov 2021 11:15:09 -0800 Subject: [PATCH 02/41] [flutter_releases] Flutter beta 2.8.0-3.2.pre Framework Cherrypicks (#93841) * [flutter_tools] Catch lack of flutter tools source missing (#93168) * 'Update Engine revision to bcc2b7f12cada3d1359e353c416568b4c3f6df69 for beta release 2.8.0-3.2.pre' * Replace text directionality control characters with escape sequences in the semantics_tester (#93034) Co-authored-by: Christopher Fujino Co-authored-by: Jason Simmons --- bin/internal/engine.version | 2 +- .../test/widgets/semantics_tester.dart | 9 +- ...ssion_for_current_semantics_tree_test.dart | 2 +- packages/flutter_tools/lib/executable.dart | 2 + .../lib/src/globals_null_migrated.dart | 3 + .../lib/src/pre_run_validator.dart | 51 ++++++++++ .../lib/src/runner/flutter_command.dart | 1 + .../hermetic/shell_completion_test.dart | 4 + .../permeable/packages_test.dart | 1 + .../runner/flutter_command_test.dart | 95 +++++++++++++++++-- packages/flutter_tools/test/src/common.dart | 1 + 11 files changed, 154 insertions(+), 17 deletions(-) create mode 100644 packages/flutter_tools/lib/src/pre_run_validator.dart diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d2dd5b33c323e..c4e64ccf9f663 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -09f1520e8b9585d133faf1eccced9357670c6d11 +bcc2b7f12cada3d1359e353c416568b4c3f6df69 diff --git a/packages/flutter/test/widgets/semantics_tester.dart b/packages/flutter/test/widgets/semantics_tester.dart index ed2e8ebb1516c..03cc46dae732a 100644 --- a/packages/flutter/test/widgets/semantics_tester.dart +++ b/packages/flutter/test/widgets/semantics_tester.dart @@ -635,12 +635,9 @@ class SemanticsTester { if (nodeData.actions != 0) buf.writeln(' actions: ${_actionsToSemanticsActionExpression(nodeData.actions)},'); if (node.label != null && node.label.isNotEmpty) { - final String escapedLabel = node.label.replaceAll('\n', r'\n'); - if (escapedLabel != node.label) { - buf.writeln(" label: r'$escapedLabel',"); - } else { - buf.writeln(" label: '$escapedLabel',"); - } + // Escape newlines and text directionality control characters. + final String escapedLabel = node.label.replaceAll('\n', r'\n').replaceAll('\u202a', r'\u202a').replaceAll('\u202c', r'\u202c'); + buf.writeln(" label: '$escapedLabel',"); } if (node.value != null && node.value.isNotEmpty) buf.writeln(" value: '${node.value}',"); diff --git a/packages/flutter/test/widgets/semantics_tester_generate_test_semantics_expression_for_current_semantics_tree_test.dart b/packages/flutter/test/widgets/semantics_tester_generate_test_semantics_expression_for_current_semantics_tree_test.dart index 0336aaf683ad7..eb3c58f8e1e54 100644 --- a/packages/flutter/test/widgets/semantics_tester_generate_test_semantics_expression_for_current_semantics_tree_test.dart +++ b/packages/flutter/test/widgets/semantics_tester_generate_test_semantics_expression_for_current_semantics_tree_test.dart @@ -132,7 +132,7 @@ void _tests() { tags: [const SemanticsTag('RenderViewport.twoPane')], flags: [SemanticsFlag.hasCheckedState, SemanticsFlag.isChecked, SemanticsFlag.isSelected], actions: [SemanticsAction.tap, SemanticsAction.decrease], - label: '‪Interactive text‬', + label: '\u202aInteractive text\u202c', value: 'test-value', increasedValue: 'test-increasedValue', decreasedValue: 'test-decreasedValue', diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index dffc0097a1e7d..de2ce3c944e70 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -54,6 +54,7 @@ import 'src/globals_null_migrated.dart' as globals; // Files in `isolated` are intentionally excluded from google3 tooling. import 'src/isolated/mustache_template.dart'; import 'src/isolated/resident_web_runner.dart'; +import 'src/pre_run_validator.dart'; import 'src/resident_runner.dart'; import 'src/runner/flutter_command.dart'; import 'src/web/web_runner.dart'; @@ -126,6 +127,7 @@ Future main(List args) async { windows: globals.platform.isWindows, ); }, + PreRunValidator: () => PreRunValidator(fileSystem: globals.fs), }, ); } diff --git a/packages/flutter_tools/lib/src/globals_null_migrated.dart b/packages/flutter_tools/lib/src/globals_null_migrated.dart index e59eea7211641..29b24239017fe 100644 --- a/packages/flutter_tools/lib/src/globals_null_migrated.dart +++ b/packages/flutter_tools/lib/src/globals_null_migrated.dart @@ -39,6 +39,7 @@ import 'macos/cocoapods_validator.dart'; import 'macos/xcdevice.dart'; import 'macos/xcode.dart'; import 'persistent_tool_state.dart'; +import 'pre_run_validator.dart'; import 'project.dart'; import 'reporting/crash_reporting.dart'; import 'reporting/reporting.dart'; @@ -233,3 +234,5 @@ FlutterProjectFactory get projectFactory { } CustomDevicesConfig get customDevicesConfig => context.get()!; + +PreRunValidator get preRunValidator => context.get() ?? const NoOpPreRunValidator(); diff --git a/packages/flutter_tools/lib/src/pre_run_validator.dart b/packages/flutter_tools/lib/src/pre_run_validator.dart new file mode 100644 index 0000000000000..e08cf1c60c306 --- /dev/null +++ b/packages/flutter_tools/lib/src/pre_run_validator.dart @@ -0,0 +1,51 @@ +// 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 'base/common.dart'; +import 'base/file_system.dart'; +import 'cache.dart'; + +/// A validator that runs before the tool runs any command. +abstract class PreRunValidator { + factory PreRunValidator({ + required FileSystem fileSystem, + }) => _DefaultPreRunValidator(fileSystem: fileSystem); + + void validate(); +} + +class _DefaultPreRunValidator implements PreRunValidator { + _DefaultPreRunValidator({ + required this.fileSystem, + }); + + final FileSystem fileSystem; + + late final Directory _toolsDir = fileSystem.directory( + fileSystem.path.join(Cache.flutterRoot!, 'packages', 'flutter_tools'), + ); + + @override + void validate() { + // If a user downloads the Flutter SDK via a pre-built archive and there is + // an error during extraction, the user could have a valid Dart snapshot of + // the tool but not the source directory. We still need the source, so + // validate the source directory exists and toolExit if not. + if (!_toolsDir.existsSync()) { + throwToolExit( + 'Flutter SDK installation appears corrupted: expected to find the ' + 'directory ${_toolsDir.path} but it does not exist! Please go to ' + 'https://flutter.dev/setup for instructions on how to re-install ' + 'Flutter.', + ); + } + } +} + +class NoOpPreRunValidator implements PreRunValidator { + const NoOpPreRunValidator(); + + @override + void validate() {} +} diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 4b3c8bea51569..339829997646b 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -1234,6 +1234,7 @@ abstract class FlutterCommand extends Command { /// rather than calling [runCommand] directly. @mustCallSuper Future verifyThenRunCommand(String commandPath) async { + globals.preRunValidator.validate(); // Populate the cache. We call this before pub get below so that the // sky_engine package is available in the flutter cache for pub to find. if (shouldUpdateCache) { 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 d2fda269225b5..914e8b1da0aed 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 @@ -31,6 +31,8 @@ void main() { expect(fakeStdio.writtenToStdout.length, equals(1)); expect(fakeStdio.writtenToStdout.first, contains('__flutter_completion')); }, overrides: { + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), Stdio: () => fakeStdio, }); @@ -40,6 +42,8 @@ void main() { expect(fakeStdio.writtenToStdout.length, equals(1)); expect(fakeStdio.writtenToStdout.first, contains('__flutter_completion')); }, overrides: { + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), Stdio: () => fakeStdio, }); 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 95c5b0b4e251d..e0bafd7978a5e 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart @@ -449,6 +449,7 @@ void main() { testUsingContext('test without bot', () async { Cache.flutterRoot = ''; + globals.fs.directory('/packages/flutter_tools').createSync(recursive: true); globals.fs.file('pubspec.yaml').createSync(); processManager.addCommand( const FakeCommand(command: ['/bin/cache/dart-sdk/bin/dart', '__deprecated_pub', 'run', 'test']), diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart index e770c183fd5e4..77a09dd8b7edb 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart @@ -18,7 +18,8 @@ import 'package:flutter_tools/src/base/time.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/dart/pub.dart'; -import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/pre_run_validator.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:test/fake.dart'; @@ -34,6 +35,13 @@ void main() { TestUsage usage; FakeClock clock; FakeProcessInfo processInfo; + MemoryFileSystem fileSystem; + FakeProcessManager processManager; + PreRunValidator preRunValidator; + + setUpAll(() { + Cache.flutterRoot = '/path/to/sdk/flutter'; + }); setUp(() { Cache.disableLocking(); @@ -42,6 +50,9 @@ void main() { clock = FakeClock(); processInfo = FakeProcessInfo(); processInfo.maxRss = 10; + fileSystem = MemoryFileSystem.test(); + processManager = FakeProcessManager.empty(); + preRunValidator = PreRunValidator(fileSystem: fileSystem); }); tearDown(() { @@ -63,6 +74,8 @@ void main() { expect(flutterCommand.hidden, isFalse); }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, Cache: () => cache, }); @@ -78,8 +91,24 @@ void main() { ], ); }, + overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + Cache: () => cache, + }); + + testUsingContext("throws toolExit if flutter_tools source dir doesn't exist", () async { + final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); + await expectToolExitLater( + flutterCommand.run(), + contains('Flutter SDK installation appears corrupted'), + ); + }, overrides: { Cache: () => cache, + FileSystem: () => fileSystem, + PreRunValidator: () => preRunValidator, + ProcessManager: () => processManager, }); testUsingContext('deprecated command should warn', () async { @@ -95,6 +124,9 @@ void main() { 'of Flutter.')); expect(flutterCommand.deprecated, isTrue); expect(flutterCommand.hidden, isTrue); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('uses the error handling file system', () async { @@ -105,6 +137,9 @@ void main() { } ); await flutterCommand.run(); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('finds the target file with default values', () async { @@ -115,8 +150,8 @@ void main() { expect(fakeTargetCommand.cachedTargetFile, 'lib/main.dart'); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('finds the target file with specified value', () async { @@ -127,8 +162,8 @@ void main() { expect(fakeTargetCommand.cachedTargetFile, 'lib/foo.dart'); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('throws tool exit if specified file does not exist', () async { @@ -137,13 +172,15 @@ void main() { expect(() async => runner.run(['test', '-t', 'lib/foo.dart']), throwsToolExit()); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); void testUsingCommandContext(String testName, dynamic Function() testBody) { testUsingContext(testName, testBody, overrides: { + FileSystem: () => fileSystem, ProcessInfo: () => processInfo, + ProcessManager: () => processManager, SystemClock: () => clock, Usage: () => usage, }); @@ -245,6 +282,9 @@ void main() { 'http://127.0.0.1:9105', ]); expect(command.devToolsServerAddress.toString(), equals('http://127.0.0.1:9105')); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('devToolsServerAddress returns null for bad input', () async { @@ -277,6 +317,9 @@ void main() { '127.0.0.1:9101', ]); expect(command.devToolsServerAddress, isNull); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); group('signals tests', () { @@ -328,6 +371,8 @@ void main() { ), ]); }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, ProcessInfo: () => processInfo, Signals: () => FakeSignals( subForSigTerm: signalUnderTest, @@ -363,6 +408,8 @@ void main() { signalController.add(mockSignal); await completer.future; }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, ProcessInfo: () => processInfo, Signals: () => FakeSignals( subForSigTerm: signalUnderTest, @@ -499,26 +546,35 @@ void main() { }, overrides: { Pub: () => FakePub(), Usage: () => usage, - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('use packagesPath to generate BuildInfo', () async { final DummyFlutterCommand flutterCommand = DummyFlutterCommand(packagesPath: 'foo'); final BuildInfo buildInfo = await flutterCommand.getBuildInfo(forcedBuildMode: BuildMode.debug); expect(buildInfo.packagesPath, 'foo'); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('use fileSystemScheme to generate BuildInfo', () async { final DummyFlutterCommand flutterCommand = DummyFlutterCommand(fileSystemScheme: 'foo'); final BuildInfo buildInfo = await flutterCommand.getBuildInfo(forcedBuildMode: BuildMode.debug); expect(buildInfo.fileSystemScheme, 'foo'); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('use fileSystemRoots to generate BuildInfo', () async { final DummyFlutterCommand flutterCommand = DummyFlutterCommand(fileSystemRoots: ['foo', 'bar']); final BuildInfo buildInfo = await flutterCommand.getBuildInfo(forcedBuildMode: BuildMode.debug); expect(buildInfo.fileSystemRoots, ['foo', 'bar']); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('includes initializeFromDill in BuildInfo', () async { @@ -527,6 +583,9 @@ void main() { await runner.run(['dummy', '--initialize-from-dill=/foo/bar.dill']); final BuildInfo buildInfo = await flutterCommand.getBuildInfo(forcedBuildMode: BuildMode.debug); expect(buildInfo.initializeFromDill, '/foo/bar.dill'); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('dds options', () async { @@ -535,6 +594,9 @@ void main() { await runner.run(['test', '--dds-port=1']); expect(ddsCommand.enableDds, isTrue); expect(ddsCommand.ddsPort, 1); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('dds options --dds', () async { @@ -542,6 +604,9 @@ void main() { final CommandRunner runner = createTestCommandRunner(ddsCommand); await runner.run(['test', '--dds']); expect(ddsCommand.enableDds, isTrue); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('dds options --no-dds', () async { @@ -549,6 +614,9 @@ void main() { final CommandRunner runner = createTestCommandRunner(ddsCommand); await runner.run(['test', '--no-dds']); expect(ddsCommand.enableDds, isFalse); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('dds options --disable-dds', () async { @@ -556,6 +624,9 @@ void main() { final CommandRunner runner = createTestCommandRunner(ddsCommand); await runner.run(['test', '--disable-dds']); expect(ddsCommand.enableDds, isFalse); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('dds options --no-disable-dds', () async { @@ -563,6 +634,9 @@ void main() { final CommandRunner runner = createTestCommandRunner(ddsCommand); await runner.run(['test', '--no-disable-dds']); expect(ddsCommand.enableDds, isTrue); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('dds options --dds --disable-dds', () async { @@ -570,6 +644,9 @@ void main() { final CommandRunner runner = createTestCommandRunner(ddsCommand); await runner.run(['test', '--dds', '--disable-dds']); expect(() => ddsCommand.enableDds, throwsToolExit()); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); } diff --git a/packages/flutter_tools/test/src/common.dart b/packages/flutter_tools/test/src/common.dart index 6f0e31152c213..2e0094204476f 100644 --- a/packages/flutter_tools/test/src/common.dart +++ b/packages/flutter_tools/test/src/common.dart @@ -162,6 +162,7 @@ void test(String description, FutureOr Function() body, { addTearDown(() async { await globals.localFileSystem.dispose(); }); + return body(); }, skip: skip, From 262b70ece1aebf84f132c51ec4cf90be605ce61b Mon Sep 17 00:00:00 2001 From: godofredoc Date: Wed, 1 Dec 2021 13:00:48 -0800 Subject: [PATCH 03/41] [flutter_releases] Flutter beta 2.8.0-3.3.pre Framework Cherrypicks (#94490) * make CIPD url customizable using FLUTTER_STORAGE_BASE_URL (#94137) * 'Update Engine revision to 06a7363b0cfd4092fe06eb80f829b5fbc94fd32a for beta release 2.8.0-3.3.pre' * Update plugin lint test for federated url_launcher plugin (#94374) Co-authored-by: Yegor Co-authored-by: Jenn Magder --- bin/internal/engine.version | 2 +- dev/devicelab/bin/tasks/plugin_lint_mac.dart | 12 ++-- packages/flutter_tools/lib/src/cache.dart | 23 ++++++++ .../flutter_tools/lib/src/flutter_cache.dart | 19 ++++--- .../test/general.shard/cache_test.dart | 57 +++++++++++++++++-- 5 files changed, 93 insertions(+), 20 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c4e64ccf9f663..fdd5b78a5c7df 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -bcc2b7f12cada3d1359e353c416568b4c3f6df69 +06a7363b0cfd4092fe06eb80f829b5fbc94fd32a diff --git a/dev/devicelab/bin/tasks/plugin_lint_mac.dart b/dev/devicelab/bin/tasks/plugin_lint_mac.dart index b92f422ce363c..052a7d492195b 100644 --- a/dev/devicelab/bin/tasks/plugin_lint_mac.dart +++ b/dev/devicelab/bin/tasks/plugin_lint_mac.dart @@ -399,7 +399,7 @@ Future main() async { final File podfileLockFile = File(path.join(swiftAppPath, 'ios', 'Podfile.lock')); final String podfileLockOutput = podfileLockFile.readAsStringSync(); - if (!podfileLockOutput.contains(':path: ".symlinks/plugins/url_launcher/ios"') + if (!podfileLockOutput.contains(':path: ".symlinks/plugins/url_launcher_ios/ios"') || !podfileLockOutput.contains(':path: Flutter') // test_plugin_objc no longer supports iOS, shouldn't be present. || podfileLockOutput.contains(':path: ".symlinks/plugins/test_plugin_objc/ios"') @@ -417,7 +417,7 @@ Future main() async { checkDirectoryExists(path.join( pluginSymlinks, - 'url_launcher', + 'url_launcher_ios', 'ios', )); @@ -447,7 +447,7 @@ void _validateIosPodfile(String appPath) { final File podfileLockFile = File(path.join(appPath, 'ios', 'Podfile.lock')); final String podfileLockOutput = podfileLockFile.readAsStringSync(); - if (!podfileLockOutput.contains(':path: ".symlinks/plugins/url_launcher/ios"') + if (!podfileLockOutput.contains(':path: ".symlinks/plugins/url_launcher_ios/ios"') || !podfileLockOutput.contains(':path: Flutter') || !podfileLockOutput.contains(':path: ".symlinks/plugins/test_plugin_objc/ios"') || !podfileLockOutput.contains(':path: ".symlinks/plugins/test_plugin_swift/ios"') @@ -479,7 +479,7 @@ void _validateIosPodfile(String appPath) { checkDirectoryExists(path.join( pluginSymlinks, - 'url_launcher', + 'url_launcher_ios', 'ios', )); @@ -516,7 +516,7 @@ void _validateMacOSPodfile(String appPath) { if (!podfileLockOutput.contains(':path: Flutter/ephemeral\n') || !podfileLockOutput.contains(':path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos') || !podfileLockOutput.contains(':path: Flutter/ephemeral/.symlinks/plugins/test_plugin_swift/macos') - || podfileLockOutput.contains('url_launcher/')) { + || podfileLockOutput.contains('url_launcher_ios/')) { print(podfileLockOutput); throw TaskResult.failure('macOS Podfile.lock does not contain expected pods'); } @@ -546,7 +546,7 @@ void _validateMacOSPodfile(String appPath) { checkDirectoryNotExists(path.join( pluginSymlinks, - 'url_launcher', + 'url_launcher_ios', )); checkDirectoryExists(path.join( diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 254c68eb53c90..7870c7807f926 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -412,6 +412,29 @@ class Cache { return overrideUrl; } + String get cipdBaseUrl { + final String? overrideUrl = _platform.environment['FLUTTER_STORAGE_BASE_URL']; + if (overrideUrl == null) { + return 'https://chrome-infra-packages.appspot.com/dl'; + } + + final Uri original; + try { + original = Uri.parse(overrideUrl); + } on FormatException catch (err) { + throwToolExit('"FLUTTER_STORAGE_BASE_URL" contains an invalid URI:\n$err'); + } + + final String cipdOverride = original.replace( + pathSegments: [ + ...original.pathSegments, + 'flutter_infra_release', + 'cipd', + ], + ).toString(); + return cipdOverride; + } + bool _hasWarnedAboutStorageOverride = false; void _maybeWarnAboutStorageOverride(String overrideUrl) { diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart index 9e29d5ad75c4d..ae479b4e9f69a 100644 --- a/packages/flutter_tools/lib/src/flutter_cache.dart +++ b/packages/flutter_tools/lib/src/flutter_cache.dart @@ -198,7 +198,7 @@ class FlutterWebSdk extends CachedArtifact { } final String canvasKitVersion = cache.getVersionFor('canvaskit')!; - final String canvasKitUrl = '$_cipdBaseUrl/flutter/web/canvaskit_bundle/+/$canvasKitVersion'; + final String canvasKitUrl = '${cache.cipdBaseUrl}/flutter/web/canvaskit_bundle/+/$canvasKitVersion'; return artifactUpdater.downloadZipArchive( 'Downloading CanvasKit...', Uri.parse(canvasKitUrl), @@ -575,8 +575,6 @@ class GradleWrapper extends CachedArtifact { } } -const String _cipdBaseUrl = 'https://chrome-infra-packages.appspot.com/dl'; - /// Common functionality for pulling Fuchsia SDKs. abstract class _FuchsiaSDKArtifacts extends CachedArtifact { _FuchsiaSDKArtifacts(Cache cache, String platform) : @@ -593,7 +591,7 @@ abstract class _FuchsiaSDKArtifacts extends CachedArtifact { Directory get location => cache.getArtifactDirectory('fuchsia'); Future _doUpdate(ArtifactUpdater artifactUpdater) { - final String url = '$_cipdBaseUrl/$_path/+/$version'; + final String url = '${cache.cipdBaseUrl}/$_path/+/$version'; return artifactUpdater.downloadZipArchive('Downloading package fuchsia SDK...', Uri.parse(url), location); } @@ -627,7 +625,7 @@ class FlutterRunnerSDKArtifacts extends CachedArtifact { if (!_platform.isLinux && !_platform.isMacOS) { return; } - final String url = '$_cipdBaseUrl/flutter/fuchsia/+/git_revision:$version'; + final String url = '${cache.cipdBaseUrl}/flutter/fuchsia/+/git_revision:$version'; await artifactUpdater.downloadZipArchive('Downloading package flutter runner...', Uri.parse(url), location); } } @@ -644,11 +642,13 @@ abstract class VersionedPackageResolver { /// Resolves the CIPD archive URL for a given package and version. class CipdArchiveResolver extends VersionedPackageResolver { - const CipdArchiveResolver(); + const CipdArchiveResolver(this.cache); + + final Cache cache; @override String resolveUrl(String packageName, String version) { - return '$_cipdBaseUrl/flutter/$packageName/+/git_revision:$version'; + return '${cache.cipdBaseUrl}/flutter/$packageName/+/git_revision:$version'; } } @@ -656,9 +656,10 @@ class CipdArchiveResolver extends VersionedPackageResolver { class FlutterRunnerDebugSymbols extends CachedArtifact { FlutterRunnerDebugSymbols(Cache cache, { required Platform platform, - this.packageResolver = const CipdArchiveResolver(), + VersionedPackageResolver? packageResolver, }) : _platform = platform, - super('flutter_runner_debug_symbols', cache, DevelopmentArtifact.flutterRunner); + packageResolver = packageResolver ?? CipdArchiveResolver(cache), + super('flutter_runner_debug_symbols', cache, DevelopmentArtifact.flutterRunner); final VersionedPackageResolver packageResolver; final Platform _platform; diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index 24b330298cb46..22ed53b9a33ab 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -730,14 +730,18 @@ void main() { testWithoutContext('FlutterWebSdk fetches web artifacts and deletes previous directory contents', () async { final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - final File canvasKitVersionFile = fileSystem.currentDirectory + final Directory internalDir = fileSystem.currentDirectory .childDirectory('cache') .childDirectory('bin') - .childDirectory('internal') - .childFile('canvaskit.version'); + .childDirectory('internal'); + final File canvasKitVersionFile = internalDir.childFile('canvaskit.version'); canvasKitVersionFile.createSync(recursive: true); canvasKitVersionFile.writeAsStringSync('abcdefg'); + final File engineVersionFile = internalDir.childFile('engine.version'); + engineVersionFile.createSync(recursive: true); + engineVersionFile.writeAsStringSync('hijklmnop'); + final Cache cache = Cache.test(processManager: FakeProcessManager.any(), fileSystem: fileSystem); final Directory webCacheDirectory = cache.getWebSdkDirectory(); final FakeArtifactUpdater artifactUpdater = FakeArtifactUpdater(); @@ -763,7 +767,7 @@ void main() { ]); expect(downloads, [ - 'https://storage.googleapis.com/flutter_infra_release/flutter/null/flutter-web-sdk-linux-x64.zip', + 'https://storage.googleapis.com/flutter_infra_release/flutter/hijklmnop/flutter-web-sdk-linux-x64.zip', 'https://chrome-infra-packages.appspot.com/dl/flutter/web/canvaskit_bundle/+/abcdefg', ]); @@ -776,6 +780,51 @@ void main() { expect(webCacheDirectory.childFile('bar'), isNot(exists)); }); + testWithoutContext('FlutterWebSdk CanvasKit URL can be overridden via FLUTTER_STORAGE_BASE_URL', () async { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final Directory internalDir = fileSystem.currentDirectory + .childDirectory('cache') + .childDirectory('bin') + .childDirectory('internal'); + final File canvasKitVersionFile = internalDir.childFile('canvaskit.version'); + canvasKitVersionFile.createSync(recursive: true); + canvasKitVersionFile.writeAsStringSync('abcdefg'); + + final File engineVersionFile = internalDir.childFile('engine.version'); + engineVersionFile.createSync(recursive: true); + engineVersionFile.writeAsStringSync('hijklmnop'); + + final Cache cache = Cache.test( + processManager: FakeProcessManager.any(), + fileSystem: fileSystem, + platform: FakePlatform( + environment: { + 'FLUTTER_STORAGE_BASE_URL': 'https://flutter.storage.com/override' + }, + ), + ); + final Directory webCacheDirectory = cache.getWebSdkDirectory(); + final FakeArtifactUpdater artifactUpdater = FakeArtifactUpdater(); + final FlutterWebSdk webSdk = FlutterWebSdk(cache, platform: FakePlatform()); + + final List downloads = []; + final List locations = []; + artifactUpdater.onDownloadZipArchive = (String message, Uri uri, Directory location) { + downloads.add(uri.toString()); + locations.add(location.path); + location.createSync(recursive: true); + location.childFile('foo').createSync(); + }; + webCacheDirectory.childFile('bar').createSync(recursive: true); + + await webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils()); + + expect(downloads, [ + 'https://flutter.storage.com/override/flutter_infra_release/flutter/hijklmnop/flutter-web-sdk-linux-x64.zip', + 'https://flutter.storage.com/override/flutter_infra_release/cipd/flutter/web/canvaskit_bundle/+/abcdefg' + ]); + }); + testWithoutContext('FlutterWebSdk uses tryToDelete to handle directory edge cases', () async { final FileExceptionHandler handler = FileExceptionHandler(); final MemoryFileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle); From cf4400006550b70f28e4b4af815151d1e74846c6 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Wed, 8 Dec 2021 14:06:50 -0800 Subject: [PATCH 04/41] 'Update Engine revision to 40a99c595137e4b2f5b2efa8ff343ea23c1e16b8 for stable release 2.8.0' (#94889) --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fdd5b78a5c7df..19bc71393b394 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -06a7363b0cfd4092fe06eb80f829b5fbc94fd32a +40a99c595137e4b2f5b2efa8ff343ea23c1e16b8 From 463eaf8880eae22c8cc9068747641e162af1a542 Mon Sep 17 00:00:00 2001 From: zlshames Date: Sun, 11 Jul 2021 14:02:26 -0400 Subject: [PATCH 05/41] Full GIF Insertion --- packages/flutter/lib/src/cupertino/text_field.dart | 5 +++++ packages/flutter/lib/src/material/text_field.dart | 5 +++++ packages/flutter/lib/src/services/text_input.dart | 9 ++++++++- packages/flutter/lib/src/widgets/editable_text.dart | 10 ++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index 663e5a1acbee4..d927cfddd6342 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -274,6 +274,7 @@ class CupertinoTextField extends StatefulWidget { this.maxLengthEnforced = true, this.maxLengthEnforcement, this.onChanged, + this.onContentCommited, this.onEditingComplete, this.onSubmitted, this.inputFormatters, @@ -705,6 +706,9 @@ class CupertinoTextField extends StatefulWidget { /// {@macro flutter.widgets.editableText.onChanged} final ValueChanged? onChanged; + /// Once new content is commited... + final ValueChanged>? onContentCommited; + /// {@macro flutter.widgets.editableText.onEditingComplete} final VoidCallback? onEditingComplete; @@ -1250,6 +1254,7 @@ class _CupertinoTextFieldState extends State with Restoratio selectionControls: widget.selectionEnabled ? textSelectionControls : null, onChanged: widget.onChanged, + onContentCommited: widget.onContentCommited, onSelectionChanged: _handleSelectionChanged, onEditingComplete: widget.onEditingComplete, onSubmitted: widget.onSubmitted, diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 8e6dc27f5febe..f7ed509b6fc33 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -324,6 +324,7 @@ class TextField extends StatefulWidget { this.maxLengthEnforced = true, this.maxLengthEnforcement, this.onChanged, + this.onContentCommited, this.onEditingComplete, this.onSubmitted, this.onAppPrivateCommand, @@ -602,6 +603,9 @@ class TextField extends StatefulWidget { /// which are more specialized input change notifications. final ValueChanged? onChanged; + /// Once new content is commited... + final ValueChanged>? onContentCommited; + /// {@macro flutter.widgets.editableText.onEditingComplete} final VoidCallback? onEditingComplete; @@ -1247,6 +1251,7 @@ class _TextFieldState extends State with RestorationMixin implements selectionColor: focusNode.hasFocus ? selectionColor : null, selectionControls: widget.selectionEnabled ? textSelectionControls : null, onChanged: widget.onChanged, + onContentCommited: widget.onContentCommited, onSelectionChanged: _handleSelectionChanged, onEditingComplete: widget.onEditingComplete, onSubmitted: widget.onSubmitted, diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index 40b5379d83947..48a0091293d4f 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -1025,6 +1025,9 @@ abstract class TextInputClient { /// Requests that this client perform the given action. void performAction(TextInputAction action); + /// Notify client about new content insertion, like gif or PNG... + void commitContent(Map content); + /// Request from the input method that this client perform the given private /// command. /// @@ -1557,7 +1560,11 @@ class TextInput { (_currentConnection!._client as DeltaTextInputClient).updateEditingValueWithDeltas(deltas); break; case 'TextInputClient.performAction': - _currentConnection!._client.performAction(_toTextInputAction(args[1] as String)); + if (args[1] as String == 'TextInputAction.commitContent') { + _currentConnection!._client.commitContent(args[2] as Map); + } else { + _currentConnection!._client.performAction(_toTextInputAction(args[1] as String)); + } break; case 'TextInputClient.performPrivateCommand': final Map firstArg = args[1] as Map; diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index a0cb911868ae7..57fdda350e265 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -427,6 +427,7 @@ class EditableText extends StatefulWidget { this.textInputAction, this.textCapitalization = TextCapitalization.none, this.onChanged, + this.onContentCommited, this.onEditingComplete, this.onSubmitted, this.onAppPrivateCommand, @@ -948,6 +949,9 @@ class EditableText extends StatefulWidget { /// which are more specialized input change notifications. final ValueChanged? onChanged; + /// Once new content such as GIF is commited... + final ValueChanged>? onContentCommited; + /// {@template flutter.widgets.editableText.onEditingComplete} /// Called when the user submits editable content (e.g., user presses the "done" /// button on the keyboard). @@ -1904,6 +1908,12 @@ class EditableTextState extends State with AutomaticKeepAliveClien widget.onAppPrivateCommand!(action, data); } + @override + void commitContent(Map content) { + widget.onContentCommited!(content); + _finalizeEditing(TextInputAction.none, shouldUnfocus: false); + } + // The original position of the caret on FloatingCursorDragState.start. Rect? _startCaretRect; From 87128415556f1230b880c4e67ba10dae31df6d92 Mon Sep 17 00:00:00 2001 From: zlshames Date: Sun, 11 Jul 2021 14:30:59 -0400 Subject: [PATCH 06/41] Fixes committed typo --- packages/flutter/lib/src/cupertino/text_field.dart | 6 +++--- packages/flutter/lib/src/material/text_field.dart | 6 +++--- packages/flutter/lib/src/widgets/editable_text.dart | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index d927cfddd6342..3657fa9492f53 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -274,7 +274,7 @@ class CupertinoTextField extends StatefulWidget { this.maxLengthEnforced = true, this.maxLengthEnforcement, this.onChanged, - this.onContentCommited, + this.onContentCommitted, this.onEditingComplete, this.onSubmitted, this.inputFormatters, @@ -707,7 +707,7 @@ class CupertinoTextField extends StatefulWidget { final ValueChanged? onChanged; /// Once new content is commited... - final ValueChanged>? onContentCommited; + final ValueChanged>? onContentCommitted; /// {@macro flutter.widgets.editableText.onEditingComplete} final VoidCallback? onEditingComplete; @@ -1254,7 +1254,7 @@ class _CupertinoTextFieldState extends State with Restoratio selectionControls: widget.selectionEnabled ? textSelectionControls : null, onChanged: widget.onChanged, - onContentCommited: widget.onContentCommited, + onContentCommitted: widget.onContentCommitted, onSelectionChanged: _handleSelectionChanged, onEditingComplete: widget.onEditingComplete, onSubmitted: widget.onSubmitted, diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index f7ed509b6fc33..8311c5af10f7a 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -324,7 +324,7 @@ class TextField extends StatefulWidget { this.maxLengthEnforced = true, this.maxLengthEnforcement, this.onChanged, - this.onContentCommited, + this.onContentCommitted, this.onEditingComplete, this.onSubmitted, this.onAppPrivateCommand, @@ -604,7 +604,7 @@ class TextField extends StatefulWidget { final ValueChanged? onChanged; /// Once new content is commited... - final ValueChanged>? onContentCommited; + final ValueChanged>? onContentCommitted; /// {@macro flutter.widgets.editableText.onEditingComplete} final VoidCallback? onEditingComplete; @@ -1251,7 +1251,7 @@ class _TextFieldState extends State with RestorationMixin implements selectionColor: focusNode.hasFocus ? selectionColor : null, selectionControls: widget.selectionEnabled ? textSelectionControls : null, onChanged: widget.onChanged, - onContentCommited: widget.onContentCommited, + onContentCommitted: widget.onContentCommitted, onSelectionChanged: _handleSelectionChanged, onEditingComplete: widget.onEditingComplete, onSubmitted: widget.onSubmitted, diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 57fdda350e265..e1ddf84545f29 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -427,7 +427,7 @@ class EditableText extends StatefulWidget { this.textInputAction, this.textCapitalization = TextCapitalization.none, this.onChanged, - this.onContentCommited, + this.onContentCommitted, this.onEditingComplete, this.onSubmitted, this.onAppPrivateCommand, @@ -950,7 +950,7 @@ class EditableText extends StatefulWidget { final ValueChanged? onChanged; /// Once new content such as GIF is commited... - final ValueChanged>? onContentCommited; + final ValueChanged>? onContentCommitted; /// {@template flutter.widgets.editableText.onEditingComplete} /// Called when the user submits editable content (e.g., user presses the "done" @@ -1910,7 +1910,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien @override void commitContent(Map content) { - widget.onContentCommited!(content); + widget.onContentCommitted!(content); _finalizeEditing(TextInputAction.none, shouldUnfocus: false); } From e08fa96e17700bcb93591f51f2047cc514d8a248 Mon Sep 17 00:00:00 2001 From: zlshames Date: Sun, 11 Jul 2021 15:06:16 -0400 Subject: [PATCH 07/41] Adds class implementation of committed content --- .../lib/src/widgets/editable_text.dart | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index e1ddf84545f29..06af5163cee66 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -1910,7 +1910,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien @override void commitContent(Map content) { - widget.onContentCommitted!(content); + widget.onContentCommitted!(CommittedContent.fromMap(content)); _finalizeEditing(TextInputAction.none, shouldUnfocus: false); } @@ -3135,3 +3135,23 @@ class _Editable extends MultiChildRenderObjectWidget { ..setPromptRectRange(promptRectRange); } } + +class CommittedContent { + String? mimeType; + String? uri; + UInt8List? data; + + bool get hasData => this.data != null && this.data.length > 0; + + CommittedContent({this.mimeType, this.uri, this.data}); + + static CommittedContent fromMap(Map data) { + var content = new CommittedContent(); + if (data == null) return content; + + if (data.containsKey('mimeType')) content.mimeType = data['mimeType'] as String?; + if (data.containsKey('uri')) content.uri = data['uri'] as String?; + if (data.containsKey('data')) content.data = data['data'] as Uint8List?; + return content; + } +} From aae4c0e064491b304436bbb92870516a85b2ed66 Mon Sep 17 00:00:00 2001 From: tanay Date: Sun, 11 Jul 2021 14:40:43 -0400 Subject: [PATCH 08/41] Add more documentation and tests --- .../flutter/lib/src/cupertino/text_field.dart | 48 ++++++++++++++++- .../flutter/lib/src/material/text_field.dart | 48 ++++++++++++++++- .../flutter/lib/src/services/text_input.dart | 2 +- .../lib/src/widgets/editable_text.dart | 52 +++++++++++++++++-- .../test/services/text_input_test.dart | 25 +++++++++ 5 files changed, 169 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index 3657fa9492f53..16d4f65952039 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -706,7 +706,53 @@ class CupertinoTextField extends StatefulWidget { /// {@macro flutter.widgets.editableText.onChanged} final ValueChanged? onChanged; - /// Once new content is commited... + /// Called when a user inserts image-based content through the device keyboard + /// on Android only. + /// + /// The map will contain the following data: + /// - MIME Type (supporting png, bmp, jpg, tiff, gif, jpeg, and webp) + /// - Bytes + /// - URI + /// + /// You will want to use the bytes to display the image. + /// + /// {@tool dartpad --template=stateful_widget_material} + /// + /// This example shows how to access the data for committed content in your + /// `TextField`. + /// + /// ```dart + /// final TextEditingController _controller = TextEditingController(); + /// + /// @override + /// void dispose() { + /// _controller.dispose(); + /// super.dispose(); + /// } + /// + /// @override + /// Widget build(BuildContext context) { + /// return Scaffold( + /// body: Column( + /// mainAxisAlignment: MainAxisAlignment.center, + /// children: [ + /// const Text('Here's a text field that supports inserting gif content:'), + /// TextField( + /// controller: _controller, + /// onContentCommitted: (Map data) async { + /// if (data['mimeType'] == "image/gif" && data['data'] != null) { + /// List bytes = (data['data'] as List)?.map((e) => e as int)?.toList(); + /// ... + /// } + /// }, + /// ), + /// ], + /// ), + /// ); + /// } + /// ``` + /// {@end-tool} + /// {@endtemplate} final ValueChanged>? onContentCommitted; /// {@macro flutter.widgets.editableText.onEditingComplete} diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 8311c5af10f7a..c52535c713d0e 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -603,7 +603,53 @@ class TextField extends StatefulWidget { /// which are more specialized input change notifications. final ValueChanged? onChanged; - /// Once new content is commited... + /// Called when a user inserts image-based content through the device keyboard + /// on Android only. + /// + /// The map will contain the following data: + /// - MIME Type (supporting png, bmp, jpg, tiff, gif, jpeg, and webp) + /// - Bytes + /// - URI + /// + /// You will want to use the bytes to display the image. + /// + /// {@tool dartpad --template=stateful_widget_material} + /// + /// This example shows how to access the data for committed content in your + /// `TextField`. + /// + /// ```dart + /// final TextEditingController _controller = TextEditingController(); + /// + /// @override + /// void dispose() { + /// _controller.dispose(); + /// super.dispose(); + /// } + /// + /// @override + /// Widget build(BuildContext context) { + /// return Scaffold( + /// body: Column( + /// mainAxisAlignment: MainAxisAlignment.center, + /// children: [ + /// const Text('Here's a text field that supports inserting gif content:'), + /// TextField( + /// controller: _controller, + /// onContentCommitted: (Map data) async { + /// if (data['mimeType'] == "image/gif" && data['data'] != null) { + /// List bytes = (data['data'] as List)?.map((e) => e as int)?.toList(); + /// ... + /// } + /// }, + /// ), + /// ], + /// ), + /// ); + /// } + /// ``` + /// {@end-tool} + /// {@endtemplate} final ValueChanged>? onContentCommitted; /// {@macro flutter.widgets.editableText.onEditingComplete} diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index 48a0091293d4f..6f0736c723c74 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -1025,7 +1025,7 @@ abstract class TextInputClient { /// Requests that this client perform the given action. void performAction(TextInputAction action); - /// Notify client about new content insertion, like gif or PNG... + /// Notify client about new content insertion from Android keyboard void commitContent(Map content); /// Request from the input method that this client perform the given private diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 06af5163cee66..54e9b653f9c2b 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -949,7 +949,53 @@ class EditableText extends StatefulWidget { /// which are more specialized input change notifications. final ValueChanged? onChanged; - /// Once new content such as GIF is commited... + /// Called when a user inserts image-based content through the device keyboard + /// on Android only. + /// + /// The map will contain the following data: + /// - MIME Type (supporting png, bmp, jpg, tiff, gif, jpeg, and webp) + /// - Bytes + /// - URI + /// + /// You will want to use the bytes to display the image. + /// + /// {@tool dartpad --template=stateful_widget_material} + /// + /// This example shows how to access the data for committed content in your + /// `TextField`. + /// + /// ```dart + /// final TextEditingController _controller = TextEditingController(); + /// + /// @override + /// void dispose() { + /// _controller.dispose(); + /// super.dispose(); + /// } + /// + /// @override + /// Widget build(BuildContext context) { + /// return Scaffold( + /// body: Column( + /// mainAxisAlignment: MainAxisAlignment.center, + /// children: [ + /// const Text('Here's a text field that supports inserting gif content:'), + /// TextField( + /// controller: _controller, + /// onContentCommitted: (Map data) async { + /// if (data['mimeType'] == "image/gif" && data['data'] != null) { + /// List bytes = (data['data'] as List)?.map((e) => e as int)?.toList(); + /// ... + /// } + /// }, + /// ), + /// ], + /// ), + /// ); + /// } + /// ``` + /// {@end-tool} + /// {@endtemplate} final ValueChanged>? onContentCommitted; /// {@template flutter.widgets.editableText.onEditingComplete} @@ -1910,7 +1956,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien @override void commitContent(Map content) { - widget.onContentCommitted!(CommittedContent.fromMap(content)); + widget.onContentCommitted?.call(CommittedContent.fromMap(content)); _finalizeEditing(TextInputAction.none, shouldUnfocus: false); } @@ -3148,7 +3194,7 @@ class CommittedContent { static CommittedContent fromMap(Map data) { var content = new CommittedContent(); if (data == null) return content; - + if (data.containsKey('mimeType')) content.mimeType = data['mimeType'] as String?; if (data.containsKey('uri')) content.uri = data['uri'] as String?; if (data.containsKey('data')) content.data = data['data'] as Uint8List?; diff --git a/packages/flutter/test/services/text_input_test.dart b/packages/flutter/test/services/text_input_test.dart index f24fa0f263b98..b8b24ed2a2998 100644 --- a/packages/flutter/test/services/text_input_test.dart +++ b/packages/flutter/test/services/text_input_test.dart @@ -243,6 +243,31 @@ void main() { expect(client.latestMethodCall, 'connectionClosed'); }); + test('TextInputClient commitContent method is called', () async { + final FakeTextInputClient client = FakeTextInputClient(TextEditingValue.empty); + const TextInputConfiguration configuration = TextInputConfiguration(); + TextInput.attach(client, configuration); + + expect(client.latestMethodCall, isEmpty); + + // Send performPrivateCommand message. + final ByteData? messageBytes = const JSONMessageCodec().encodeMessage({ + 'args': [ + 1, + "TextInputAction.commitContent", + jsonDecode('{"mimeType": "image/gif", "data": "010101000", "uri": "content://com.google.android.inputmethod.latin.fileprovider/test.gif"}'), + ], + 'method': 'TextInputClient.performAction', + }); + await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage( + 'flutter/textinput', + messageBytes, + (ByteData? _) {}, + ); + + expect(client.latestMethodCall, 'performAction'); + }); + test('TextInputClient performPrivateCommand method is called', () async { // Assemble a TextInputConnection so we can verify its change in state. final FakeTextInputClient client = FakeTextInputClient(TextEditingValue.empty); From a1db817f0e75673116dee1d08a671f32067d3ec3 Mon Sep 17 00:00:00 2001 From: zlshames Date: Sun, 11 Jul 2021 15:11:32 -0400 Subject: [PATCH 09/41] Typo --- packages/flutter/lib/src/widgets/editable_text.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 54e9b653f9c2b..5c3fae9a3e183 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:math' as math; +import 'dart:typed_data'; import 'dart:ui' as ui hide TextStyle; import 'package:flutter/foundation.dart'; @@ -3185,7 +3186,7 @@ class _Editable extends MultiChildRenderObjectWidget { class CommittedContent { String? mimeType; String? uri; - UInt8List? data; + Uint8List? data; bool get hasData => this.data != null && this.data.length > 0; From 9fd5f3c2333c66f7a746d0ae0b7fd0bf29b5bce8 Mon Sep 17 00:00:00 2001 From: zlshames Date: Sun, 11 Jul 2021 15:20:17 -0400 Subject: [PATCH 10/41] Cleanup & Styling Guide suggestions --- .../lib/src/widgets/editable_text.dart | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 5c3fae9a3e183..97fc599f47e8e 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -13,6 +13,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; +import '../../foundation.dart'; import 'autofill.dart'; import 'automatic_keep_alive.dart'; import 'basic.dart'; @@ -3188,17 +3189,31 @@ class CommittedContent { String? uri; Uint8List? data; - bool get hasData => this.data != null && this.data.length > 0; + bool get hasData => data != null && data!.isNotEmpty; CommittedContent({this.mimeType, this.uri, this.data}); - static CommittedContent fromMap(Map data) { - var content = new CommittedContent(); - if (data == null) return content; + static CommittedContent fromMap(Map? data) { + if (data == null || data.isEmpty) return CommittedContent(); + return CommittedContent( + mimeType: data['mimeType'] as String?, + uri: data['uri'] as String?, + data: Uint8List.fromList(List.from(data['data'] as Iterable)) + ); + } + + @override + String toString() => '${objectRuntimeType(this, 'CommittedContent')}($mimeType, $uri, $data)'; - if (data.containsKey('mimeType')) content.mimeType = data['mimeType'] as String?; - if (data.containsKey('uri')) content.uri = data['uri'] as String?; - if (data.containsKey('data')) content.data = data['data'] as Uint8List?; - return content; + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) return false; + return other is CommittedContent + && other.mimeType == mimeType + && other.uri == uri + && other.data == data; } + + @override + int get hashCode => hashValues(mimeType, uri, data); } From 2254a666939a9b098f322e611fc2b859feaee9b9 Mon Sep 17 00:00:00 2001 From: zlshames Date: Sun, 11 Jul 2021 15:34:39 -0400 Subject: [PATCH 11/41] Fixes import --- packages/flutter/lib/src/widgets/editable_text.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 97fc599f47e8e..4d0ab368cf9f7 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -13,7 +13,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; -import '../../foundation.dart'; import 'autofill.dart'; import 'automatic_keep_alive.dart'; import 'basic.dart'; From d45b55e4d9ea6d102e97a3ee982d508316aa0823 Mon Sep 17 00:00:00 2001 From: tanay Date: Sun, 11 Jul 2021 15:51:54 -0400 Subject: [PATCH 12/41] Change type signatures and update docs --- packages/flutter/lib/src/cupertino/text_field.dart | 8 ++++---- packages/flutter/lib/src/material/text_field.dart | 8 ++++---- packages/flutter/lib/src/widgets/editable_text.dart | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index 16d4f65952039..31913f85669b0 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -739,9 +739,9 @@ class CupertinoTextField extends StatefulWidget { /// const Text('Here's a text field that supports inserting gif content:'), /// TextField( /// controller: _controller, - /// onContentCommitted: (Map data) async { - /// if (data['mimeType'] == "image/gif" && data['data'] != null) { - /// List bytes = (data['data'] as List)?.map((e) => e as int)?.toList(); + /// onContentCommitted: (CommittedContent data) async { + /// if (data.mimeType == "image/gif" && data.data != null) { + /// //handle Uint8List (e.g. upload to server, display a MemoryImage, etc) /// ... /// } /// }, @@ -753,7 +753,7 @@ class CupertinoTextField extends StatefulWidget { /// ``` /// {@end-tool} /// {@endtemplate} - final ValueChanged>? onContentCommitted; + final ValueChanged? onContentCommitted; /// {@macro flutter.widgets.editableText.onEditingComplete} final VoidCallback? onEditingComplete; diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index c52535c713d0e..e4ccf319a2f5f 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -636,9 +636,9 @@ class TextField extends StatefulWidget { /// const Text('Here's a text field that supports inserting gif content:'), /// TextField( /// controller: _controller, - /// onContentCommitted: (Map data) async { - /// if (data['mimeType'] == "image/gif" && data['data'] != null) { - /// List bytes = (data['data'] as List)?.map((e) => e as int)?.toList(); + /// onContentCommitted: (CommittedContent data) async { + /// if (data.mimeType == "image/gif" && data.data != null) { + /// //handle Uint8List (e.g. upload to server, display a MemoryImage, etc) /// ... /// } /// }, @@ -650,7 +650,7 @@ class TextField extends StatefulWidget { /// ``` /// {@end-tool} /// {@endtemplate} - final ValueChanged>? onContentCommitted; + final ValueChanged? onContentCommitted; /// {@macro flutter.widgets.editableText.onEditingComplete} final VoidCallback? onEditingComplete; diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 4d0ab368cf9f7..5354abb906e1e 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -983,9 +983,9 @@ class EditableText extends StatefulWidget { /// const Text('Here's a text field that supports inserting gif content:'), /// TextField( /// controller: _controller, - /// onContentCommitted: (Map data) async { - /// if (data['mimeType'] == "image/gif" && data['data'] != null) { - /// List bytes = (data['data'] as List)?.map((e) => e as int)?.toList(); + /// onContentCommitted: (CommittedContent data) async { + /// if (data.mimeType == "image/gif" && data.data != null) { + /// //handle Uint8List (e.g. upload to server, display a MemoryImage, etc) /// ... /// } /// }, @@ -997,7 +997,7 @@ class EditableText extends StatefulWidget { /// ``` /// {@end-tool} /// {@endtemplate} - final ValueChanged>? onContentCommitted; + final ValueChanged? onContentCommitted; /// {@template flutter.widgets.editableText.onEditingComplete} /// Called when the user submits editable content (e.g., user presses the "done" From c488647b3edc5d275f18e4dd997cc3cf0ebb0361 Mon Sep 17 00:00:00 2001 From: zlshames Date: Mon, 12 Jul 2021 14:32:24 -0400 Subject: [PATCH 13/41] Adds onContentCommitted to .borderless --- packages/flutter/lib/src/cupertino/text_field.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index 31913f85669b0..353bf936dd1ad 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -432,6 +432,7 @@ class CupertinoTextField extends StatefulWidget { this.maxLengthEnforced = true, this.maxLengthEnforcement, this.onChanged, + this.onContentCommitted, this.onEditingComplete, this.onSubmitted, this.inputFormatters, From 16c165fae5558dd35467e6fe2aac3787620ded7b Mon Sep 17 00:00:00 2001 From: Tanay Neotia Date: Sat, 6 Nov 2021 14:32:00 -0400 Subject: [PATCH 14/41] Fix tests --- packages/flutter/test/services/text_input_test.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/flutter/test/services/text_input_test.dart b/packages/flutter/test/services/text_input_test.dart index b8b24ed2a2998..fc6161e5cd8b0 100644 --- a/packages/flutter/test/services/text_input_test.dart +++ b/packages/flutter/test/services/text_input_test.dart @@ -488,5 +488,10 @@ class FakeTextInputClient implements TextInputClient { latestMethodCall = 'showAutocorrectionPromptRect'; } + @override + void commitContent(Map content) { + latestMethodCall = 'commitContent'; + } + TextInputConfiguration get configuration => const TextInputConfiguration(); } From fb4d7df7865850bca6b9ec43803bf9a3807882c5 Mon Sep 17 00:00:00 2001 From: Zach Shames Date: Thu, 11 Nov 2021 16:47:58 -0500 Subject: [PATCH 15/41] removes finalize action to prevent gif some auto-sending --- packages/flutter/lib/src/widgets/editable_text.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 5354abb906e1e..55611436db40c 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -1958,7 +1958,6 @@ class EditableTextState extends State with AutomaticKeepAliveClien @override void commitContent(Map content) { widget.onContentCommitted?.call(CommittedContent.fromMap(content)); - _finalizeEditing(TextInputAction.none, shouldUnfocus: false); } // The original position of the caret on FloatingCursorDragState.start. From 2ef5ad67fefb883d830b02fc59f5bac5443fc782 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Wed, 15 Dec 2021 07:50:56 -0800 Subject: [PATCH 16/41] Update configurations to match the current test beds. (#95303) * Update configurations to match the current test beds. * Update cirrus secrets. * Disable mac_module_test_ios. The fix for the test not available in this branch. --- .ci.yaml | 18 ++++++++---------- .cirrus.yml | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 3be70a9db8e67..e701a5747f246 100755 --- a/.ci.yaml +++ b/.ci.yaml @@ -6,12 +6,9 @@ # More information at: # * https://github.com/flutter/cocoon/blob/main/CI_YAML.md enabled_branches: - - flutter-2.8-candidate.3 - main - master - - dev - - beta - - stable + - flutter-\d+\.\d+-candidate\.\d+ platform_properties: linux: @@ -88,7 +85,7 @@ platform_properties: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"} ] - os: Mac-10.15 + os: Mac-12.0 device_os: N mac_ios: properties: @@ -109,9 +106,9 @@ platform_properties: {"dependency": "gems"}, {"dependency": "ios_signing"} ] - os: Mac-10.15 - device_os: iOS-14.4.2 - xcode: 12c33 + os: Mac-12.0 + device_os: iOS-15.1 + xcode: 13a233 mac_ios32: properties: caches: >- @@ -131,9 +128,9 @@ platform_properties: {"dependency": "gems"}, {"dependency": "ios_signing"} ] - os: Mac-10.15 + os: Mac-12.0 device_os: iOS-9.3.6 - xcode: 12c33 + xcode: 13a233 windows: properties: caches: >- @@ -2266,6 +2263,7 @@ targets: - name: Mac module_test_ios recipe: devicelab/devicelab_drone + bringup: true # Flaky https://github.com/flutter/flutter/issues/93517 timeout: 60 properties: caches: >- diff --git a/.cirrus.yml b/.cirrus.yml index f73e1dcb2d546..1da3b938cbaf7 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -12,7 +12,7 @@ environment: # dependency on precisely how Cirrus is detected by our tools. BOT: "true" -gcp_credentials: ENCRYPTED[!48cff44dd32e9cc412d4d381c7fe68d373ca04cf2639f8192d21cb1a9ab5e21129651423a1cf88f3fd7fe2125c1cabd9!] +gcp_credentials: ENCRYPTED[!cc769765170bebc37e0556e2da5915ca64ee37f4ec8c966ec147e2f59578b476c99e457eafce4e2f8b1a4e305f7096b8!] # LINUX SHARDS task: From 77d935af4db863f6abd0b9c31c7e6df2a13de57b Mon Sep 17 00:00:00 2001 From: godofredoc Date: Thu, 16 Dec 2021 08:37:33 -0800 Subject: [PATCH 17/41] [flutter_releases] Flutter stable 2.8.1 Framework Cherrypicks (#95375) * Build Flutter iOS plugins with all valid architectures (#95293) * 'add branch flutter-2.8-candidate.3 to enabled_branches in .ci.yaml' * 'Update Engine revision to 890a5fca2e34db413be624fc83aeea8e61d42ce6 for stable release 2.8.1' Co-authored-by: Jenn Magder --- .ci.yaml | 1 + bin/internal/engine.version | 2 +- packages/flutter_tools/bin/podhelper.rb | 11 ++- .../ios_content_validation_test.dart | 70 ++++++++++++++++--- 4 files changed, 70 insertions(+), 14 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index e701a5747f246..8b6f69430c567 100755 --- a/.ci.yaml +++ b/.ci.yaml @@ -6,6 +6,7 @@ # More information at: # * https://github.com/flutter/cocoon/blob/main/CI_YAML.md enabled_branches: + - flutter-2.8-candidate.3 - main - master - flutter-\d+\.\d+-candidate\.\d+ diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 19bc71393b394..e4d51ed7cc425 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -40a99c595137e4b2f5b2efa8ff343ea23c1e16b8 +890a5fca2e34db413be624fc83aeea8e61d42ce6 diff --git a/packages/flutter_tools/bin/podhelper.rb b/packages/flutter_tools/bin/podhelper.rb index 6a8185e9d3333..97e073dd84a63 100644 --- a/packages/flutter_tools/bin/podhelper.rb +++ b/packages/flutter_tools/bin/podhelper.rb @@ -33,9 +33,6 @@ def flutter_macos_podfile_setup def flutter_additional_ios_build_settings(target) return unless target.platform_name == :ios - # Return if it's not a Flutter plugin (transitive dependency). - return unless target.dependencies.any? { |dependency| dependency.name == 'Flutter' } - # [target.deployment_target] is a [String] formatted as "8.0". inherit_deployment_target = target.deployment_target[/\d+/].to_i < 9 @@ -52,6 +49,14 @@ def flutter_additional_ios_build_settings(target) release_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios-release', 'Flutter.xcframework'), __FILE__) target.build_configurations.each do |build_configuration| + # Build both x86_64 and arm64 simulator archs for all dependencies. If a single plugin does not support arm64 simulators, + # the app and all frameworks will fall back to x86_64. Unfortunately that case is not detectable in this script. + # Therefore all pods must have a x86_64 slice available, or linking a x86_64 app will fail. + build_configuration.build_settings['ONLY_ACTIVE_ARCH'] = 'NO' if build_configuration.type == :debug + + # Skip other updates if it's not a Flutter plugin (transitive dependency). + next unless target.dependencies.any? { |dependency| dependency.name == 'Flutter' } + # Profile can't be derived from the CocoaPods build configuration. Use release framework (for linking only). configuration_engine_dir = build_configuration.type == :debug ? debug_framework_dir : release_framework_dir Dir.new(configuration_engine_dir).each_child do |xcframework_file| diff --git a/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart b/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart index 1d3315683d37c..e8cb730f82e23 100644 --- a/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart +++ b/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart @@ -16,6 +16,7 @@ import 'test_utils.dart'; void main() { group('iOS app validation', () { String flutterRoot; + Directory pluginRoot; String projectRoot; String flutterBin; Directory tempDir; @@ -29,18 +30,20 @@ void main() { 'flutter', ); + // Test a plugin example app to allow plugins validation. processManager.runSync([ flutterBin, ...getLocalEngineArguments(), 'create', '--verbose', '--platforms=ios', - '-i', - 'objc', + '-t', + 'plugin', 'hello', ], workingDirectory: tempDir.path); - projectRoot = tempDir.childDirectory('hello').path; + pluginRoot = tempDir.childDirectory('hello'); + projectRoot = pluginRoot.childDirectory('example').path; }); tearDownAll(() { @@ -56,6 +59,7 @@ void main() { File outputFlutterFrameworkBinary; Directory outputAppFramework; File outputAppFrameworkBinary; + File outputPluginFrameworkBinary; setUpAll(() { processManager.runSync([ @@ -85,11 +89,13 @@ void main() { outputAppFramework = frameworkDirectory.childDirectory('App.framework'); outputAppFrameworkBinary = outputAppFramework.childFile('App'); + + outputPluginFrameworkBinary = frameworkDirectory.childDirectory('hello.framework').childFile('hello'); }); testWithoutContext('flutter build ios builds a valid app', () { - // Should only contain Flutter.framework and App.framework. - expect(frameworkDirectory.listSync().length, 2); + expect(outputPluginFrameworkBinary, exists); + expect(outputAppFrameworkBinary, exists); expect(outputAppFramework.childFile('Info.plist'), exists); @@ -202,17 +208,61 @@ void main() { }, skip: !platform.isMacOS || buildMode != BuildMode.release); // [intended] only makes sense on macos. testWithoutContext('validate obfuscation', () { - final ProcessResult grepResult = processManager.runSync([ + // HelloPlugin class is present in project. + ProcessResult grepResult = processManager.runSync([ + 'grep', + '-r', + 'HelloPlugin', + pluginRoot.path, + ]); + // Matches exits 0. + expect(grepResult.exitCode, 0); + + // Not present in binary. + grepResult = processManager.runSync([ 'grep', - '-i', - 'hello', + 'HelloPlugin', outputAppFrameworkBinary.path, ]); - expect(grepResult.stdout, isNot(contains('matches'))); + // Does not match exits 1. + expect(grepResult.exitCode, 1); }); }); } + testWithoutContext('builds all plugin architectures for simulator', () { + final ProcessResult buildSimulator = processManager.runSync( + [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--simulator', + '--verbose', + '--no-codesign', + ], + workingDirectory: projectRoot, + ); + expect(buildSimulator.exitCode, 0); + + final File pluginFrameworkBinary = fileSystem.file(fileSystem.path.join( + projectRoot, + 'build', + 'ios', + 'iphonesimulator', + 'Runner.app', + 'Frameworks', + 'hello.framework', + 'hello', + )); + expect(pluginFrameworkBinary, exists); + final ProcessResult archs = processManager.runSync( + ['file', pluginFrameworkBinary.path], + ); + expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library x86_64')); + expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64')); + }); + testWithoutContext('build for simulator with all available architectures', () { final ProcessResult buildSimulator = processManager.runSync( [ @@ -250,6 +300,6 @@ void main() { expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64')); }); }, skip: !platform.isMacOS, // [intended] only makes sense for macos platform. - timeout: const Timeout(Duration(minutes: 5)) + timeout: const Timeout(Duration(minutes: 7)) ); } From 290862cd149138ece6a702bf954ac9f0493d1d99 Mon Sep 17 00:00:00 2001 From: zlshames Date: Sat, 15 Jan 2022 11:17:03 -0500 Subject: [PATCH 18/41] Adds contentCommitMimeTypes widget param --- .../flutter/lib/src/cupertino/text_field.dart | 46 +++++++++++++++++++ .../flutter/lib/src/services/text_input.dart | 46 +++++++++++++++++++ .../lib/src/widgets/editable_text.dart | 45 ++++++++++++++++++ 3 files changed, 137 insertions(+) diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index 353bf936dd1ad..2631716cf3f67 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -294,6 +294,7 @@ class CupertinoTextField extends StatefulWidget { this.scrollController, this.scrollPhysics, this.autofillHints = const [], + this.contentCommitMimeTypes = const [], this.clipBehavior = Clip.hardEdge, this.restorationId, this.enableIMEPersonalizedLearning = true, @@ -339,6 +340,7 @@ class CupertinoTextField extends StatefulWidget { 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', ), assert(enableIMEPersonalizedLearning != null), + assert(contentCommitMimeTypes != null), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), toolbarOptions = toolbarOptions ?? (obscureText ? const ToolbarOptions( @@ -455,6 +457,7 @@ class CupertinoTextField extends StatefulWidget { this.clipBehavior = Clip.hardEdge, this.restorationId, this.enableIMEPersonalizedLearning = true, + this.contentCommitMimeTypes = const [], }) : assert(textAlign != null), assert(readOnly != null), assert(autofocus != null), @@ -498,6 +501,7 @@ class CupertinoTextField extends StatefulWidget { ), assert(clipBehavior != null), assert(enableIMEPersonalizedLearning != null), + assert(contentCommitMimeTypes!= null), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), toolbarOptions = toolbarOptions ?? (obscureText ? const ToolbarOptions( @@ -850,6 +854,47 @@ class CupertinoTextField extends StatefulWidget { /// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning} final bool enableIMEPersonalizedLearning; + /// Used when a user inserts image-based content through the device keyboard + /// on Android only. + /// + /// The passed list of strings will determine which MIME types are allowed to + /// be inserted via the device keyboard + /// + /// This example shows how to limit your keyboard commits to specific file types + /// `TextField`. + /// + /// ```dart + /// final TextEditingController _controller = TextEditingController(); + /// + /// @override + /// void dispose() { + /// _controller.dispose(); + /// super.dispose(); + /// } + /// + /// @override + /// Widget build(BuildContext context) { + /// return Scaffold( + /// body: Column( + /// mainAxisAlignment: MainAxisAlignment.center, + /// children: [ + /// const Text('Here's a text field that supports inserting gif content:'), + /// TextField( + /// controller: _controller, + /// contentCommitMimeTypes: ['image/gif', 'image/png'], + /// onContentCommitted: (CommittedContent data) async { + /// ... + /// }, + /// ), + /// ], + /// ), + /// ); + /// } + /// ``` + /// {@end-tool} + /// {@endtemplate} + final List contentCommitMimeTypes; + @override State createState() => _CupertinoTextFieldState(); @@ -893,6 +938,7 @@ class CupertinoTextField extends StatefulWidget { properties.add(EnumProperty('textDirection', textDirection, defaultValue: null)); properties.add(DiagnosticsProperty('clipBehavior', clipBehavior, defaultValue: Clip.hardEdge)); properties.add(DiagnosticsProperty('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true)); + properties.add(DiagnosticsProperty>('contentCommitMimeTypes', contentCommitMimeTypes, defaultValue: null)); } } diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index 6f0736c723c74..038f3d9c60d96 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -468,6 +468,7 @@ class TextInputConfiguration { this.textCapitalization = TextCapitalization.none, this.autofillConfiguration = AutofillConfiguration.disabled, this.enableIMEPersonalizedLearning = true, + this.contentCommitMimeTypes = const [], this.enableDeltaModel = false, }) : assert(inputType != null), assert(obscureText != null), @@ -479,6 +480,7 @@ class TextInputConfiguration { assert(inputAction != null), assert(textCapitalization != null), assert(enableIMEPersonalizedLearning != null), + assert(contentCommitMimeTypes != null), assert(enableDeltaModel != null); /// The type of information for which to optimize the text input control. @@ -609,6 +611,47 @@ class TextInputConfiguration { /// {@endtemplate} final bool enableIMEPersonalizedLearning; + /// Used when a user inserts image-based content through the device keyboard + /// on Android only. + /// + /// The passed list of strings will determine which MIME types are allowed to + /// be inserted via the device keyboard + /// + /// This example shows how to limit your keyboard commits to specific file types + /// `TextField`. + /// + /// ```dart + /// final TextEditingController _controller = TextEditingController(); + /// + /// @override + /// void dispose() { + /// _controller.dispose(); + /// super.dispose(); + /// } + /// + /// @override + /// Widget build(BuildContext context) { + /// return Scaffold( + /// body: Column( + /// mainAxisAlignment: MainAxisAlignment.center, + /// children: [ + /// const Text('Here's a text field that supports inserting gif content:'), + /// TextField( + /// controller: _controller, + /// contentCommitMimeTypes: ['image/gif', 'image/png'], + /// onContentCommitted: (CommittedContent data) async { + /// ... + /// }, + /// ), + /// ], + /// ), + /// ); + /// } + /// ``` + /// {@end-tool} + /// {@endtemplate} + final List contentCommitMimeTypes; + /// Creates a copy of this [TextInputConfiguration] with the given fields /// replaced with new values. TextInputConfiguration copyWith({ @@ -625,6 +668,7 @@ class TextInputConfiguration { TextCapitalization? textCapitalization, bool? enableIMEPersonalizedLearning, AutofillConfiguration? autofillConfiguration, + List? contentCommitMimeTypes, bool? enableDeltaModel, }) { return TextInputConfiguration( @@ -641,6 +685,7 @@ class TextInputConfiguration { enableIMEPersonalizedLearning: enableIMEPersonalizedLearning?? this.enableIMEPersonalizedLearning, autofillConfiguration: autofillConfiguration ?? this.autofillConfiguration, enableDeltaModel: enableDeltaModel ?? this.enableDeltaModel, + contentCommitMimeTypes: contentCommitMimeTypes ?? this.contentCommitMimeTypes ); } @@ -687,6 +732,7 @@ class TextInputConfiguration { 'enableIMEPersonalizedLearning': enableIMEPersonalizedLearning, if (autofill != null) 'autofill': autofill, 'enableDeltaModel' : enableDeltaModel, + 'contentCommitMimeTypes': contentCommitMimeTypes }; } } diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 55611436db40c..1231bcfb9fa8c 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -460,6 +460,7 @@ class EditableText extends StatefulWidget { ), this.autofillHints = const [], this.autofillClient, + this.contentCommitMimeTypes = const [], this.clipBehavior = Clip.hardEdge, this.restorationId, this.scrollBehavior, @@ -503,6 +504,7 @@ class EditableText extends StatefulWidget { assert(toolbarOptions != null), assert(clipBehavior != null), assert(enableIMEPersonalizedLearning != null), + assert(contentCommitMimeTypes != null), _strutStyle = strutStyle, keyboardType = keyboardType ?? _inferKeyboardType(autofillHints: autofillHints, maxLines: maxLines), inputFormatters = maxLines == 1 @@ -1285,6 +1287,47 @@ class EditableText extends StatefulWidget { /// [AutofillClient]. This property may override [autofillHints]. final AutofillClient? autofillClient; + /// Used when a user inserts image-based content through the device keyboard + /// on Android only. + /// + /// The passed list of strings will determine which MIME types are allowed to + /// be inserted via the device keyboard + /// + /// This example shows how to limit your keyboard commits to specific file types + /// `TextField`. + /// + /// ```dart + /// final TextEditingController _controller = TextEditingController(); + /// + /// @override + /// void dispose() { + /// _controller.dispose(); + /// super.dispose(); + /// } + /// + /// @override + /// Widget build(BuildContext context) { + /// return Scaffold( + /// body: Column( + /// mainAxisAlignment: MainAxisAlignment.center, + /// children: [ + /// const Text('Here's a text field that supports inserting gif content:'), + /// TextField( + /// controller: _controller, + /// contentCommitMimeTypes: ['image/gif', 'image/png'], + /// onContentCommitted: (CommittedContent data) async { + /// ... + /// }, + /// ), + /// ], + /// ), + /// ); + /// } + /// ``` + /// {@end-tool} + /// {@endtemplate} + final List contentCommitMimeTypes; + /// {@macro flutter.material.Material.clipBehavior} /// /// Defaults to [Clip.hardEdge]. @@ -1500,6 +1543,7 @@ class EditableText extends StatefulWidget { properties.add(DiagnosticsProperty>('autofillHints', autofillHints, defaultValue: null)); properties.add(DiagnosticsProperty('textHeightBehavior', textHeightBehavior, defaultValue: null)); properties.add(DiagnosticsProperty('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true)); + properties.add(DiagnosticsProperty>('contentCommitMimeTypes', contentCommitMimeTypes, defaultValue: null)); } } @@ -2840,6 +2884,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien keyboardAppearance: widget.keyboardAppearance, autofillConfiguration: autofillConfiguration, enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning, + contentCommitMimeTypes: widget.contentCommitMimeTypes ); } From f1bb12fc5c64cde4399954e9f407cc57d0a73705 Mon Sep 17 00:00:00 2001 From: zlshames Date: Sat, 15 Jan 2022 11:33:10 -0500 Subject: [PATCH 19/41] adds material support --- .../flutter/lib/src/material/text_field.dart | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index e4ccf319a2f5f..102ecb28d1761 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -350,6 +350,7 @@ class TextField extends StatefulWidget { this.clipBehavior = Clip.hardEdge, this.restorationId, this.enableIMEPersonalizedLearning = true, + this.contentCommitMimeTypes = const [], }) : assert(textAlign != null), assert(readOnly != null), assert(autofocus != null), @@ -391,6 +392,7 @@ class TextField extends StatefulWidget { ), assert(clipBehavior != null), assert(enableIMEPersonalizedLearning != null), + assert(contentCommitMimeTypes != null), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), toolbarOptions = toolbarOptions ?? (obscureText ? const ToolbarOptions( @@ -840,6 +842,47 @@ class TextField extends StatefulWidget { /// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning} final bool enableIMEPersonalizedLearning; + /// Used when a user inserts image-based content through the device keyboard + /// on Android only. + /// + /// The passed list of strings will determine which MIME types are allowed to + /// be inserted via the device keyboard + /// + /// This example shows how to limit your keyboard commits to specific file types + /// `TextField`. + /// + /// ```dart + /// final TextEditingController _controller = TextEditingController(); + /// + /// @override + /// void dispose() { + /// _controller.dispose(); + /// super.dispose(); + /// } + /// + /// @override + /// Widget build(BuildContext context) { + /// return Scaffold( + /// body: Column( + /// mainAxisAlignment: MainAxisAlignment.center, + /// children: [ + /// const Text('Here's a text field that supports inserting gif content:'), + /// TextField( + /// controller: _controller, + /// contentCommitMimeTypes: ['image/gif', 'image/png'], + /// onContentCommitted: (CommittedContent data) async { + /// ... + /// }, + /// ), + /// ], + /// ), + /// ); + /// } + /// ``` + /// {@end-tool} + /// {@endtemplate} + final List contentCommitMimeTypes; + @override State createState() => _TextFieldState(); @@ -882,6 +925,7 @@ class TextField extends StatefulWidget { properties.add(DiagnosticsProperty('scrollPhysics', scrollPhysics, defaultValue: null)); properties.add(DiagnosticsProperty('clipBehavior', clipBehavior, defaultValue: Clip.hardEdge)); properties.add(DiagnosticsProperty('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true)); + properties.add(DiagnosticsProperty>('contentCommitMimeTypes', contentCommitMimeTypes, defaultValue: null)); } } From cd286dd76ef176847b9193be33b458af03390d62 Mon Sep 17 00:00:00 2001 From: Zach Shames Date: Sun, 16 Jan 2022 10:32:28 -0500 Subject: [PATCH 20/41] Revert "Flutter Master" --- .ci.yaml | 1245 +++---- .github/workflows/no-response.yaml | 2 +- CODE_OF_CONDUCT.md | 16 +- CONTRIBUTING.md | 9 +- TESTOWNERS | 9 +- analysis_options.yaml | 12 +- bin/flutter | 5 - bin/flutter.bat | 6 +- bin/internal/canvaskit.version | 2 +- bin/internal/engine.version | 2 +- bin/internal/flutter_plugins.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- bin/internal/material_fonts.version | 2 +- bin/internal/shared.bat | 12 +- bin/internal/shared.sh | 30 +- bin/internal/update_dart_sdk.sh | 17 +- dev/automated_tests/pubspec.yaml | 22 +- .../android/app/src/main/AndroidManifest.xml | 7 +- .../android/project-app.lockfile | 11 +- .../android/project-integration_test.lockfile | 11 +- dev/benchmarks/complex_layout/pubspec.yaml | 22 +- .../test_driver/semantics_perf_test.dart | 4 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../android/project-app.lockfile | 11 +- .../android/project-integration_test.lockfile | 11 +- .../macrobenchmarks/lib/common.dart | 11 - dev/benchmarks/macrobenchmarks/lib/main.dart | 10 - .../lib/src/opacity_peephole.dart | 332 -- .../bench_dynamic_clip_on_static_picture.dart | 2 +- .../lib/src/web/bench_image_decoding.dart | 93 - .../lib/src/web/bench_text_layout.dart | 65 +- .../macrobenchmarks/lib/src/web/recorder.dart | 225 +- .../macrobenchmarks/lib/web_benchmarks.dart | 9 +- dev/benchmarks/macrobenchmarks/pubspec.yaml | 22 +- ...opacity_peephole_col_of_rows_perf_e2e.dart | 19 - ...eephole_fade_transition_text_perf_e2e.dart | 19 - ...ity_peephole_grid_of_opacity_perf_e2e.dart | 19 - .../opacity_peephole_one_rect_perf_e2e.dart | 19 - ...ity_peephole_opacity_of_grid_perf_e2e.dart | 19 - dev/benchmarks/macrobenchmarks/test/util.dart | 56 +- .../android/app/src/main/AndroidManifest.xml | 9 +- dev/benchmarks/microbenchmarks/pubspec.yaml | 20 +- .../android/app/build.gradle | 4 +- .../flutter/multipleflutters/MainActivity.kt | 11 +- .../multiple_flutters/android/build.gradle | 2 +- .../multiple_flutters/module/lib/main.dart | 149 +- .../multiple_flutters/module/pubspec.yaml | 31 +- .../platform_channels_benchmarks/pubspec.yaml | 22 +- .../android/app/src/main/AndroidManifest.xml | 2 +- .../android/project-app.lockfile | 11 +- .../platform_views_layout/pubspec.yaml | 22 +- .../android/app/src/main/AndroidManifest.xml | 2 +- .../android/project-app.lockfile | 11 +- .../pubspec.yaml | 22 +- .../stocks/android/project-app.lockfile | 11 +- dev/benchmarks/test_apps/stocks/pubspec.yaml | 22 +- dev/bots/allowlist.dart | 2 +- dev/bots/analyze.dart | 265 +- dev/bots/analyze_sample_code.dart | 4 +- dev/bots/docs.sh | 3 + dev/bots/prepare_package.dart | 64 +- dev/bots/pubspec.yaml | 33 +- dev/bots/test.dart | 195 +- .../root/packages/flutter/lib/bar.dart | 18 - dev/bots/test/analyze_test.dart | 25 +- dev/bots/test/prepare_package_test.dart | 28 +- dev/conductor/README.md | 35 +- dev/conductor/core/bin/cli.dart | 6 + dev/conductor/core/lib/conductor_core.dart | 1 + dev/conductor/core/lib/src/clean.dart | 27 +- dev/conductor/core/lib/src/codesign.dart | 83 +- dev/conductor/core/lib/src/context.dart | 54 - dev/conductor/core/lib/src/git.dart | 53 +- dev/conductor/core/lib/src/globals.dart | 43 +- dev/conductor/core/lib/src/next.dart | 250 +- dev/conductor/core/lib/src/repository.dart | 76 +- dev/conductor/core/lib/src/roll_dev.dart | 204 ++ dev/conductor/core/lib/src/start.dart | 209 +- dev/conductor/core/lib/src/state.dart | 2 +- dev/conductor/core/lib/src/stdio.dart | 23 +- dev/conductor/core/lib/src/version.dart | 43 +- dev/conductor/core/pubspec.yaml | 25 +- dev/conductor/core/test/clean_test.dart | 27 +- .../core/test/codesign_integration_test.dart | 23 +- dev/conductor/core/test/codesign_test.dart | 25 - dev/conductor/core/test/common.dart | 11 +- dev/conductor/core/test/globals_test.dart | 66 - dev/conductor/core/test/next_test.dart | 271 +- dev/conductor/core/test/repository_test.dart | 214 +- dev/conductor/core/test/roll_dev_test.dart | 708 ++++ dev/conductor/core/test/start_test.dart | 451 +-- dev/conductor/core/test/version_test.dart | 18 - dev/customer_testing/ci.bat | 2 +- dev/customer_testing/ci.sh | 2 +- dev/customer_testing/pubspec.yaml | 19 +- dev/devicelab/README.md | 29 +- dev/devicelab/bin/run.dart | 446 ++- .../build_ios_framework_module_test.dart | 38 +- dev/devicelab/bin/tasks/flavors_test.dart | 8 +- dev/devicelab/bin/tasks/flavors_test_ios.dart | 8 +- dev/devicelab/bin/tasks/flavors_test_win.dart | 8 +- .../tasks/ios_app_with_extensions_test.dart | 241 +- .../module_custom_host_app_name_test.dart | 2 +- dev/devicelab/bin/tasks/module_test.dart | 2 +- dev/devicelab/bin/tasks/module_test_ios.dart | 74 +- .../bin/tasks/native_ui_tests_ios.dart | 6 +- .../bin/tasks/native_ui_tests_macos.dart | 7 +- ...eephole_col_of_rows_perf__e2e_summary.dart | 14 - ...ade_transition_text_perf__e2e_summary.dart | 14 - ...ole_grid_of_opacity_perf__e2e_summary.dart | 14 - ...y_peephole_one_rect_perf__e2e_summary.dart | 14 - ...ole_opacity_of_grid_perf__e2e_summary.dart | 14 - dev/devicelab/bin/tasks/plugin_test.dart | 2 - dev/devicelab/bin/tasks/plugin_test_ios.dart | 3 - dev/devicelab/bin/tasks/run_release_test.dart | 2 - ...na_hot_mode_dev_cycle_ios__benchmark.dart} | 0 ...t_up.dart => smoke_catalina_start_up.dart} | 0 dev/devicelab/lib/command/test.dart | 1 - dev/devicelab/lib/framework/devices.dart | 18 - dev/devicelab/lib/framework/framework.dart | 60 +- dev/devicelab/lib/framework/ios.dart | 31 +- .../lib/framework/metrics_center.dart | 15 +- dev/devicelab/lib/framework/runner.dart | 37 +- .../lib/framework/running_processes.dart | 91 +- dev/devicelab/lib/framework/utils.dart | 59 +- .../lib/tasks/integration_tests.dart | 17 +- dev/devicelab/lib/tasks/perf_tests.dart | 48 +- dev/devicelab/lib/tasks/plugin_tests.dart | 101 +- dev/devicelab/lib/versions/gallery.dart | 2 +- dev/devicelab/pubspec.yaml | 33 +- dev/devicelab/test/metrics_center_test.dart | 12 +- dev/devicelab/test/run_test.dart | 12 +- dev/devicelab/test/runner_test.dart | 5 +- .../test/running_processes_test.dart | 92 +- .../test/tasks/build_test_task_test.dart | 3 +- dev/devicelab/test/utils_test.dart | 4 +- dev/docs/assets/overrides.css | 19 + dev/docs/google2ed1af765c529f57.html | 1 + dev/docs/styles.html | 2 +- dev/forbidden_from_release_tests/pubspec.yaml | 6 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../android/project-app.lockfile | 15 +- .../abstract_method_smoke_test/pubspec.yaml | 3 +- .../SampleApp/build.gradle | 4 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../android/project-app.lockfile | 8 +- .../android/project-battery.lockfile | 11 +- .../pubspec.yaml | 11 +- .../app/build.gradle | 4 +- .../android/app/src/main/AndroidManifest.xml | 13 +- .../platforminteraction/MainActivity.java | 17 +- .../android/project-app.lockfile | 11 +- .../lib/src/matcher.dart | 14 +- .../android_semantics_testing/pubspec.yaml | 22 +- .../test_driver/main_test.dart | 12 +- .../android/app/src/main/AndroidManifest.xml | 2 +- .../android/project-app.lockfile | 11 +- .../android/project-path_provider.lockfile | 11 +- .../android_views/pubspec.yaml | 40 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../channels/android/project-app.lockfile | 11 +- dev/integration_tests/channels/pubspec.yaml | 22 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../android/component1/build.gradle | 4 +- .../deferred_components_test/pubspec.yaml | 22 +- .../run_release_test.sh | 25 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../io/flutter/externalui/MainActivity.java | 22 +- .../external_ui/android/project-app.lockfile | 11 +- .../external_ui/pubspec.yaml | 22 +- .../android/app/src/main/AndroidManifest.xml | 7 +- .../com/yourcompany/flavors/MainActivity.java | 21 +- .../flavors/android/project-app.lockfile | 11 +- .../android/project-integration_test.lockfile | 11 +- .../integration_test/integration_test.dart | 21 - dev/integration_tests/flavors/lib/main.dart | 4 - dev/integration_tests/flavors/pubspec.yaml | 22 +- .../flutter_gallery/android/app/build.gradle | 1 - .../android/app/src/main/AndroidManifest.xml | 3 +- .../android/project-app.lockfile | 25 +- .../android/project-connectivity.lockfile | 11 +- .../android/project-device_info.lockfile | 11 +- .../android/project-integration_test.lockfile | 11 +- .../android/project-url_launcher.lockfile | 11 +- .../project-url_launcher_android.lockfile | 164 - .../android/project-video_player.lockfile | 30 +- .../material/date_and_time_picker_demo.dart | 2 + .../flutter_gallery/lib/demo/shrine/app.dart | 2 + .../flutter_gallery/lib/demo/video_demo.dart | 4 + .../flutter_gallery/macos/Podfile.lock | 2 +- .../macos/Runner/Base.lproj/MainMenu.xib | 4 - .../macos/RunnerTests/RunnerTests.m | 15 +- .../flutter_gallery/pubspec.yaml | 59 +- .../test/flutter_test_config.dart | 18 +- .../flutter_gallery/test/smoke_test.dart | 2 +- .../android/app/build.gradle | 3 +- .../android/app/src/main/AndroidManifest.xml | 7 +- .../com/yourcompany/flavors/MainActivity.java | 13 +- .../android/project-app.lockfile | 11 +- .../android/project-camera.lockfile | 11 +- ...-flutter_plugin_android_lifecycle.lockfile | 11 +- .../gradle_deprecated_settings/pubspec.yaml | 15 +- .../android/app/src/main/AndroidManifest.xml | 2 +- .../android/project-app.lockfile | 11 +- .../android/project-path_provider.lockfile | 11 +- .../hybrid_android_views/pubspec.yaml | 40 +- .../flutterapp/pubspec.yaml | 9 +- .../ios/Runner.xcodeproj/project.pbxproj | 26 + .../xcshareddata/xcschemes/Runner.xcscheme | 8 +- .../ios_app_with_extensions/pubspec.yaml | 11 +- .../FlutterUITests/FlutterUITests.m | 14 +- .../ios_host_app/Host/MainViewController.m | 33 +- .../ios_platform_view_tests/pubspec.yaml | 22 +- .../app/build.gradle | 4 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../non_nullable/android/project-app.lockfile | 15 +- .../non_nullable/pubspec.yaml | 9 +- .../android/app/src/main/AndroidManifest.xml | 14 +- .../platforminteraction/MainActivity.java | 19 +- .../android/project-app.lockfile | 11 +- .../platform_interaction/pubspec.yaml | 22 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../android/project-app.lockfile | 11 +- .../android/project-integration_test.lockfile | 11 +- .../release_smoke_test/pubspec.yaml | 9 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../ui/android/project-app.lockfile | 11 +- .../android/project-integration_test.lockfile | 11 +- dev/integration_tests/ui/pubspec.yaml | 24 +- dev/integration_tests/web/pubspec.yaml | 3 +- .../web_compile_tests/pubspec.yaml | 3 +- .../web_e2e_tests/pubspec.yaml | 24 +- dev/manual_tests/android/.gitignore | 13 - dev/manual_tests/android/app/build.gradle | 6 +- .../android/app/src/debug/AndroidManifest.xml | 2 +- .../android/app/src/main/AndroidManifest.xml | 20 +- .../com/example/manual_tests/MainActivity.kt | 12 + .../dev/flutter/manual_tests/MainActivity.kt | 6 - .../res/drawable-v21/launch_background.xml | 16 - .../main/res/drawable/launch_background.xml | 1 - .../app/src/main/res/values-night/styles.xml | 22 - .../app/src/main/res/values/styles.xml | 13 +- .../app/src/profile/AndroidManifest.xml | 2 +- dev/manual_tests/android/project-app.lockfile | 15 +- dev/manual_tests/ios/.gitignore | 34 - .../ios/Flutter/AppFrameworkInfo.plist | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 36 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 8 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - dev/manual_tests/ios/Runner/Info.plist | 4 +- dev/manual_tests/linux/.gitignore | 1 - dev/manual_tests/linux/CMakeLists.txt | 116 - dev/manual_tests/linux/flutter/CMakeLists.txt | 87 - .../flutter/generated_plugin_registrant.cc | 11 - .../flutter/generated_plugin_registrant.h | 15 - .../linux/flutter/generated_plugins.cmake | 15 - dev/manual_tests/linux/main.cc | 10 - dev/manual_tests/linux/my_application.cc | 108 - dev/manual_tests/linux/my_application.h | 22 - dev/manual_tests/macos/.gitignore | 1 - .../macos/Runner.xcodeproj/project.pbxproj | 6 +- .../xcshareddata/xcschemes/Runner.xcscheme | 8 +- .../macos/Runner/Base.lproj/MainMenu.xib | 4 - .../macos/Runner/Configs/AppInfo.xcconfig | 4 +- dev/manual_tests/pubspec.yaml | 7 +- dev/manual_tests/web/favicon.png | Bin 917 -> 0 bytes dev/manual_tests/web/icons/Icon-192.png | Bin 5292 -> 0 bytes dev/manual_tests/web/icons/Icon-512.png | Bin 8252 -> 0 bytes .../web/icons/Icon-maskable-192.png | Bin 5292 -> 0 bytes .../web/icons/Icon-maskable-512.png | Bin 8252 -> 0 bytes dev/manual_tests/web/index.html | 97 +- dev/manual_tests/web/manifest.json | 35 - .../windows/flutter/CMakeLists.txt | 1 - .../windows/runner/CMakeLists.txt | 1 + dev/manual_tests/windows/runner/Runner.rc | 16 +- .../windows/runner/flutter_window.cpp | 11 +- .../windows/runner/flutter_window.h | 10 +- dev/manual_tests/windows/runner/main.cpp | 15 +- dev/manual_tests/windows/runner/resource.h | 3 +- .../windows/runner/resources/app_icon.ico | Bin 787 -> 0 bytes dev/manual_tests/windows/runner/run_loop.cpp | 66 + dev/manual_tests/windows/runner/run_loop.h | 44 + dev/snippets/config/templates/README.md | 15 +- dev/tools/gen_defaults/README.md | 27 - dev/tools/gen_defaults/bin/gen_defaults.dart | 29 - .../gen_defaults/data/material-tokens.json | 1044 ------ dev/tools/gen_defaults/lib/fab_template.dart | 90 - dev/tools/gen_defaults/lib/template.dart | 91 - dev/tools/gen_defaults/pubspec.yaml | 60 - .../gen_defaults/test/gen_defaults_test.dart | 110 - dev/tools/gen_keycodes/data/keyboard_key.tmpl | 140 +- .../gen_keycodes/data/logical_key_data.json | 6 - .../gen_keycodes/data/physical_key_data.json | 11 - .../data/windows_logical_to_window_vk.json | 2 +- .../gen_keycodes/lib/logical_key_data.dart | 6 +- dev/tools/gen_keycodes/pubspec.yaml | 21 +- dev/tools/pubspec.yaml | 23 +- dev/tools/test/update_icons_test.dart | 39 - dev/tools/update_icons.dart | 240 +- dev/tools/vitool/pubspec.yaml | 7 +- dev/tracing_tests/README.md | 11 - dev/tracing_tests/android/.gitignore | 13 - dev/tracing_tests/android/app/build.gradle | 72 - .../android/app/src/debug/AndroidManifest.xml | 11 - .../android/app/src/main/AndroidManifest.xml | 38 - .../com/example/tracing_tests/MainActivity.kt | 6 - .../res/drawable-v21/launch_background.xml | 15 - .../main/res/drawable/launch_background.xml | 15 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values-night/styles.xml | 21 - .../app/src/main/res/values/styles.xml | 21 - .../app/src/profile/AndroidManifest.xml | 11 - dev/tracing_tests/android/build.gradle | 35 - dev/tracing_tests/android/gradle.properties | 3 - dev/tracing_tests/android/settings.gradle | 15 - dev/tracing_tests/lib/control.dart | 16 - dev/tracing_tests/lib/test.dart | 70 - dev/tracing_tests/pubspec.yaml | 9 +- dev/tracing_tests/test/common.dart | 34 - .../test/image_cache_tracing_test.dart | 27 +- dev/tracing_tests/test/timeline_test.dart | 155 - examples/api/android/build.gradle | 2 +- .../cupertino/button/cupertino_button.0.dart | 57 - .../date_picker/cupertino_date_picker.0.dart | 186 - ...eletable_chip_attributes.on_deleted.0.dart | 8 +- .../lib/material/ink/ink.image_clip.0.dart | 55 - .../lib/material/ink/ink.image_clip.1.dart | 57 - ...coration.floating_label_style_error.0.dart | 58 - .../input_decoration.label_style_error.0.dart | 58 - .../reorderable_list_view.0.dart | 2 +- .../reorderable_list_view.1.dart | 85 - .../services/mouse_cursor/mouse_cursor.0.dart | 48 - examples/api/lib/ui/text/font_feature.0.dart | 79 - ...nt_feature.font_feature_alternative.0.dart | 40 - ....font_feature_alternative_fractions.0.dart | 40 - ...e.font_feature_case_sensitive_forms.0.dart | 40 - ...ture.font_feature_character_variant.0.dart | 42 - ....font_feature_contextual_alternates.0.dart | 40 - ...nt_feature.font_feature_denominator.0.dart | 40 - ...font_feature.font_feature_fractions.0.dart | 40 - ...ature.font_feature_historical_forms.0.dart | 41 - ...e.font_feature_historical_ligatures.0.dart | 42 - ...feature.font_feature_lining_figures.0.dart | 40 - ...t_feature.font_feature_locale_aware.0.dart | 38 - ...ature.font_feature_notational_forms.0.dart | 40 - ...ont_feature.font_feature_numerators.0.dart | 41 - ...ature.font_feature_oldstyle_figures.0.dart | 40 - ..._feature.font_feature_ordinal_forms.0.dart | 40 - ...e.font_feature_proportional_figures.0.dart | 40 - ...e.font_feature_scientific_inferiors.0.dart | 40 - ...t_feature.font_feature_slashed_zero.0.dart | 40 - ...e.font_feature_stylistic_alternates.0.dart | 40 - ..._feature.font_feature_stylistic_set.0.dart | 42 - ..._feature.font_feature_stylistic_set.1.dart | 41 - ...ont_feature.font_feature_subscripts.0.dart | 40 - ...t_feature.font_feature_superscripts.0.dart | 40 - .../font_feature.font_feature_swash.0.dart | 40 - ...eature.font_feature_tabular_figures.0.dart | 40 - .../actions/action.action_overridable.0.dart | 19 +- .../lib/widgets/async/stream_builder.0.dart | 17 +- .../basic/custom_multi_child_layout.0.dart | 124 - .../focus_manager/focus_node.unfocus.0.dart | 2 +- ...ti_child_render_object_widget_mixin.0.dart | 289 -- ...pop_scope.0.dart => will_pop_scope.1.dart} | 2 +- examples/api/pubspec.yaml | 24 +- .../button/cupertino_button.0_test.dart | 19 - .../cupertino_date_picker.0_test.dart | 67 - .../material/ink/ink.image_clip.0_test.dart | 34 - .../material/ink/ink.image_clip.1_test.dart | 34 - ...ion.floating_label_style_error.0_test.dart | 22 - ...t_decoration.label_style_error.0_test.dart | 19 - .../mouse_cursor/mouse_cursor.0_test.dart | 21 - .../api/test/ui/text/font_feature.0_test.dart | 29 - ...ature.font_feature_alternative.0_test.dart | 24 - ..._feature_alternative_fractions.0_test.dart | 24 - ...t_feature_case_sensitive_forms.0_test.dart | 24 - ...font_feature_character_variant.0_test.dart | 29 - ..._feature_contextual_alternates.0_test.dart | 24 - ...ature.font_feature_denominator.0_test.dart | 24 - ...feature.font_feature_fractions.0_test.dart | 24 - ....font_feature_historical_forms.0_test.dart | 24 - ...t_feature_historical_ligatures.0_test.dart | 24 - ...re.font_feature_lining_figures.0_test.dart | 24 - ...ture.font_feature_locale_aware.0_test.dart | 23 - ....font_feature_notational_forms.0_test.dart | 24 - ...eature.font_feature_numerators.0_test.dart | 24 - ....font_feature_oldstyle_figures.0_test.dart | 24 - ...ure.font_feature_ordinal_forms.0_test.dart | 24 - ...t_feature_proportional_figures.0_test.dart | 24 - ...t_feature_scientific_inferiors.0_test.dart | 24 - ...ture.font_feature_slashed_zero.0_test.dart | 24 - ...t_feature_stylistic_alternates.0_test.dart | 24 - ...ure.font_feature_stylistic_set.0_test.dart | 32 - ...ure.font_feature_stylistic_set.1_test.dart | 31 - ...eature.font_feature_subscripts.0_test.dart | 26 - ...ture.font_feature_superscripts.0_test.dart | 26 - ...ont_feature.font_feature_swash.0_test.dart | 26 - ...e.font_feature_tabular_figures.0_test.dart | 26 - .../custom_multi_child_layout.0_test.dart | 59 - ...ild_render_object_widget_mixin.0_test.dart | 41 - .../will_pop_scope/will_pop_scope.0_test.dart | 32 - .../flutter_view/android/project-app.lockfile | 11 +- examples/flutter_view/pubspec.yaml | 3 +- .../hello_world/android/project-app.lockfile | 11 +- examples/hello_world/pubspec.yaml | 22 +- .../image_list/android/project-app.lockfile | 11 +- examples/image_list/pubspec.yaml | 9 +- examples/layers/android/project-app.lockfile | 11 +- examples/layers/pubspec.yaml | 7 +- .../android/project-app.lockfile | 11 +- examples/platform_channel/pubspec.yaml | 22 +- examples/platform_channel_swift/pubspec.yaml | 22 +- .../android/project-app.lockfile | 11 +- examples/platform_view/pubspec.yaml | 3 +- examples/splash/pubspec.yaml | 7 +- packages/flutter/lib/fix_data.yaml | 143 - .../lib/src/animation/listener_helpers.dart | 20 +- .../lib/src/cupertino/activity_indicator.dart | 10 +- packages/flutter/lib/src/cupertino/app.dart | 10 +- .../lib/src/cupertino/bottom_tab_bar.dart | 14 +- .../flutter/lib/src/cupertino/button.dart | 7 - .../lib/src/cupertino/context_menu.dart | 30 +- .../src/cupertino/context_menu_action.dart | 22 +- .../lib/src/cupertino/date_picker.dart | 10 - .../src/cupertino/desktop_text_selection.dart | 9 +- .../flutter/lib/src/cupertino/dialog.dart | 12 +- packages/flutter/lib/src/cupertino/icons.dart | 35 +- packages/flutter/lib/src/cupertino/route.dart | 17 +- .../flutter/lib/src/cupertino/scrollbar.dart | 2 - .../flutter/lib/src/cupertino/tab_view.dart | 2 +- .../flutter/lib/src/cupertino/text_field.dart | 105 +- .../lib/src/foundation/assertions.dart | 52 +- .../lib/src/foundation/basic_types.dart | 8 +- .../flutter/lib/src/foundation/bitfield.dart | 8 +- .../lib/src/foundation/change_notifier.dart | 8 +- .../flutter/lib/src/foundation/debug.dart | 15 - .../lib/src/foundation/diagnostics.dart | 95 +- .../flutter/lib/src/foundation/isolates.dart | 16 +- .../flutter/lib/src/foundation/licenses.dart | 41 +- .../flutter/lib/src/foundation/platform.dart | 4 +- .../flutter/lib/src/foundation/print.dart | 12 +- .../flutter/lib/src/gestures/binding.dart | 14 +- .../flutter/lib/src/gestures/converter.dart | 373 +- .../flutter/lib/src/gestures/monodrag.dart | 8 +- .../flutter/lib/src/gestures/multitap.dart | 2 +- .../lib/src/gestures/pointer_router.dart | 14 +- .../src/gestures/pointer_signal_resolver.dart | 6 +- .../flutter/lib/src/gestures/recognizer.dart | 10 +- packages/flutter/lib/src/gestures/tap.dart | 11 +- packages/flutter/lib/src/gestures/team.dart | 12 +- packages/flutter/lib/src/material/about.dart | 149 +- packages/flutter/lib/src/material/app.dart | 12 +- .../flutter/lib/src/material/app_bar.dart | 2 +- .../src/material/bottom_navigation_bar.dart | 9 +- .../material/bottom_navigation_bar_theme.dart | 4 +- .../lib/src/material/bottom_sheet.dart | 7 +- .../src/material/calendar_date_picker.dart | 1 - .../flutter/lib/src/material/checkbox.dart | 24 +- .../lib/src/material/checkbox_list_tile.dart | 11 - packages/flutter/lib/src/material/chip.dart | 336 +- .../flutter/lib/src/material/chip_theme.dart | 230 +- .../lib/src/material/color_scheme.dart | 987 ++---- packages/flutter/lib/src/material/colors.dart | 3 + .../flutter/lib/src/material/data_table.dart | 4 +- .../src/material/desktop_text_selection.dart | 9 +- packages/flutter/lib/src/material/dialog.dart | 2 +- .../flutter/lib/src/material/dropdown.dart | 9 +- .../lib/src/material/elevated_button.dart | 4 +- .../lib/src/material/expansion_panel.dart | 2 - .../lib/src/material/flexible_space_bar.dart | 12 +- .../src/material/floating_action_button.dart | 226 +- .../floating_action_button_theme.dart | 10 - .../flutter/lib/src/material/icon_button.dart | 23 +- packages/flutter/lib/src/material/icons.dart | 3125 +---------------- .../lib/src/material/ink_decoration.dart | 21 - .../flutter/lib/src/material/ink_well.dart | 34 +- .../lib/src/material/input_border.dart | 22 +- .../lib/src/material/input_decorator.dart | 623 ++-- .../flutter/lib/src/material/list_tile.dart | 262 +- .../flutter/lib/src/material/material.dart | 1 - .../lib/src/material/material_state.dart | 19 +- .../lib/src/material/mergeable_material.dart | 5 +- .../lib/src/material/navigation_bar.dart | 45 +- .../lib/src/material/navigation_rail.dart | 110 +- .../src/material/navigation_rail_theme.dart | 24 +- .../lib/src/material/outlined_button.dart | 6 +- .../src/material/paginated_data_table.dart | 16 +- .../flutter/lib/src/material/popup_menu.dart | 69 +- .../lib/src/material/popup_menu_theme.dart | 27 +- .../lib/src/material/progress_indicator.dart | 8 +- packages/flutter/lib/src/material/radio.dart | 20 - .../lib/src/material/refresh_indicator.dart | 2 - .../lib/src/material/reorderable_list.dart | 14 +- .../flutter/lib/src/material/scaffold.dart | 7 +- .../flutter/lib/src/material/scrollbar.dart | 39 +- .../lib/src/material/scrollbar_theme.dart | 19 +- .../lib/src/material/selectable_text.dart | 10 +- packages/flutter/lib/src/material/slider.dart | 73 +- .../lib/src/material/slider_theme.dart | 129 +- .../flutter/lib/src/material/snack_bar.dart | 2 +- packages/flutter/lib/src/material/switch.dart | 38 - .../lib/src/material/tab_bar_theme.dart | 56 +- .../lib/src/material/tab_controller.dart | 42 +- packages/flutter/lib/src/material/tabs.dart | 65 +- .../flutter/lib/src/material/text_button.dart | 4 +- .../flutter/lib/src/material/text_field.dart | 109 +- .../lib/src/material/text_form_field.dart | 7 +- .../flutter/lib/src/material/text_theme.dart | 449 +-- packages/flutter/lib/src/material/theme.dart | 2 - .../flutter/lib/src/material/theme_data.dart | 2243 ++++++------ .../lib/src/material/toggle_buttons.dart | 162 +- .../flutter/lib/src/material/toggleable.dart | 4 - .../flutter/lib/src/material/typography.dart | 454 ++- .../lib/src/painting/_network_image_io.dart | 10 +- .../lib/src/painting/_network_image_web.dart | 10 +- .../lib/src/painting/decoration_image.dart | 11 +- .../lib/src/painting/image_provider.dart | 40 +- .../lib/src/painting/image_stream.dart | 17 +- .../lib/src/painting/matrix_utils.dart | 2 +- .../lib/src/painting/text_painter.dart | 14 +- .../flutter/lib/src/painting/text_style.dart | 2 +- .../flutter/lib/src/rendering/binding.dart | 8 +- packages/flutter/lib/src/rendering/box.dart | 59 +- .../lib/src/rendering/custom_paint.dart | 10 - packages/flutter/lib/src/rendering/debug.dart | 29 +- .../rendering/debug_overflow_indicator.dart | 16 +- .../flutter/lib/src/rendering/editable.dart | 194 +- packages/flutter/lib/src/rendering/flex.dart | 6 +- packages/flutter/lib/src/rendering/layer.dart | 211 +- .../src/rendering/list_wheel_viewport.dart | 27 +- .../flutter/lib/src/rendering/object.dart | 147 +- .../flutter/lib/src/rendering/paragraph.dart | 2 +- .../flutter/lib/src/rendering/proxy_box.dart | 10 +- .../lib/src/rendering/shifted_box.dart | 6 +- .../flutter/lib/src/rendering/sliver.dart | 6 +- .../rendering/sliver_fixed_extent_list.dart | 8 +- packages/flutter/lib/src/rendering/table.dart | 6 +- packages/flutter/lib/src/rendering/view.dart | 8 +- .../flutter/lib/src/rendering/viewport.dart | 33 +- .../flutter/lib/src/scheduler/binding.dart | 69 +- .../flutter/lib/src/semantics/semantics.dart | 10 +- .../flutter/lib/src/services/binding.dart | 60 +- .../lib/src/services/hardware_keyboard.dart | 12 +- .../lib/src/services/keyboard_key.dart | 8 - .../lib/src/services/keyboard_maps.dart | 4 - .../lib/src/services/mouse_cursor.dart | 20 +- .../lib/src/services/platform_channel.dart | 12 +- .../lib/src/services/raw_keyboard.dart | 67 +- .../lib/src/services/raw_keyboard_macos.dart | 46 +- .../lib/src/services/raw_keyboard_web.dart | 14 +- .../flutter/lib/src/services/restoration.dart | 2 +- .../lib/src/services/system_channels.dart | 8 +- .../lib/src/services/text_editing.dart | 43 +- .../flutter/lib/src/services/text_input.dart | 52 - packages/flutter/lib/src/widgets/actions.dart | 21 +- packages/flutter/lib/src/widgets/app.dart | 100 +- packages/flutter/lib/src/widgets/async.dart | 2 +- .../flutter/lib/src/widgets/autocomplete.dart | 4 + packages/flutter/lib/src/widgets/basic.dart | 35 +- packages/flutter/lib/src/widgets/binding.dart | 6 +- .../widgets/bottom_navigation_bar_item.dart | 15 + packages/flutter/lib/src/widgets/debug.dart | 15 +- .../widgets/default_text_editing_actions.dart | 326 ++ .../default_text_editing_shortcuts.dart | 584 +-- .../flutter/lib/src/widgets/drag_target.dart | 6 +- .../widgets/draggable_scrollable_sheet.dart | 269 +- .../lib/src/widgets/editable_text.dart | 1159 ++---- .../lib/src/widgets/focus_manager.dart | 134 +- .../flutter/lib/src/widgets/focus_scope.dart | 57 +- .../lib/src/widgets/focus_traversal.dart | 88 +- .../flutter/lib/src/widgets/framework.dart | 391 +-- .../lib/src/widgets/gesture_detector.dart | 2 - packages/flutter/lib/src/widgets/icon.dart | 2 +- packages/flutter/lib/src/widgets/image.dart | 13 +- .../lib/src/widgets/implicit_animations.dart | 4 +- .../lib/src/widgets/interactive_viewer.dart | 25 +- .../lib/src/widgets/layout_builder.dart | 14 +- .../src/widgets/list_wheel_scroll_view.dart | 32 +- .../lib/src/widgets/localizations.dart | 2 +- .../flutter/lib/src/widgets/media_query.dart | 32 +- .../lib/src/widgets/modal_barrier.dart | 35 +- .../flutter/lib/src/widgets/navigator.dart | 119 +- .../lib/src/widgets/nested_scroll_view.dart | 25 +- packages/flutter/lib/src/widgets/overlay.dart | 2 +- .../lib/src/widgets/overscroll_indicator.dart | 13 - .../flutter/lib/src/widgets/placeholder.dart | 11 - .../lib/src/widgets/reorderable_list.dart | 230 +- .../flutter/lib/src/widgets/restoration.dart | 2 +- packages/flutter/lib/src/widgets/router.dart | 8 +- packages/flutter/lib/src/widgets/routes.dart | 15 +- .../lib/src/widgets/scroll_controller.dart | 2 +- .../widgets/scroll_notification_observer.dart | 10 +- .../lib/src/widgets/scroll_physics.dart | 28 +- .../scroll_position_with_single_context.dart | 3 - .../flutter/lib/src/widgets/scroll_view.dart | 2 - .../flutter/lib/src/widgets/scrollbar.dart | 75 +- .../lib/src/widgets/shared_app_data.dart | 2 +- .../flutter/lib/src/widgets/shortcuts.dart | 35 +- .../src/widgets/single_child_scroll_view.dart | 2 +- packages/flutter/lib/src/widgets/sliver.dart | 2 +- .../flutter/lib/src/widgets/sliver_fill.dart | 2 +- .../widgets/slotted_render_object_widget.dart | 271 -- packages/flutter/lib/src/widgets/text.dart | 6 +- .../lib/src/widgets/text_editing_action.dart | 48 + .../widgets/text_editing_action_target.dart | 1572 +++++++++ .../lib/src/widgets/text_editing_intents.dart | 461 +-- .../lib/src/widgets/text_selection.dart | 125 +- .../lib/src/widgets/ticker_provider.dart | 164 +- .../flutter/lib/src/widgets/viewport.dart | 50 +- .../lib/src/widgets/widget_inspector.dart | 24 +- .../lib/src/widgets/will_pop_scope.dart | 23 +- packages/flutter/lib/widgets.dart | 4 +- packages/flutter/pubspec.yaml | 11 +- .../cupertino/activity_indicator_test.dart | 26 - .../test/cupertino/bottom_tab_bar_test.dart | 45 +- .../cupertino/context_menu_action_test.dart | 62 +- .../test/cupertino/context_menu_test.dart | 67 +- .../flutter/test/cupertino/picker_test.dart | 2 - .../flutter/test/cupertino/refresh_test.dart | 1 - .../flutter/test/cupertino/route_test.dart | 165 - .../test/cupertino/scrollbar_test.dart | 2 - .../flutter/test/cupertino/switch_test.dart | 4 - .../test/cupertino/text_field_test.dart | 259 +- .../test/foundation/diagnostics_test.dart | 4 +- packages/flutter/test/gestures/tap_test.dart | 78 - .../flutter/test/material/about_test.dart | 5 +- .../flutter/test/material/app_bar_test.dart | 10 +- .../material/bottom_navigation_bar_test.dart | 130 +- .../test/material/bottom_sheet_test.dart | 233 -- .../material/calendar_date_picker_test.dart | 13 +- .../material/checkbox_list_tile_test.dart | 39 - .../flutter/test/material/checkbox_test.dart | 1 - packages/flutter/test/material/chip_test.dart | 181 +- .../test/material/chip_theme_test.dart | 376 +- .../test/material/circle_avatar_test.dart | 1 + .../test/material/color_scheme_test.dart | 277 +- .../test/material/data_table_test.dart | 126 +- .../flutter/test/material/debug_test.dart | 2 + .../flutter/test/material/dropdown_test.dart | 95 - .../test/material/elevated_button_test.dart | 79 - .../material/flexible_space_bar_test.dart | 197 -- .../material/floating_action_button_test.dart | 340 +- .../floating_action_button_theme_test.dart | 22 - .../test/material/icon_button_test.dart | 117 +- .../flutter/test/material/icons_test.dart | 21 - .../flutter/test/material/ink_well_test.dart | 54 - .../test/material/input_decorator_test.dart | 365 -- .../flutter/test/material/list_tile_test.dart | 5 - .../test/material/navigation_rail_test.dart | 191 - .../material/navigation_rail_theme_test.dart | 30 +- .../test/material/outlined_button_test.dart | 79 - .../material/paginated_data_table_test.dart | 18 +- .../test/material/popup_menu_test.dart | 66 - .../test/material/popup_menu_theme_test.dart | 65 +- .../material/progress_indicator_test.dart | 28 - .../flutter/test/material/scrollbar_test.dart | 63 +- .../test/material/scrollbar_theme_test.dart | 48 - .../flutter/test/material/search_test.dart | 15 +- .../flutter/test/material/slider_test.dart | 338 +- .../test/material/slider_theme_test.dart | 18 - .../test/material/switch_list_tile_test.dart | 8 +- .../flutter/test/material/switch_test.dart | 12 +- .../test/material/tab_bar_theme_test.dart | 15 - packages/flutter/test/material/tabs_test.dart | 483 +-- .../test/material/text_button_test.dart | 78 - .../test/material/text_field_test.dart | 755 +--- .../test/material/text_form_field_test.dart | 92 +- .../test/material/text_theme_test.dart | 230 +- .../test/material/theme_data_test.dart | 227 +- .../flutter/test/material/theme_test.dart | 26 +- .../test/material/toggle_buttons_test.dart | 90 - .../flutter/test/material/tooltip_test.dart | 4 +- .../test/material/typography_test.dart | 194 +- .../flutter/test/material/will_pop_test.dart | 87 +- .../image_provider_network_image_test.dart | 2 +- .../test/painting/image_stream_test.dart | 67 +- .../flutter/test/rendering/editable_test.dart | 4 +- .../test/rendering/first_frame_test.dart | 1 - .../flutter/test/rendering/layers_test.dart | 71 +- .../flutter/test/rendering/mock_canvas.dart | 27 +- .../test/rendering/mock_canvas_test.dart | 246 -- .../rendering/mouse_tracker_cursor_test.dart | 4 +- .../flutter/test/rendering/object_test.dart | 103 - .../test/rendering/recording_canvas.dart | 5 +- .../test/rendering/rendering_tester.dart | 32 +- .../sliver_fixed_extent_layout_test.dart | 8 +- .../flutter/test/rendering/viewport_test.dart | 4 +- .../default_binary_messenger_test.dart | 1 - .../services/deferred_component_test.dart | 2 - .../test/services/haptic_feedback_test.dart | 2 - .../test/services/raw_keyboard_test.dart | 259 +- .../test/services/restoration_test.dart | 1 - .../test/services/system_chrome_test.dart | 8 - .../test/services/system_navigator_test.dart | 2 - .../test/services/system_sound_test.dart | 1 - .../test/services/text_input_test.dart | 104 - ...m_channel_without_initialization_test.dart | 24 - .../flutter/test/widgets/actions_test.dart | 78 +- packages/flutter/test/widgets/app_test.dart | 24 - .../flutter/test/widgets/app_title_test.dart | 13 +- packages/flutter/test/widgets/async_test.dart | 14 - .../flutter/test/widgets/clipboard_utils.dart | 1 - .../widgets/composited_transform_test.dart | 18 - .../test/widgets/custom_scroll_view_test.dart | 75 - .../default_text_editing_actions_test.dart | 118 + .../draggable_scrollable_sheet_test.dart | 501 +-- .../flutter/test/widgets/draggable_test.dart | 1 - .../editable_text_shortcuts_tests.dart | 1800 ---------- .../editable_text_show_on_screen_test.dart | 3 +- .../test/widgets/editable_text_test.dart | 1165 +----- .../test/widgets/focus_manager_test.dart | 70 - .../test/widgets/focus_scope_test.dart | 90 - .../test/widgets/focus_traversal_test.dart | 133 - .../flutter/test/widgets/framework_test.dart | 15 - .../widgets/image_filter_quality_test.dart | 2 + packages/flutter/test/widgets/image_test.dart | 17 - .../test/widgets/interactive_viewer_test.dart | 80 - .../flutter/test/widgets/keep_alive_test.dart | 41 +- .../widgets/list_wheel_scroll_view_test.dart | 64 - .../flutter/test/widgets/listener_test.dart | 3 +- .../test/widgets/media_query_test.dart | 67 +- .../test/widgets/modal_barrier_test.dart | 68 +- .../test/widgets/mouse_region_test.dart | 1 - .../flutter/test/widgets/navigator_test.dart | 107 - .../test/widgets/nested_scroll_view_test.dart | 62 - .../flutter/test/widgets/page_view_test.dart | 27 - ...range_maintaining_scroll_physics_test.dart | 78 +- .../test/widgets/reorderable_list_test.dart | 53 +- .../route_notification_messages_test.dart | 5 - .../flutter/test/widgets/router_test.dart | 1 - .../test/widgets/scroll_activity_test.dart | 18 +- .../flutter/test/widgets/scrollbar_test.dart | 118 - .../test/widgets/selectable_text_test.dart | 161 +- .../test/widgets/semantics_tester.dart | 2 +- .../flutter/test/widgets/shortcuts_test.dart | 78 +- .../slotted_render_object_widget_test.dart | 290 -- .../text_editing_action_target_test.dart | 1951 ++++++++++ .../test/widgets/text_selection_test.dart | 17 +- .../test/widgets/ticker_mode_test.dart | 168 +- packages/flutter/test/widgets/title_test.dart | 1 - .../flutter/test/widgets/transform_test.dart | 135 - packages/flutter/test_fixes/material.dart | 21 - .../flutter/test_fixes/material.dart.expect | 21 - packages/flutter/test_private/pubspec.yaml | 6 +- .../flutter/test_private/test/pubspec.yaml | 9 +- packages/flutter/test_profile/README.md | 3 - packages/flutter/test_profile/basic_test.dart | 14 - .../test_release/diagnostics_test.dart | 2 +- .../lib/src/driver/gc_summarizer.dart | 59 - .../lib/src/driver/timeline_summary.dart | 5 - .../lib/src/extension/extension.dart | 11 +- packages/flutter_driver/pubspec.yaml | 26 +- .../src/real_tests/timeline_summary_test.dart | 71 +- .../flutter_goldens/lib/flutter_goldens.dart | 15 +- packages/flutter_goldens/pubspec.yaml | 9 +- .../test/flutter_goldens_test.dart | 257 +- .../lib/skia_client.dart | 51 +- packages/flutter_goldens_client/pubspec.yaml | 6 +- .../lib/src/l10n/cupertino_uk.arb | 2 +- .../generated_cupertino_localizations.dart | 2 +- .../generated_material_localizations.dart | 15 +- .../lib/src/l10n/material_kk.arb | 6 +- .../lib/src/l10n/material_nl.arb | 4 +- .../lib/src/l10n/material_pt.arb | 2 +- packages/flutter_localizations/pubspec.yaml | 7 +- .../test/basics_test.dart | 6 +- .../test/material/date_picker_test.dart | 2 +- .../test/material/date_time_test.dart | 17 +- .../test/override_test.dart | 10 +- .../flutter_localizations/test/text_test.dart | 8 +- .../flutter_test/lib/src/accessibility.dart | 8 +- packages/flutter_test/lib/src/binding.dart | 9 - .../lib/src/event_simulation.dart | 6 +- .../lib/src/frame_timing_summarizer.dart | 17 +- packages/flutter_test/lib/src/goldens.dart | 4 +- packages/flutter_test/lib/src/window.dart | 15 - packages/flutter_test/pubspec.yaml | 7 +- .../flutter_test/test/accessibility_test.dart | 53 - .../test/frame_timing_summarizer_test.dart | 176 +- .../flutter_test/test/live_binding_test.dart | 6 - .../flutter_test/test/widget_tester_test.dart | 3 + packages/flutter_test/test/window_test.dart | 8 +- .../bin/fuchsia_asset_builder.dart | 6 +- .../flutter_tools/bin/fuchsia_tester.dart | 2 +- packages/flutter_tools/bin/podhelper.rb | 3 +- packages/flutter_tools/bin/xcode_backend.dart | 1 - .../gradle/app_plugin_loader.gradle | 6 - packages/flutter_tools/gradle/flutter.gradle | 48 +- .../gradle/module_plugin_loader.gradle | 6 - packages/flutter_tools/lib/executable.dart | 2 +- packages/flutter_tools/lib/runner.dart | 31 +- .../lib/src/android/android_device.dart | 28 +- .../lib/src/android/android_emulator.dart | 49 +- .../lib/src/android/android_sdk.dart | 4 +- .../lib/src/android/android_studio.dart | 2 +- .../lib/src/android/application_package.dart | 19 +- ...eferred_components_prebuild_validator.dart | 2 +- .../lib/src/android/gradle_errors.dart | 126 +- .../lib/src/android/gradle_utils.dart | 22 +- .../lib/src/application_package.dart | 17 +- packages/flutter_tools/lib/src/artifacts.dart | 2 +- .../flutter_tools/lib/src/base/common.dart | 2 +- .../lib/src/base/error_handling_io.dart | 8 +- .../flutter_tools/lib/src/base/logger.dart | 368 +- packages/flutter_tools/lib/src/base/os.dart | 27 +- .../lib/src/base/task_queue.dart | 2 +- .../lib/src/base/user_messages.dart | 1 - .../flutter_tools/lib/src/build_info.dart | 4 +- .../lib/src/build_system/targets/android.dart | 2 +- .../lib/src/build_system/targets/common.dart | 2 +- .../targets/deferred_components.dart | 18 +- .../lib/src/build_system/targets/ios.dart | 74 +- .../lib/src/build_system/targets/linux.dart | 13 +- .../lib/src/build_system/targets/macos.dart | 39 +- .../lib/src/build_system/targets/web.dart | 60 +- .../lib/src/build_system/targets/windows.dart | 23 +- packages/flutter_tools/lib/src/bundle.dart | 2 +- .../flutter_tools/lib/src/bundle_builder.dart | 6 +- packages/flutter_tools/lib/src/cache.dart | 142 +- .../lib/src/commands/analyze.dart | 32 +- .../lib/src/commands/analyze_base.dart | 66 +- .../src/commands/analyze_continuously.dart | 45 +- .../lib/src/commands/analyze_once.dart | 27 +- .../lib/src/commands/assemble.dart | 73 +- .../lib/src/commands/attach.dart | 9 +- .../flutter_tools/lib/src/commands/build.dart | 9 +- .../lib/src/commands/build_aar.dart | 23 +- .../lib/src/commands/build_apk.dart | 13 +- .../lib/src/commands/build_appbundle.dart | 26 +- .../lib/src/commands/build_bundle.dart | 21 +- .../lib/src/commands/build_fuchsia.dart | 14 +- .../lib/src/commands/build_ios.dart | 84 +- .../lib/src/commands/build_ios_framework.dart | 60 +- .../lib/src/commands/build_linux.dart | 15 +- .../lib/src/commands/build_macos.dart | 10 +- .../lib/src/commands/build_web.dart | 23 +- .../lib/src/commands/build_windows.dart | 10 +- .../lib/src/commands/build_winuwp.dart | 10 +- .../lib/src/commands/channel.dart | 16 +- .../flutter_tools/lib/src/commands/clean.dart | 15 +- .../lib/src/commands/config.dart | 68 +- .../lib/src/commands/create.dart | 98 +- .../lib/src/commands/create_base.dart | 72 +- .../lib/src/commands/daemon.dart | 228 +- .../lib/src/commands/debug_adapter.dart | 7 +- .../lib/src/commands/devices.dart | 21 +- .../lib/src/commands/doctor.dart | 17 +- .../lib/src/commands/downgrade.dart | 77 +- .../flutter_tools/lib/src/commands/drive.dart | 2 +- .../lib/src/commands/emulators.dart | 41 +- .../lib/src/commands/format.dart | 16 +- .../lib/src/commands/generate.dart | 4 +- .../src/commands/generate_localizations.dart | 30 +- .../lib/src/commands/ide_config.dart | 29 +- .../lib/src/commands/install.dart | 30 +- .../flutter_tools/lib/src/commands/logs.dart | 13 +- .../src/commands/make_host_app_editable.dart | 2 + .../lib/src/commands/packages.dart | 46 +- .../flutter_tools/lib/src/commands/run.dart | 19 +- .../lib/src/commands/screenshot.dart | 38 +- .../lib/src/commands/shell_completion.dart | 15 +- .../lib/src/commands/symbolize.dart | 30 +- .../flutter_tools/lib/src/commands/test.dart | 12 +- .../lib/src/commands/update_packages.dart | 391 +-- .../lib/src/commands/upgrade.dart | 58 +- packages/flutter_tools/lib/src/compile.dart | 5 +- .../flutter_tools/lib/src/context_runner.dart | 3 +- .../lib/src/custom_devices/custom_device.dart | 220 +- packages/flutter_tools/lib/src/daemon.dart | 241 -- packages/flutter_tools/lib/src/dart/pub.dart | 4 +- .../lib/src/debug_adapters/README.md | 23 +- .../src/debug_adapters/flutter_adapter.dart | 66 +- .../debug_adapters/flutter_adapter_args.dart | 24 - .../debug_adapters/flutter_test_adapter.dart | 30 +- .../flutter_tools/lib/src/desktop_device.dart | 1 + packages/flutter_tools/lib/src/devfs.dart | 10 - packages/flutter_tools/lib/src/device.dart | 15 +- packages/flutter_tools/lib/src/doctor.dart | 63 +- .../lib/src/doctor_validator.dart | 16 +- .../lib/src/drive/web_driver_service.dart | 2 +- packages/flutter_tools/lib/src/emulator.dart | 103 +- .../lib/src/flutter_application_package.dart | 23 +- .../flutter_tools/lib/src/flutter_cache.dart | 2 +- .../lib/src/flutter_device_manager.dart | 44 +- .../lib/src/flutter_manifest.dart | 6 +- .../lib/src/flutter_plugins.dart | 18 +- .../lib/src/fuchsia/application_package.dart | 20 +- .../lib/src/fuchsia/fuchsia_build.dart | 40 +- .../lib/src/fuchsia/fuchsia_device.dart | 183 +- .../src/fuchsia/fuchsia_kernel_compiler.dart | 2 +- .../lib/src/fuchsia/fuchsia_pm.dart | 8 +- .../lib/src/fuchsia/fuchsia_sdk.dart | 6 +- .../flutter_tools/lib/src/fuchsia/pkgctl.dart | 2 + .../lib/src/fuchsia/session_control.dart | 2 + .../lib/src/fuchsia/tiles_ctl.dart | 18 +- packages/flutter_tools/lib/src/globals.dart | 280 +- .../lib/src/globals_null_migrated.dart | 238 ++ .../lib/src/http_host_validator.dart | 126 - .../lib/src/intellij/intellij_validator.dart | 4 +- .../lib/src/ios/application_package.dart | 40 +- .../flutter_tools/lib/src/ios/bitcode.dart | 4 +- .../flutter_tools/lib/src/ios/devices.dart | 2 +- .../lib/src/ios/ios_emulators.dart | 15 +- packages/flutter_tools/lib/src/ios/mac.dart | 198 +- .../lib/src/ios/plist_parser.dart | 112 +- .../flutter_tools/lib/src/ios/simulators.dart | 5 +- .../lib/src/ios/xcode_build_settings.dart | 2 +- .../flutter_tools/lib/src/ios/xcresult.dart | 217 +- .../lib/src/isolated/devfs_web.dart | 55 +- .../lib/src/linux/application_package.dart | 2 +- .../lib/src/linux/build_linux.dart | 9 +- .../lib/src/linux/linux_device.dart | 48 +- .../lib/src/localizations/gen_l10n.dart | 128 +- .../lib/src/macos/application_package.dart | 42 +- .../lib/src/macos/build_macos.dart | 4 +- .../lib/src/macos/cocoapod_utils.dart | 2 +- .../lib/src/macos/cocoapods.dart | 19 +- .../lib/src/macos/macos_ipad_device.dart | 43 +- .../flutter_tools/lib/src/macos/xcdevice.dart | 4 +- .../flutter_tools/lib/src/macos/xcode.dart | 4 +- .../flutter_tools/lib/src/mdns_discovery.dart | 2 +- packages/flutter_tools/lib/src/project.dart | 131 +- .../lib/src/proxy_validator.dart | 20 +- .../lib/src/reporting/crash_reporting.dart | 5 +- .../lib/src/reporting/github_template.dart | 5 +- .../lib/src/reporting/reporting.dart | 2 +- .../lib/src/resident_devtools_handler.dart | 17 +- .../lib/src/resident_runner.dart | 10 +- packages/flutter_tools/lib/src/run_cold.dart | 6 +- packages/flutter_tools/lib/src/run_hot.dart | 18 +- .../lib/src/runner/flutter_command.dart | 304 +- .../src/runner/flutter_command_runner.dart | 57 +- .../flutter_tools/lib/src/sksl_writer.dart | 2 +- packages/flutter_tools/lib/src/template.dart | 4 +- .../lib/src/test/coverage_collector.dart | 2 +- .../lib/src/test/flutter_platform.dart | 3 +- .../lib/src/test/flutter_web_platform.dart | 4 + .../lib/src/test/font_config_manager.dart | 2 +- .../lib/src/test/integration_test_device.dart | 44 +- .../flutter_tools/lib/src/test/runner.dart | 2 +- .../lib/src/test/test_compiler.dart | 2 +- .../lib/src/tester/flutter_tester.dart | 3 + packages/flutter_tools/lib/src/tracing.dart | 57 +- packages/flutter_tools/lib/src/version.dart | 259 +- packages/flutter_tools/lib/src/vmservice.dart | 8 +- .../flutter_tools/lib/src/web/chrome.dart | 10 +- .../flutter_tools/lib/src/web/compile.dart | 15 +- .../lib/src/windows/application_package.dart | 2 +- .../lib/src/windows/build_windows.dart | 92 +- .../lib/src/windows/visual_studio.dart | 13 - .../lib/src/windows/windows_device.dart | 99 +- .../flutter_tools/lib/src/xcode_project.dart | 10 +- packages/flutter_tools/pubspec.yaml | 34 +- .../android-java.tmpl/app/build.gradle.tmpl | 1 - .../build.gradle} | 4 +- .../build.gradle} | 4 +- .../gradle/wrapper/gradle-wrapper.properties | 0 .../wrapper/gradle-wrapper.properties.tmpl | 6 - .../ios.tmpl/Runner/Info.plist.tmpl | 2 +- .../app_shared/linux.tmpl/CMakeLists.txt.tmpl | 30 +- .../linux.tmpl/flutter/CMakeLists.txt | 1 - .../macos.tmpl/Runner/Base.lproj/MainMenu.xib | 4 - .../templates/app_shared/web/index.html.tmpl | 2 +- .../windows.tmpl/CMakeLists.txt.tmpl | 20 +- .../windows.tmpl/flutter/CMakeLists.txt | 1 - .../windows.tmpl/runner/CMakeLists.txt | 15 - .../windows.tmpl/runner/Runner.rc.tmpl | 2 +- .../winuwp.tmpl/CMakeLists.txt.tmpl | 17 +- .../winuwp.tmpl/flutter/CMakeLists.txt | 1 - .../runner_uwp/CMakeLists.txt.tmpl | 14 - .../deferred_component/build.gradle.tmpl | 4 +- ...ild.gradle.tmpl => build.gradle.copy.tmpl} | 2 +- .../app.tmpl/build.gradle.tmpl | 4 +- .../Runner.tmpl/Info.plist.tmpl | 2 +- .../library/Flutter.tmpl/podhelper.rb.tmpl | 3 +- .../android-java.tmpl/build.gradle.tmpl | 2 +- .../android-kotlin.tmpl/build.gradle.tmpl | 6 +- .../plugin/linux.tmpl/CMakeLists.txt.tmpl | 26 +- .../plugin/windows.tmpl/CMakeLists.txt.tmpl | 25 +- .../templates/template_manifest.json | 8 +- .../hermetic/analyze_continuously_test.dart | 87 +- .../hermetic/assemble_test.dart | 2 +- .../commands.shard/hermetic/attach_test.dart | 28 +- .../hermetic/build_ios_test.dart | 279 +- .../hermetic/build_ipa_test.dart | 183 +- .../hermetic/build_linux_test.dart | 6 +- .../hermetic/build_macos_test.dart | 2 +- .../commands.shard/hermetic/build_test.dart | 122 +- .../hermetic/build_web_test.dart | 1 + .../hermetic/build_windows_test.dart | 90 +- .../commands.shard/hermetic/config_test.dart | 2 +- .../hermetic/create_usage_test.dart | 2 +- .../commands.shard/hermetic/daemon_test.dart | 259 +- .../commands.shard/hermetic/devices_test.dart | 2 +- .../commands.shard/hermetic/doctor_test.dart | 113 +- .../hermetic/http_host_validator_test.dart | 266 -- .../hermetic/ide_config_test.dart | 2 +- .../hermetic/proxy_validator_test.dart | 178 +- .../commands.shard/hermetic/run_test.dart | 185 +- .../hermetic/shell_completion_test.dart | 2 +- .../commands.shard/hermetic/test_test.dart | 83 +- .../hermetic/update_packages_test.dart | 210 -- .../permeable/build_aar_test.dart | 63 +- .../permeable/build_apk_test.dart | 2 +- .../permeable/build_appbundle_test.dart | 2 +- .../permeable/build_bundle_test.dart | 23 +- .../commands.shard/permeable/create_test.dart | 90 +- .../commands.shard/permeable/format_test.dart | 2 +- .../permeable/packages_test.dart | 2 +- .../permeable/upgrade_test.dart | 2 +- .../test/general.shard/analytics_test.dart | 6 +- .../android/android_device_start_test.dart | 8 +- .../android/android_emulator_test.dart | 26 +- .../android/android_install_test.dart | 16 +- .../android/android_sdk_test.dart | 2 +- .../android/android_studio_test.dart | 2 +- .../android_studio_validator_test.dart | 2 +- .../android/gradle_errors_test.dart | 169 +- .../general.shard/android/gradle_test.dart | 2 +- .../general.shard/android/multidex_test.dart | 2 +- .../application_package_test.dart | 11 +- .../general.shard/artifact_updater_test.dart | 20 +- .../asset_bundle_package_fonts_test.dart | 2 +- .../asset_bundle_package_test.dart | 2 +- .../test/general.shard/asset_bundle_test.dart | 4 +- .../asset_bundle_variant_test.dart | 2 +- .../test/general.shard/asset_test.dart | 2 +- .../test/general.shard/base/logger_test.dart | 203 -- .../test/general.shard/base/os_test.dart | 2 - .../build_system/exceptions_test.dart | 2 +- .../build_system/source_test.dart | 2 +- .../build_system/targets/ios_test.dart | 50 +- .../build_system/targets/web_test.dart | 8 +- .../general.shard/bundle_builder_test.dart | 2 +- .../test/general.shard/cache_test.dart | 37 +- .../test/general.shard/channel_test.dart | 2 +- .../commands/analyze_base_test.dart | 2 + .../general.shard/commands/build_test.dart | 4 +- .../test/general.shard/compile_test.dart | 13 - .../general.shard/crash_reporting_test.dart | 25 +- .../custom_devices/custom_device_test.dart | 54 +- .../test/general.shard/daemon_test.dart | 240 -- .../test/general.shard/dart_plugin_test.dart | 2 +- .../general.shard/desktop_device_test.dart | 48 +- .../test/general.shard/devfs_test.dart | 213 -- .../test/general.shard/emulator_test.dart | 1 + .../general.shard/flutter_validator_test.dart | 7 - .../fuchsia/fuchsia_device_start_test.dart | 2 +- .../fuchsia/fuchsia_device_test.dart | 36 +- .../generate_localizations_test.dart | 137 +- .../general.shard/github_template_test.dart | 3 - .../integration_test_device_test.dart | 31 - .../intellij/intellij_validator_test.dart | 13 +- .../general.shard/ios/code_signing_test.dart | 2 +- .../ios/ios_device_install_test.dart | 45 +- .../ios_device_start_nonprebuilt_test.dart | 3 - .../ios/ios_device_start_prebuilt_test.dart | 18 +- .../test/general.shard/ios/mac_test.dart | 2 +- .../general.shard/ios/simulators_test.dart | 23 +- .../test/general.shard/ios/xcresult_test.dart | 1165 +++++- .../general.shard/ios/xcresult_test_data.dart | 304 -- .../macos/application_package_test.dart | 6 +- .../general.shard/macos/cocoapods_test.dart | 90 +- .../macos/macos_ipad_device_test.dart | 2 +- .../test/general.shard/macos/xcode_test.dart | 10 +- .../macos/xcode_validator_test.dart | 6 +- .../test/general.shard/plugins_test.dart | 155 +- .../test/general.shard/project_test.dart | 46 +- .../general.shard/resident_runner_test.dart | 11 +- .../resident_web_runner_test.dart | 2 +- .../runner/flutter_command_runner_test.dart | 2 +- .../runner/flutter_command_test.dart | 2 +- .../general.shard/runner/runner_test.dart | 21 +- .../test/general.shard/template_test.dart | 93 +- .../test/general.shard/testbed_test.dart | 2 +- .../tester/flutter_tester_test.dart | 1 + .../test/general.shard/tracing_test.dart | 38 +- .../general.shard/update_packages_test.dart | 96 +- .../test/general.shard/version_test.dart | 63 +- .../general.shard/web/devfs_web_test.dart | 23 +- .../web/golden_comparator_process_test.dart | 2 +- .../windows/visual_studio_test.dart | 32 - .../integration.shard/analyze_once_test.dart | 10 +- .../integration.shard/analyze_size_test.dart | 2 + ...lugin_compilesdkversion_mismatch_test.dart | 92 - ...android_plugin_example_app_build_test.dart | 11 +- .../background_isolate_test.dart | 10 +- .../build_ios_config_only_test.dart | 2 + .../test/integration.shard/cache_test.dart | 154 +- .../command_output_test.dart | 6 +- .../coverage_collection_test.dart | 4 +- .../debug_adapter/flutter_adapter_test.dart | 81 - .../debug_adapter/test_adapter_test.dart | 4 +- .../debug_adapter/test_client.dart | 31 +- .../debug_adapter/test_server.dart | 9 +- .../debugger_stepping_test.dart | 10 +- .../deferred_components_test.dart | 6 +- .../expression_evaluation_test.dart | 2 +- .../test/integration.shard/gen_l10n_test.dart | 78 +- .../generated_plugin_registrant_test.dart | 2 +- .../overall_experience_test.dart | 4 +- .../integration.shard/plist_parser_test.dart | 67 +- .../test_data/basic_project.dart | 62 - .../test_data/compile_error_project.dart | 2 + .../test_data/deferred_components_config.dart | 4 +- .../test_data/gen_l10n_project.dart | 11 - .../test_data/multidex_project.dart | 2 +- .../test/integration.shard/test_driver.dart | 11 +- .../test/integration.shard/test_test.dart | 60 +- .../vmservice_integration_test.dart | 39 +- .../integration.shard/xcode_backend_test.dart | 2 +- .../test/src/android_common.dart | 2 +- packages/flutter_tools/test/src/common.dart | 2 +- packages/flutter_tools/test/src/context.dart | 6 +- .../test/src/dap/flutter_adapter_test.dart | 83 - .../src/dap/flutter_test_adapter_test.dart | 90 - .../flutter_tools/test/src/dap/mocks.dart | 106 - .../test/src/fake_process_manager.dart | 18 +- .../test/src/fake_vm_services.dart | 11 +- packages/flutter_tools/test/src/fakes.dart | 20 +- .../test/src/pubspec_schema.dart | 2 +- .../test/src/test_flutter_command_runner.dart | 2 +- packages/flutter_tools/test/src/testbed.dart | 2 +- .../test/web.shard/chrome_test.dart | 12 +- .../test/web.shard/output_web_test.dart | 81 - .../test/web.shard/vm_service_web_test.dart | 2 +- packages/flutter_tools/tool/global_count.dart | 25 +- .../lib/flutter_web_plugins.dart | 1 - .../lib/src/navigation/js_url_strategy.dart | 4 +- .../lib/src/navigation/url_strategy.dart | 123 +- .../src/navigation_common/url_strategy.dart | 130 - .../src/navigation_non_web/url_strategy.dart | 103 - .../flutter_web_plugins/lib/url_strategy.dart | 8 - packages/flutter_web_plugins/pubspec.yaml | 11 +- .../test/navigation/url_strategy_test.dart | 2 + .../pubspec.yaml | 23 +- .../src/runners/ssh_command_runner_test.dart | 4 +- .../integration_test/android/build.gradle | 2 +- .../android/app/src/main/AndroidManifest.xml | 8 +- .../example/android/project-app.lockfile | 11 +- .../android/project-integration_test.lockfile | 11 +- .../integration_test/_extended_test_io.dart | 28 +- .../xcshareddata/xcschemes/Runner.xcscheme | 14 - .../example/ios/RunnerTests/RunnerTests.m | 85 - .../integration_test/example/pubspec.yaml | 23 +- .../ios/integration_test_macos.podspec | 2 +- .../integration_test_macos/pubspec.yaml | 5 +- .../ios/Classes/FLTIntegrationTestRunner.h | 36 - .../ios/Classes/FLTIntegrationTestRunner.m | 77 - .../ios/Classes/IntegrationTestIosTest.h | 58 +- .../ios/Classes/IntegrationTestIosTest.m | 59 +- .../ios/Classes/IntegrationTestPlugin.h | 14 +- .../ios/Classes/IntegrationTestPlugin.m | 17 +- packages/integration_test/pubspec.yaml | 11 +- 1162 files changed, 19857 insertions(+), 47788 deletions(-) delete mode 100644 dev/benchmarks/macrobenchmarks/lib/src/opacity_peephole.dart delete mode 100644 dev/benchmarks/macrobenchmarks/lib/src/web/bench_image_decoding.dart delete mode 100644 dev/benchmarks/macrobenchmarks/test/opacity_peephole_col_of_rows_perf_e2e.dart delete mode 100644 dev/benchmarks/macrobenchmarks/test/opacity_peephole_fade_transition_text_perf_e2e.dart delete mode 100644 dev/benchmarks/macrobenchmarks/test/opacity_peephole_grid_of_opacity_perf_e2e.dart delete mode 100644 dev/benchmarks/macrobenchmarks/test/opacity_peephole_one_rect_perf_e2e.dart delete mode 100644 dev/benchmarks/macrobenchmarks/test/opacity_peephole_opacity_of_grid_perf_e2e.dart delete mode 100644 dev/bots/test/analyze-test-input/root/packages/flutter/lib/bar.dart delete mode 100644 dev/conductor/core/lib/src/context.dart create mode 100644 dev/conductor/core/lib/src/roll_dev.dart create mode 100644 dev/conductor/core/test/roll_dev_test.dart delete mode 100644 dev/devicelab/bin/tasks/opacity_peephole_col_of_rows_perf__e2e_summary.dart delete mode 100644 dev/devicelab/bin/tasks/opacity_peephole_fade_transition_text_perf__e2e_summary.dart delete mode 100644 dev/devicelab/bin/tasks/opacity_peephole_grid_of_opacity_perf__e2e_summary.dart delete mode 100644 dev/devicelab/bin/tasks/opacity_peephole_one_rect_perf__e2e_summary.dart delete mode 100644 dev/devicelab/bin/tasks/opacity_peephole_opacity_of_grid_perf__e2e_summary.dart rename dev/devicelab/bin/tasks/{hot_mode_dev_cycle_ios__benchmark.dart => smoke_catalina_hot_mode_dev_cycle_ios__benchmark.dart} (100%) rename dev/devicelab/bin/tasks/{flutter_gallery_mac__start_up.dart => smoke_catalina_start_up.dart} (100%) create mode 100644 dev/docs/google2ed1af765c529f57.html delete mode 100644 dev/integration_tests/flavors/integration_test/integration_test.dart delete mode 100644 dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile delete mode 100644 dev/manual_tests/android/.gitignore create mode 100644 dev/manual_tests/android/app/src/main/kotlin/com/example/manual_tests/MainActivity.kt delete mode 100644 dev/manual_tests/android/app/src/main/kotlin/dev/flutter/manual_tests/MainActivity.kt delete mode 100644 dev/manual_tests/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 dev/manual_tests/android/app/src/main/res/values-night/styles.xml delete mode 100644 dev/manual_tests/ios/.gitignore delete mode 100644 dev/manual_tests/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 dev/manual_tests/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 dev/manual_tests/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 dev/manual_tests/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 dev/manual_tests/linux/.gitignore delete mode 100644 dev/manual_tests/linux/CMakeLists.txt delete mode 100644 dev/manual_tests/linux/flutter/CMakeLists.txt delete mode 100644 dev/manual_tests/linux/flutter/generated_plugin_registrant.cc delete mode 100644 dev/manual_tests/linux/flutter/generated_plugin_registrant.h delete mode 100644 dev/manual_tests/linux/flutter/generated_plugins.cmake delete mode 100644 dev/manual_tests/linux/main.cc delete mode 100644 dev/manual_tests/linux/my_application.cc delete mode 100644 dev/manual_tests/linux/my_application.h delete mode 100644 dev/manual_tests/web/favicon.png delete mode 100644 dev/manual_tests/web/icons/Icon-192.png delete mode 100644 dev/manual_tests/web/icons/Icon-512.png delete mode 100644 dev/manual_tests/web/icons/Icon-maskable-192.png delete mode 100644 dev/manual_tests/web/icons/Icon-maskable-512.png delete mode 100644 dev/manual_tests/web/manifest.json delete mode 100644 dev/manual_tests/windows/runner/resources/app_icon.ico create mode 100644 dev/manual_tests/windows/runner/run_loop.cpp create mode 100644 dev/manual_tests/windows/runner/run_loop.h delete mode 100644 dev/tools/gen_defaults/README.md delete mode 100644 dev/tools/gen_defaults/bin/gen_defaults.dart delete mode 100644 dev/tools/gen_defaults/data/material-tokens.json delete mode 100644 dev/tools/gen_defaults/lib/fab_template.dart delete mode 100644 dev/tools/gen_defaults/lib/template.dart delete mode 100644 dev/tools/gen_defaults/pubspec.yaml delete mode 100644 dev/tools/gen_defaults/test/gen_defaults_test.dart delete mode 100644 dev/tools/test/update_icons_test.dart delete mode 100644 dev/tracing_tests/android/.gitignore delete mode 100644 dev/tracing_tests/android/app/build.gradle delete mode 100644 dev/tracing_tests/android/app/src/debug/AndroidManifest.xml delete mode 100644 dev/tracing_tests/android/app/src/main/AndroidManifest.xml delete mode 100644 dev/tracing_tests/android/app/src/main/kotlin/com/example/tracing_tests/MainActivity.kt delete mode 100644 dev/tracing_tests/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 dev/tracing_tests/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 dev/tracing_tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 dev/tracing_tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 dev/tracing_tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 dev/tracing_tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 dev/tracing_tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 dev/tracing_tests/android/app/src/main/res/values-night/styles.xml delete mode 100644 dev/tracing_tests/android/app/src/main/res/values/styles.xml delete mode 100644 dev/tracing_tests/android/app/src/profile/AndroidManifest.xml delete mode 100644 dev/tracing_tests/android/build.gradle delete mode 100644 dev/tracing_tests/android/gradle.properties delete mode 100644 dev/tracing_tests/android/settings.gradle delete mode 100644 dev/tracing_tests/lib/control.dart delete mode 100644 dev/tracing_tests/lib/test.dart delete mode 100644 dev/tracing_tests/test/common.dart delete mode 100644 dev/tracing_tests/test/timeline_test.dart delete mode 100644 examples/api/lib/cupertino/button/cupertino_button.0.dart delete mode 100644 examples/api/lib/cupertino/date_picker/cupertino_date_picker.0.dart delete mode 100644 examples/api/lib/material/ink/ink.image_clip.0.dart delete mode 100644 examples/api/lib/material/ink/ink.image_clip.1.dart delete mode 100644 examples/api/lib/material/input_decorator/input_decoration.floating_label_style_error.0.dart delete mode 100644 examples/api/lib/material/input_decorator/input_decoration.label_style_error.0.dart delete mode 100644 examples/api/lib/material/reorderable_list/reorderable_list_view.1.dart delete mode 100644 examples/api/lib/services/mouse_cursor/mouse_cursor.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_alternative.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_alternative_fractions.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_case_sensitive_forms.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_character_variant.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_contextual_alternates.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_denominator.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_fractions.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_historical_forms.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_historical_ligatures.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_lining_figures.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_locale_aware.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_notational_forms.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_numerators.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_oldstyle_figures.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_ordinal_forms.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_proportional_figures.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_scientific_inferiors.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_slashed_zero.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_stylistic_alternates.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_stylistic_set.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_stylistic_set.1.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_subscripts.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_superscripts.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_swash.0.dart delete mode 100644 examples/api/lib/ui/text/font_feature.font_feature_tabular_figures.0.dart delete mode 100644 examples/api/lib/widgets/basic/custom_multi_child_layout.0.dart delete mode 100644 examples/api/lib/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart rename examples/api/lib/widgets/will_pop_scope/{will_pop_scope.0.dart => will_pop_scope.1.dart} (97%) delete mode 100644 examples/api/test/cupertino/button/cupertino_button.0_test.dart delete mode 100644 examples/api/test/cupertino/date_picker/cupertino_date_picker.0_test.dart delete mode 100644 examples/api/test/material/ink/ink.image_clip.0_test.dart delete mode 100644 examples/api/test/material/ink/ink.image_clip.1_test.dart delete mode 100644 examples/api/test/material/input_decorator/input_decoration.floating_label_style_error.0_test.dart delete mode 100644 examples/api/test/material/input_decorator/input_decoration.label_style_error.0_test.dart delete mode 100644 examples/api/test/services/mouse_cursor/mouse_cursor.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_alternative.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_alternative_fractions.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_case_sensitive_forms.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_character_variant.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_contextual_alternates.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_denominator.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_fractions.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_historical_forms.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_historical_ligatures.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_lining_figures.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_locale_aware.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_notational_forms.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_numerators.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_oldstyle_figures.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_ordinal_forms.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_proportional_figures.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_scientific_inferiors.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_slashed_zero.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_stylistic_alternates.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_stylistic_set.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_stylistic_set.1_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_subscripts.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_superscripts.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_swash.0_test.dart delete mode 100644 examples/api/test/ui/text/font_feature.font_feature_tabular_figures.0_test.dart delete mode 100644 examples/api/test/widgets/basic/custom_multi_child_layout.0_test.dart delete mode 100644 examples/api/test/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0_test.dart delete mode 100644 examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart create mode 100644 packages/flutter/lib/src/widgets/default_text_editing_actions.dart delete mode 100644 packages/flutter/lib/src/widgets/slotted_render_object_widget.dart create mode 100644 packages/flutter/lib/src/widgets/text_editing_action.dart create mode 100644 packages/flutter/lib/src/widgets/text_editing_action_target.dart delete mode 100644 packages/flutter/test/rendering/mock_canvas_test.dart delete mode 100644 packages/flutter/test/services/use_platform_channel_without_initialization_test.dart create mode 100644 packages/flutter/test/widgets/default_text_editing_actions_test.dart delete mode 100644 packages/flutter/test/widgets/editable_text_shortcuts_tests.dart delete mode 100644 packages/flutter/test/widgets/slotted_render_object_widget_test.dart create mode 100644 packages/flutter/test/widgets/text_editing_action_target_test.dart delete mode 100644 packages/flutter/test_profile/README.md delete mode 100644 packages/flutter/test_profile/basic_test.dart delete mode 100644 packages/flutter_driver/lib/src/driver/gc_summarizer.dart delete mode 100644 packages/flutter_tools/lib/src/daemon.dart create mode 100644 packages/flutter_tools/lib/src/globals_null_migrated.dart delete mode 100644 packages/flutter_tools/lib/src/http_host_validator.dart rename packages/flutter_tools/templates/app_shared/{android-kotlin.tmpl/build.gradle.tmpl => android-java.tmpl/build.gradle} (69%) rename packages/flutter_tools/templates/app_shared/{android-java.tmpl/build.gradle.tmpl => android-kotlin.tmpl/build.gradle} (81%) rename {dev/tracing_tests/android => packages/flutter_tools/templates/app_shared/android.tmpl}/gradle/wrapper/gradle-wrapper.properties (100%) delete mode 100644 packages/flutter_tools/templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties.tmpl rename packages/flutter_tools/templates/module/android/gradle/{build.gradle.tmpl => build.gradle.copy.tmpl} (81%) delete mode 100644 packages/flutter_tools/test/commands.shard/hermetic/http_host_validator_test.dart delete mode 100644 packages/flutter_tools/test/general.shard/daemon_test.dart delete mode 100644 packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart delete mode 100644 packages/flutter_tools/test/integration.shard/android_plugin_compilesdkversion_mismatch_test.dart delete mode 100644 packages/flutter_tools/test/src/dap/flutter_adapter_test.dart delete mode 100644 packages/flutter_tools/test/src/dap/flutter_test_adapter_test.dart delete mode 100644 packages/flutter_tools/test/src/dap/mocks.dart delete mode 100644 packages/flutter_tools/test/web.shard/output_web_test.dart delete mode 100644 packages/flutter_web_plugins/lib/src/navigation_common/url_strategy.dart delete mode 100644 packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart delete mode 100644 packages/flutter_web_plugins/lib/url_strategy.dart delete mode 100644 packages/integration_test/ios/Classes/FLTIntegrationTestRunner.h delete mode 100644 packages/integration_test/ios/Classes/FLTIntegrationTestRunner.m diff --git a/.ci.yaml b/.ci.yaml index 1b82355267992..8b6f69430c567 100755 --- a/.ci.yaml +++ b/.ci.yaml @@ -399,9 +399,7 @@ targets: {"dependency": "goldctl"}, {"dependency": "clang"}, {"dependency": "cmake"}, - {"dependency": "ninja"}, - {"dependency": "open_jdk"}, - {"dependency": "android_sdk", "version": "version:29.0"} + {"dependency": "ninja"} ] shard: framework_tests subshard: misc @@ -1189,6 +1187,7 @@ targets: - .ci.yaml - name: Linux web_canvaskit_tests_0 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -1209,6 +1208,7 @@ targets: - bin/ - name: Linux web_canvaskit_tests_1 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -1229,6 +1229,7 @@ targets: - bin/ - name: Linux web_canvaskit_tests_2 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -1249,6 +1250,7 @@ targets: - bin/ - name: Linux web_canvaskit_tests_3 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -1269,6 +1271,7 @@ targets: - bin/ - name: Linux web_canvaskit_tests_4 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -1289,6 +1292,7 @@ targets: - bin/ - name: Linux web_canvaskit_tests_5 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -1309,6 +1313,7 @@ targets: - bin/ - name: Linux web_canvaskit_tests_6 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -1329,6 +1334,7 @@ targets: - bin/ - name: Linux web_canvaskit_tests_7_last + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -1400,17 +1406,6 @@ targets: task_name: android_obfuscate_test scheduler: luci - - name: Linux_android android_semantics_integration_test - bringup: true # Flaky https://github.com/flutter/flutter/issues/74522 - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: android_semantics_integration_test - scheduler: luci - - name: Linux_android android_stack_size_test recipe: devicelab/devicelab_drone presubmit: false @@ -1461,16 +1456,6 @@ targets: task_name: backdrop_filter_perf__e2e_summary scheduler: luci - - name: Linux_android backdrop_filter_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: backdrop_filter_perf__timeline_summary - scheduler: luci - - name: Linux_android basic_material_app_android__compile recipe: devicelab/devicelab_drone presubmit: false @@ -1481,16 +1466,6 @@ targets: task_name: basic_material_app_android__compile scheduler: luci - - name: Linux_android channels_integration_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: channels_integration_test - scheduler: luci - - name: Linux_android color_filter_and_fade_perf__e2e_summary recipe: devicelab/devicelab_drone presubmit: false @@ -1501,16 +1476,6 @@ targets: task_name: color_filter_and_fade_perf__e2e_summary scheduler: luci - - name: Linux_android color_filter_and_fade_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: color_filter_and_fade_perf__timeline_summary - scheduler: luci - - name: Linux_android complex_layout_android__compile recipe: devicelab/devicelab_drone presubmit: false @@ -1565,42 +1530,6 @@ targets: ] scheduler: luci - - name: Linux_android complex_layout_scroll_perf__memory - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: complex_layout_scroll_perf__memory - dependencies: >- - [ - {"dependency": "open_jdk", "version": "11"} - ] - caches: >- - [ - {"name": "openjdk", "path": "java11"} - ] - scheduler: luci - - - name: Linux_android complex_layout_scroll_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: complex_layout_scroll_perf__timeline_summary - dependencies: >- - [ - {"dependency": "open_jdk", "version": "11"} - ] - caches: >- - [ - {"name": "openjdk", "path": "java11"} - ] - scheduler: luci - - name: Linux_android complex_layout_semantics_perf recipe: devicelab/devicelab_drone presubmit: false @@ -1619,24 +1548,6 @@ targets: ] scheduler: luci - - name: Linux_android complex_layout__start_up - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: complex_layout__start_up - dependencies: >- - [ - {"dependency": "open_jdk", "version": "11"} - ] - caches: >- - [ - {"name": "openjdk", "path": "java11"} - ] - scheduler: luci - - name: Linux_android cubic_bezier_perf__e2e_summary recipe: devicelab/devicelab_drone presubmit: false @@ -1657,26 +1568,6 @@ targets: task_name: cubic_bezier_perf_sksl_warmup__e2e_summary scheduler: luci - - name: Linux_android cubic_bezier_perf_sksl_warmup__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: cubic_bezier_perf_sksl_warmup__timeline_summary - scheduler: luci - - - name: Linux_android cubic_bezier_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: cubic_bezier_perf__timeline_summary - scheduler: luci - - name: Linux_android cull_opacity_perf__e2e_summary recipe: devicelab/devicelab_drone presubmit: false @@ -1687,16 +1578,6 @@ targets: task_name: cull_opacity_perf__e2e_summary scheduler: luci - - name: Linux_android cull_opacity_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: cull_opacity_perf__timeline_summary - scheduler: luci - - name: Linux_android devtools_profile_start_test recipe: devicelab/devicelab_drone presubmit: false @@ -1707,46 +1588,6 @@ targets: task_name: devtools_profile_start_test scheduler: luci - - name: Linux_android drive_perf_debug_warning - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: drive_perf_debug_warning - scheduler: luci - - - name: Linux_android embedded_android_views_integration_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: embedded_android_views_integration_test - scheduler: luci - - - name: Linux_android external_ui_integration_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: external_ui_integration_test - scheduler: luci - - - name: Linux_android fading_child_animation_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: fading_child_animation_perf__timeline_summary - scheduler: luci - - name: Linux_android fast_scroll_heavy_gridview__memory recipe: devicelab/devicelab_drone presubmit: false @@ -1757,26 +1598,6 @@ targets: task_name: fast_scroll_heavy_gridview__memory scheduler: luci - - name: Linux_android fast_scroll_large_images__memory - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: fast_scroll_large_images__memory - scheduler: luci - - - name: Linux_android flavors_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: flavors_test - scheduler: luci - - name: Linux_android flutter_engine_group_performance recipe: devicelab/devicelab_drone presubmit: false @@ -1788,7 +1609,6 @@ targets: scheduler: luci - name: Linux_android flutter_gallery__back_button_memory - bringup: true # Flaky https://github.com/flutter/flutter/issues/94036 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 @@ -1799,6 +1619,7 @@ targets: scheduler: luci - name: Linux_android flutter_gallery__image_cache_memory + bringup: true # Flaky https://github.com/flutter/flutter/issues/92018 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 @@ -1820,6 +1641,7 @@ targets: - name: Linux_android flutter_gallery__start_up recipe: devicelab/devicelab_drone + bringup: true # Flaky https://github.com/flutter/flutter/issues/91270 presubmit: false timeout: 60 properties: @@ -1830,6 +1652,7 @@ targets: - name: Linux_android flutter_gallery__start_up_delayed recipe: devicelab/devicelab_drone + bringup: true presubmit: false timeout: 60 properties: @@ -1878,16 +1701,6 @@ targets: task_name: flutter_test_performance scheduler: luci - - name: Linux_android flutter_view__start_up - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: flutter_view__start_up - scheduler: luci - - name: Linux_android frame_policy_delay_test_android recipe: devicelab/devicelab_drone presubmit: false @@ -1898,330 +1711,153 @@ targets: task_name: frame_policy_delay_test_android scheduler: luci - - name: Linux_android fullscreen_textfield_perf__timeline_summary + - name: Linux_android hot_mode_dev_cycle_linux__benchmark recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: fullscreen_textfield_perf__timeline_summary + task_name: hot_mode_dev_cycle_linux__benchmark scheduler: luci - - name: Linux_android hello_world__memory + - name: Linux_android image_list_jit_reported_duration recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: hello_world__memory + task_name: image_list_jit_reported_duration scheduler: luci - - name: Linux_android home_scroll_perf__timeline_summary + - name: Linux_android image_list_reported_duration recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: home_scroll_perf__timeline_summary + task_name: image_list_reported_duration scheduler: luci - - name: Linux_android hot_mode_dev_cycle_linux__benchmark + - name: Linux_android large_image_changer_perf_android recipe: devicelab/devicelab_drone + presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: hot_mode_dev_cycle_linux__benchmark - runIf: - - dev/** + task_name: large_image_changer_perf_android scheduler: luci - - name: Linux_android hybrid_android_views_integration_test + - name: Linux_android linux_chrome_dev_mode recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: hybrid_android_views_integration_test + task_name: linux_chrome_dev_mode scheduler: luci - - name: Linux_android image_list_jit_reported_duration + - name: Linux_android multi_widget_construction_perf__e2e_summary recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: image_list_jit_reported_duration + task_name: multi_widget_construction_perf__e2e_summary scheduler: luci - - name: Linux_android imagefiltered_transform_animation_perf__timeline_summary + - name: Linux_android new_gallery__crane_perf recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: imagefiltered_transform_animation_perf__timeline_summary + task_name: new_gallery__crane_perf scheduler: luci - - name: Linux_android image_list_reported_duration + - name: Linux_android picture_cache_perf__e2e_summary recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: image_list_reported_duration + task_name: picture_cache_perf__e2e_summary scheduler: luci - - name: Linux_android integration_ui_driver + - name: Linux_android platform_channels_benchmarks recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: integration_ui_driver + task_name: platform_channels_benchmarks scheduler: luci - - name: Linux_android integration_ui_keyboard_resize + - name: Linux_android platform_views_scroll_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: integration_ui_keyboard_resize + task_name: platform_views_scroll_perf__timeline_summary scheduler: luci - - name: Linux_android integration_ui_screenshot + - name: Linux_android routing_test recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: integration_ui_screenshot + task_name: routing_test scheduler: luci - - name: Linux_android integration_ui_textfield + - name: Linux_android textfield_perf__e2e_summary recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: integration_ui_textfield + task_name: textfield_perf__e2e_summary scheduler: luci - - name: Linux_android large_image_changer_perf_android + - name: Linux_android web_size__compile_test recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","linux"] - task_name: large_image_changer_perf_android + task_name: web_size__compile_test scheduler: luci - - name: Linux_android linux_chrome_dev_mode - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 + - name: Linux android views + recipe: flutter/android_views + presubmit: true properties: + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:29.0"}, + {"dependency": "android_virtual_device", "version": "31"} + ] tags: > - ["devicelab","android","linux"] - task_name: linux_chrome_dev_mode + ["framework","hostonly"] + timeout: 60 scheduler: luci - - name: Linux_android multi_widget_construction_perf__e2e_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: multi_widget_construction_perf__e2e_summary - scheduler: luci - - - name: Linux_android new_gallery__crane_perf - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: new_gallery__crane_perf - scheduler: luci - - - name: Linux_android new_gallery__transition_perf - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: new_gallery__transition_perf - scheduler: luci - - - name: Linux_android picture_cache_perf__e2e_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: picture_cache_perf__e2e_summary - scheduler: luci - - - name: Linux_android picture_cache_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: picture_cache_perf__timeline_summary - scheduler: luci - - - name: Linux_android platform_channels_benchmarks - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: platform_channels_benchmarks - scheduler: luci - - - name: Linux_android platform_channel_sample_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: platform_channel_sample_test - scheduler: luci - - - name: Linux_android platform_interaction_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: platform_interaction_test - scheduler: luci - - - name: Linux_android platform_views_scroll_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: platform_views_scroll_perf__timeline_summary - scheduler: luci - - - name: Linux_android platform_view__start_up - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: platform_view__start_up - scheduler: luci - - - name: Linux_android routing_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: routing_test - scheduler: luci - - - name: Linux_android service_extensions_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: service_extensions_test - scheduler: luci - - - name: Linux_android textfield_perf__e2e_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: textfield_perf__e2e_summary - scheduler: luci - - - name: Linux_android textfield_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: textfield_perf__timeline_summary - scheduler: luci - - - name: Linux_android tiles_scroll_perf__timeline_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: tiles_scroll_perf__timeline_summary - dependencies: >- - [ - {"dependency": "open_jdk", "version": "11"} - ] - caches: >- - [ - {"name": "openjdk", "path": "java11"} - ] - scheduler: luci - - - name: Linux_android web_size__compile_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: web_size__compile_test - scheduler: luci - - - name: Linux android views - recipe: flutter/android_views - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "android_virtual_device", "version": "31"} - ] - tags: > - ["framework","hostonly"] - timeout: 60 - scheduler: luci - - - name: Linux deferred components - recipe: flutter/deferred_components + - name: Linux deferred components + recipe: flutter/deferred_components + bringup: true # Flaky https://github.com/flutter/flutter/issues/90071 properties: dependencies: >- [ @@ -2234,61 +1870,6 @@ targets: timeout: 60 scheduler: luci - - name: Linux_android opacity_peephole_one_rect_perf__e2e_summary - bringup: true # Flaky https://github.com/flutter/flutter/issues/95574 - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: opacity_peephole_one_rect_perf__e2e_summary - scheduler: luci - - - name: Linux_android opacity_peephole_col_of_rows_perf__e2e_summary - bringup: true # Flaky https://github.com/flutter/flutter/issues/96072 - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: opacity_peephole_col_of_rows_perf__e2e_summary - scheduler: luci - - - name: Linux_android opacity_peephole_opacity_of_grid_perf__e2e_summary - bringup: true # Flaky https://github.com/flutter/flutter/issues/95865 - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: opacity_peephole_opacity_of_grid_perf__e2e_summary - scheduler: luci - - - name: Linux_android opacity_peephole_grid_of_opacity_perf__e2e_summary - bringup: true # Flaky https://github.com/flutter/flutter/issues/95859 - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: opacity_peephole_grid_of_opacity_perf__e2e_summary - scheduler: luci - - - name: Linux_android opacity_peephole_fade_transition_text_perf__e2e_summary - bringup: true # Flaky https://github.com/flutter/flutter/issues/95863 - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab","android","linux"] - task_name: opacity_peephole_fade_transition_text_perf__e2e_summary - scheduler: luci - - name: Mac build_aar_module_test recipe: devicelab/devicelab_drone timeout: 60 @@ -2488,9 +2069,7 @@ targets: [ {"dependency": "goldctl"}, {"dependency": "xcode"}, - {"dependency": "gems"}, - {"dependency": "open_jdk"}, - {"dependency": "android_sdk", "version": "version:29.0"} + {"dependency": "gems"} ] shard: framework_tests subshard: misc @@ -2684,7 +2263,6 @@ targets: - .ci.yaml - name: Mac module_test_ios - bringup: true # Flaky https://github.com/flutter/flutter/issues/96075 recipe: devicelab/devicelab_drone bringup: true # Flaky https://github.com/flutter/flutter/issues/93517 timeout: 60 @@ -2903,161 +2481,533 @@ targets: shard: tool_integration_tests subshard: "4_4" tags: > - ["framework","hostonly","shard"] + ["framework","hostonly","shard"] + scheduler: luci + runIf: + - dev/** + - packages/flutter_tools/** + - bin/** + - .ci.yaml + + - name: Mac tool_tests_commands + recipe: flutter/flutter_drone + timeout: 60 + properties: + add_recipes_cq: "true" + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:29.0"}, + {"dependency": "open_jdk"} + ] + shard: tool_tests + subshard: commands + tags: > + ["framework","hostonly","shard"] + scheduler: luci + + - name: Mac tool_tests_general + recipe: flutter/flutter_drone + timeout: 60 + properties: + add_recipes_cq: "true" + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:29.0"}, + {"dependency": "open_jdk"} + ] + shard: tool_tests + subshard: general + tags: > + ["framework","hostonly","shard"] + scheduler: luci + runIf: + - dev/** + - packages/flutter_tools/** + - bin/** + - .ci.yaml + + - name: Mac verify_binaries_codesigned + enabled_branches: + - dev + - beta + - stable + recipe: flutter/flutter + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "xcode"} + ] + tags: > + ["framework","hostonly","shard"] + validation: verify_binaries_codesigned + validation_name: Verify binaries codesigned + scheduler: luci + + - name: Mac web_tool_tests + recipe: flutter/flutter_drone + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:29.0"}, + {"dependency": "chrome_and_driver", "version": "version:84"}, + {"dependency": "open_jdk"}, + {"dependency": "xcode"}, + {"dependency": "goldctl"} + ] + shard: web_tool_tests + subshard: web + tags: > + ["framework","hostonly","shard"] + scheduler: luci + runIf: + - dev/** + - packages/flutter_tools/** + - bin/** + - .ci.yaml + + - name: Mac_android android_semantics_integration_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: android_semantics_integration_test + scheduler: luci + + - name: Mac_android backdrop_filter_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: backdrop_filter_perf__timeline_summary + scheduler: luci + + - name: Mac_android channels_integration_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: channels_integration_test + scheduler: luci + + - name: Mac_android color_filter_and_fade_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: color_filter_and_fade_perf__timeline_summary + scheduler: luci + + - name: Mac_android complex_layout__start_up + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: complex_layout__start_up + dependencies: >- + [ + {"dependency": "open_jdk", "version": "11"} + ] + caches: >- + [ + {"name": "openjdk", "path": "java11"} + ] + scheduler: luci + + - name: Mac_android complex_layout_scroll_perf__memory + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: complex_layout_scroll_perf__memory + dependencies: >- + [ + {"dependency": "open_jdk", "version": "11"} + ] + caches: >- + [ + {"name": "openjdk", "path": "java11"} + ] + scheduler: luci + + - name: Mac_android complex_layout_scroll_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: complex_layout_scroll_perf__timeline_summary + dependencies: >- + [ + {"dependency": "open_jdk", "version": "11"} + ] + caches: >- + [ + {"name": "openjdk", "path": "java11"} + ] + scheduler: luci + + - name: Mac_android cubic_bezier_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: cubic_bezier_perf__timeline_summary + scheduler: luci + + - name: Mac_android cubic_bezier_perf_sksl_warmup__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: cubic_bezier_perf_sksl_warmup__timeline_summary + scheduler: luci + + - name: Mac_android cull_opacity_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: cull_opacity_perf__timeline_summary + scheduler: luci + + - name: Mac_android drive_perf_debug_warning + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: drive_perf_debug_warning + scheduler: luci + + - name: Mac_android embedded_android_views_integration_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: embedded_android_views_integration_test + scheduler: luci + + - name: Mac_android external_ui_integration_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: external_ui_integration_test + scheduler: luci + + - name: Mac_android fading_child_animation_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: fading_child_animation_perf__timeline_summary + scheduler: luci + + - name: Mac_android fast_scroll_large_images__memory + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: fast_scroll_large_images__memory + scheduler: luci + + - name: Mac_android flavors_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: flavors_test + scheduler: luci + + - name: Mac_android flutter_view__start_up + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: flutter_view__start_up + scheduler: luci + + - name: Mac_android fullscreen_textfield_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: fullscreen_textfield_perf__timeline_summary + scheduler: luci + + - name: Mac_android hello_world__memory + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: hello_world__memory + scheduler: luci + + - name: Mac_android hello_world_android__compile + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: hello_world_android__compile + scheduler: luci + + - name: Mac_android home_scroll_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: home_scroll_perf__timeline_summary + scheduler: luci + + - name: Mac_android hot_mode_dev_cycle__benchmark + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: hot_mode_dev_cycle__benchmark + scheduler: luci + + - name: Mac_android hybrid_android_views_integration_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: hybrid_android_views_integration_test + scheduler: luci + + - name: Mac_android imagefiltered_transform_animation_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: imagefiltered_transform_animation_perf__timeline_summary + scheduler: luci + + - name: Mac_android integration_test_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: integration_test_test + scheduler: luci + + - name: Mac_android integration_ui_driver + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: integration_ui_driver + scheduler: luci + + - name: Mac_android integration_ui_frame_number + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: integration_ui_frame_number + scheduler: luci + + - name: Mac_android integration_ui_keyboard_resize + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: integration_ui_keyboard_resize + scheduler: luci + + - name: Mac_android integration_ui_screenshot + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: integration_ui_screenshot scheduler: luci - runIf: - - dev/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - name: Mac tool_tests_commands - recipe: flutter/flutter_drone + - name: Mac_android integration_ui_textfield + recipe: devicelab/devicelab_drone + presubmit: false timeout: 60 properties: - add_recipes_cq: "true" - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "open_jdk"} - ] - shard: tool_tests - subshard: commands tags: > - ["framework","hostonly","shard"] + ["devicelab","android","mac"] + task_name: integration_ui_textfield scheduler: luci - - name: Mac tool_tests_general - recipe: flutter/flutter_drone + - name: Mac_android microbenchmarks + recipe: devicelab/devicelab_drone + presubmit: false timeout: 60 properties: - add_recipes_cq: "true" - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "open_jdk"} - ] - shard: tool_tests - subshard: general tags: > - ["framework","hostonly","shard"] + ["devicelab","android","mac"] + task_name: microbenchmarks scheduler: luci - runIf: - - dev/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - name: Mac verify_binaries_codesigned - enabled_branches: - - dev - - beta - - stable - recipe: flutter/flutter + - name: Mac_android new_gallery__transition_perf + recipe: devicelab/devicelab_drone + presubmit: false timeout: 60 properties: - dependencies: >- - [ - {"dependency": "xcode"} - ] tags: > - ["framework","hostonly","shard"] - validation: verify_binaries_codesigned - validation_name: Verify binaries codesigned + ["devicelab","android","mac"] + task_name: new_gallery__transition_perf scheduler: luci - - name: Mac web_tool_tests - recipe: flutter/flutter_drone + - name: Mac_android picture_cache_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false timeout: 60 properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "chrome_and_driver", "version": "version:84"}, - {"dependency": "open_jdk"}, - {"dependency": "xcode"}, - {"dependency": "goldctl"} - ] - shard: web_tool_tests - subshard: web tags: > - ["framework","hostonly","shard"] + ["devicelab","android","mac"] + task_name: picture_cache_perf__timeline_summary scheduler: luci - runIf: - - dev/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - name: Mac_android hello_world_android__compile + - name: Mac_android platform_channel_sample_test recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","mac"] - task_name: hello_world_android__compile + task_name: platform_channel_sample_test scheduler: luci - - name: Mac_android hot_mode_dev_cycle__benchmark + - name: Mac_android platform_interaction_test recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","mac"] - task_name: hot_mode_dev_cycle__benchmark + task_name: platform_interaction_test scheduler: luci - - name: Mac_android integration_test_test + - name: Mac_android platform_view__start_up recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","mac"] - task_name: integration_test_test + task_name: platform_view__start_up scheduler: luci - - name: Mac_android integration_ui_frame_number + - name: Mac_android run_release_test recipe: devicelab/devicelab_drone + bringup: true # Flaky https://github.com/flutter/flutter/issues/91625 presubmit: false timeout: 60 properties: tags: > ["devicelab","android","mac"] - task_name: integration_ui_frame_number + task_name: run_release_test scheduler: luci - - name: Mac_android microbenchmarks + - name: Mac_android service_extensions_test recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","mac"] - task_name: microbenchmarks + task_name: service_extensions_test scheduler: luci - - name: Mac_android run_release_test + - name: Mac_android smoke_catalina_start_up recipe: devicelab/devicelab_drone - runIf: - - dev/** + presubmit: false timeout: 60 properties: tags: > ["devicelab","android","mac"] - task_name: run_release_test + task_name: smoke_catalina_start_up + scheduler: luci + + - name: Mac_android textfield_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab","android","mac"] + task_name: textfield_perf__timeline_summary scheduler: luci - - name: Mac_android flutter_gallery_mac__start_up + - name: Mac_android tiles_scroll_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","android","mac"] - task_name: flutter_gallery_mac__start_up + task_name: tiles_scroll_perf__timeline_summary + dependencies: >- + [ + {"dependency": "open_jdk", "version": "11"} + ] + caches: >- + [ + {"name": "openjdk", "path": "java11"} + ] scheduler: luci - name: Mac_ios animation_with_microtasks_perf_ios__timeline_summary @@ -3155,7 +3105,6 @@ targets: scheduler: luci - name: Mac_ios cubic_bezier_perf_ios_sksl_warmup__timeline_summary - bringup: true # Flaky https://github.com/flutter/flutter/issues/95867 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 @@ -3227,13 +3176,12 @@ targets: - name: Mac_ios hot_mode_dev_cycle_macos_target__benchmark recipe: devicelab/devicelab_drone + presubmit: false timeout: 60 properties: tags: > ["devicelab","ios","mac"] task_name: hot_mode_dev_cycle_macos_target__benchmark - runIf: - - dev/** scheduler: luci - name: Mac_ios integration_test_test_ios @@ -3288,6 +3236,7 @@ targets: - name: Mac_ios integration_ui_ios_textfield recipe: devicelab/devicelab_drone + bringup: true # Flaky https://github.com/flutter/flutter/issues/91272 presubmit: false timeout: 60 properties: @@ -3367,7 +3316,6 @@ targets: scheduler: luci - name: Mac_ios new_gallery_ios__transition_perf - bringup: true # Flaky https://github.com/flutter/flutter/issues/96401 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 @@ -3418,6 +3366,7 @@ targets: scheduler: luci - name: Mac_ios platform_view_ios__start_up + bringup: true # Flaky https://github.com/flutter/flutter/issues/92422 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 @@ -3457,15 +3406,14 @@ targets: task_name: simple_animation_perf_ios scheduler: luci - - name: Mac_ios hot_mode_dev_cycle_ios__benchmark - bringup: true # Flaky https://github.com/flutter/flutter/issues/95582 + - name: Mac_ios smoke_catalina_hot_mode_dev_cycle_ios__benchmark recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab","ios","mac"] - task_name: hot_mode_dev_cycle_ios__benchmark + task_name: smoke_catalina_hot_mode_dev_cycle_ios__benchmark scheduler: luci - name: Mac_ios tiles_scroll_perf_ios__timeline_summary @@ -3512,6 +3460,7 @@ targets: - name: Mac native_ui_tests_macos recipe: devicelab/devicelab_drone + bringup: true timeout: 60 properties: dependencies: >- @@ -3565,7 +3514,7 @@ targets: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"}, {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} + {"dependency": "vs_build"} ] shard: build_tests subshard: "1_3" @@ -3584,7 +3533,7 @@ targets: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"}, {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} + {"dependency": "vs_build"} ] shard: build_tests subshard: "2_3" @@ -3603,7 +3552,7 @@ targets: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"}, {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} + {"dependency": "vs_build"} ] shard: build_tests subshard: "3_3" @@ -3655,9 +3604,7 @@ targets: dependencies: >- [ {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"}, - {"dependency": "open_jdk"}, - {"dependency": "android_sdk", "version": "version:29.0"} + {"dependency": "vs_build"} ] shard: framework_tests subshard: misc @@ -3780,7 +3727,7 @@ targets: ] dependencies: >- [ - {"dependency": "vs_build", "version": "version:vs2019"} + {"dependency": "vs_build"} ] tags: > ["devicelab","hostonly"] @@ -3914,7 +3861,7 @@ targets: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"}, {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} + {"dependency": "vs_build"} ] shard: tool_integration_tests subshard: "1_5" @@ -3938,7 +3885,7 @@ targets: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"}, {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} + {"dependency": "vs_build"} ] shard: tool_integration_tests subshard: "2_5" @@ -3962,7 +3909,7 @@ targets: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"}, {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} + {"dependency": "vs_build"} ] shard: tool_integration_tests subshard: "3_5" @@ -3986,7 +3933,7 @@ targets: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"}, {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} + {"dependency": "vs_build"} ] shard: tool_integration_tests subshard: "4_5" @@ -4010,7 +3957,7 @@ targets: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"}, {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} + {"dependency": "vs_build"} ] shard: tool_integration_tests subshard: "5_5" @@ -4023,156 +3970,6 @@ targets: - bin/** - .ci.yaml - - name: Windows tool_integration_tests_1_6 - bringup: true # TODO(fujino): https://github.com/flutter/flutter/issues/96544 - recipe: flutter/flutter_drone - timeout: 60 - properties: - add_recipes_cq: "true" - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "chrome_and_driver", "version": "version:84"}, - {"dependency": "open_jdk"}, - {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} - ] - shard: tool_integration_tests - subshard: "1_6" - tags: > - ["framework","hostonly","shard"] - scheduler: luci - runIf: - - dev/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - - name: Windows tool_integration_tests_2_6 - bringup: true # TODO(fujino): https://github.com/flutter/flutter/issues/96544 - recipe: flutter/flutter_drone - timeout: 60 - properties: - add_recipes_cq: "true" - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "chrome_and_driver", "version": "version:84"}, - {"dependency": "open_jdk"}, - {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} - ] - shard: tool_integration_tests - subshard: "2_6" - tags: > - ["framework","hostonly","shard"] - scheduler: luci - runIf: - - dev/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - - name: Windows tool_integration_tests_3_6 - bringup: true # TODO(fujino): https://github.com/flutter/flutter/issues/96544 - recipe: flutter/flutter_drone - timeout: 60 - properties: - add_recipes_cq: "true" - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "chrome_and_driver", "version": "version:84"}, - {"dependency": "open_jdk"}, - {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} - ] - shard: tool_integration_tests - subshard: "3_6" - tags: > - ["framework","hostonly","shard"] - scheduler: luci - runIf: - - dev/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - - name: Windows tool_integration_tests_4_6 - bringup: true # TODO(fujino): https://github.com/flutter/flutter/issues/96544 - recipe: flutter/flutter_drone - timeout: 60 - properties: - add_recipes_cq: "true" - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "chrome_and_driver", "version": "version:84"}, - {"dependency": "open_jdk"}, - {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} - ] - shard: tool_integration_tests - subshard: "4_6" - tags: > - ["framework","hostonly","shard"] - scheduler: luci - runIf: - - dev/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - - name: Windows tool_integration_tests_5_6 - bringup: true # TODO(fujino): https://github.com/flutter/flutter/issues/96544 - recipe: flutter/flutter_drone - timeout: 60 - properties: - add_recipes_cq: "true" - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "chrome_and_driver", "version": "version:84"}, - {"dependency": "open_jdk"}, - {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} - ] - shard: tool_integration_tests - subshard: "5_6" - tags: > - ["framework","hostonly","shard"] - scheduler: luci - runIf: - - dev/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - - name: Windows tool_integration_tests_6_6 - bringup: true # TODO(fujino): https://github.com/flutter/flutter/issues/96544 - recipe: flutter/flutter_drone - timeout: 60 - properties: - add_recipes_cq: "true" - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:29.0"}, - {"dependency": "chrome_and_driver", "version": "version:84"}, - {"dependency": "open_jdk"}, - {"dependency": "goldctl"}, - {"dependency": "vs_build", "version": "version:vs2019"} - ] - shard: tool_integration_tests - subshard: "6_6" - tags: > - ["framework","hostonly","shard"] - scheduler: luci - runIf: - - dev/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - name: Windows tool_tests_commands recipe: flutter/flutter_drone timeout: 60 diff --git a/.github/workflows/no-response.yaml b/.github/workflows/no-response.yaml index 79cae48251e67..d23157d0fbf77 100644 --- a/.github/workflows/no-response.yaml +++ b/.github/workflows/no-response.yaml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.repository == 'flutter/flutter' }} steps: - - uses: godofredoc/no-response@0ce2dc0e63e1c7d2b87752ceed091f6d32c9df09 + - uses: lee-dohm/no-response@9bb0a4b5e6a45046f00353d5de7d90fb8bd773bb with: token: ${{ github.token }} # Comment to post when closing an Issue for lack of response. Set to `false` to disable diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b24b7393fe543..5edbd6089f9fc 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,9 +2,8 @@ # Code of conduct -The Flutter project expects Flutter's contributors to act professionally -and respectfully. Flutter contributors are expected to maintain the safety -and dignity of Flutter's social environments (such as GitHub and Discord). +We expect Flutter's contributors to act professionally and respectfully, and +we expect our social spaces to be safe and dignified environments. Specifically: @@ -14,11 +13,10 @@ Specifically: Should you experience anything that makes you feel unwelcome in Flutter's community, please contact [conduct@flutter.dev](mailto:conduct@flutter.dev) -or, if you prefer, directly contact someone on the project, for instance -[Hixie](mailto:ian@hixie.ch) or [Tim](mailto:timsneath@google.com). - -The Flutter project will not tolerate harassment in Flutter's -community, even outside of Flutter's public communication channels. +or, if you prefer, directly contact someone on the team, for instance +[Hixie](mailto:ian@hixie.ch) or [Tim](mailto:timsneath@google.com). We will +not tolerate harassment from anyone in Flutter's community, even outside +of Flutter's public communication channels. ## Conflict resolution @@ -29,7 +27,7 @@ together, try to understand each other's points of view, and work to find a design that addresses everyone's concerns. This is usually sufficient to resolve issues. If you cannot come to an -agreement, ask for the advice of a more senior member of the project. +agreement, ask for the advice of a more senior member of the team. Be wary of agreement by attrition, where one person argues a point repeatedly until other participants give up in the interests of moving diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b319e4a90bcda..edcb01a933d67 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -97,11 +97,8 @@ presented. which should be used when proposing a new technical design. This is a good practice to do before coding more intricate changes. -[![How to contribute to Flutter](https://img.youtube.com/vi/4yBgOBAOx_A/0.jpg)](https://www.youtube.com/watch?v=4yBgOBAOx_A) - -In addition to the documents, there is a video linked above on **How to contribute to Flutter** -from the [Flutter](https://youtube.com/c/flutterdev) YouTube channel, -there are many pages on [our Wiki](https://github.com/flutter/flutter/wiki/), -and an article [Contributing to Flutter: Getting Started](https://medium.com/@ayushbherwani/contributing-to-flutter-getting-started-a0db68cbcd5b) +In addition to the above, there are many pages on [our +Wiki](https://github.com/flutter/flutter/wiki/) and an article [Contributing to Flutter: +Getting Started](https://medium.com/@ayushbherwani/contributing-to-flutter-getting-started-a0db68cbcd5b) on Medium that may be of interest. For a curated list of pages see the sidebar on the wiki's home page. They are more or less listed in order of importance. diff --git a/TESTOWNERS b/TESTOWNERS index ed5528e9cce23..559100d9dc507 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -61,11 +61,6 @@ /dev/devicelab/bin/tasks/routing_test.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/textfield_perf__e2e_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/web_size__compile_test.dart @yjbanov @flutter/web -/dev/devicelab/bin/tasks/opacity_peephole_col_of_rows_perf__e2e_summary.dart @flar @flutter/engine -/dev/devicelab/bin/tasks/opacity_peephole_grid_of_opacity_perf__e2e_summary.dart @flar @flutter/engine -/dev/devicelab/bin/tasks/opacity_peephole_one_rect_perf__e2e_summary.dart @flar @flutter/engine -/dev/devicelab/bin/tasks/opacity_peephole_opacity_of_grid_perf__e2e_summary.dart @flar @flutter/engine -/dev/devicelab/bin/tasks/opacity_peephole_fade_transition_text_perf__e2e_summary.dart @flar @flutter/engine ## Windows Android DeviceLab tests /dev/devicelab/bin/tasks/basic_material_app_win__compile.dart @zanderso @flutter/tool @@ -93,7 +88,6 @@ /dev/devicelab/bin/tasks/fading_child_animation_perf__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/fast_scroll_large_images__memory.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flavors_test.dart @zanderso @flutter/tool -/dev/devicelab/bin/tasks/flutter_gallery_mac__start_up.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flutter_view__start_up.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/fullscreen_textfield_perf__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hello_world_android__compile.dart @zanderso @flutter/tool @@ -116,6 +110,7 @@ /dev/devicelab/bin/tasks/platform_view__start_up.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/run_release_test.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/service_extensions_test.dart @zanderso @flutter/tool +/dev/devicelab/bin/tasks/smoke_catalina_start_up.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/textfield_perf__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/tiles_scroll_perf__timeline_summary.dart @zanderso @flutter/engine @@ -138,7 +133,6 @@ /dev/devicelab/bin/tasks/flutter_gallery_ios_sksl_warmup__transition_perf.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flutter_view_ios__start_up.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hello_world_ios__compile.dart @zanderso @flutter/engine -/dev/devicelab/bin/tasks/hot_mode_dev_cycle_ios__benchmark.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/hot_mode_dev_cycle_macos_target__benchmark.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/integration_test_test_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/integration_ui_ios_driver.dart @zanderso @flutter/tool @@ -162,6 +156,7 @@ /dev/devicelab/bin/tasks/platform_views_scroll_perf_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/post_backdrop_filter_perf_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/simple_animation_perf_ios.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/smoke_catalina_hot_mode_dev_cycle_ios__benchmark.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/tiles_scroll_perf_ios__timeline_summary.dart @zanderso @flutter/engine ## Mac iOS32 DeviceLab tests diff --git a/analysis_options.yaml b/analysis_options.yaml index 2d4291484e19a..24e9fdbfbefc8 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -65,7 +65,6 @@ linter: - avoid_equals_and_hash_code_on_mutable_classes - avoid_escaping_inner_quotes - avoid_field_initializers_in_const_classes - # - avoid_final_parameters # incompatible with prefer_final_parameters - avoid_function_literals_in_foreach_calls - avoid_implementing_value_types - avoid_init_to_null @@ -102,7 +101,6 @@ linter: - cast_nullable_to_non_nullable # - close_sinks # not reliable enough # - comment_references # blocked on https://github.com/dart-lang/linter/issues/1142 - # - conditional_uri_does_not_exist # not yet tested # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 - control_flow_in_finally # - curly_braces_in_flow_control_structures # not required by flutter style @@ -134,8 +132,6 @@ linter: - no_adjacent_strings_in_list - no_default_cases - no_duplicate_case_values - - no_leading_underscores_for_library_prefixes - # - no_leading_underscores_for_local_identifiers # not yet tested - no_logic_in_create_state # - no_runtimeType_toString # ok in tests; we enable this only in packages/ - non_constant_identifier_names @@ -167,7 +163,7 @@ linter: - prefer_final_fields - prefer_final_in_for_each - prefer_final_locals - # - prefer_final_parameters # we should enable this one day when it can be auto-fixed (https://github.com/dart-lang/linter/issues/3104), see also parameter_assignments + # - prefer_final_parameters # we should enable this one day (see also parameter_assignments) - prefer_for_elements_to_map_fromIterable - prefer_foreach - prefer_function_declarations_over_variables @@ -183,8 +179,8 @@ linter: - prefer_is_not_operator - prefer_iterable_whereType # - prefer_mixin # Has false positives, see https://github.com/dart-lang/linter/issues/3018 - # - prefer_null_aware_method_calls # "call()" is confusing to people new to the language since it's not documented anywhere - prefer_null_aware_operators + # - prefer_null_aware_method_calls # "call()" is confusing to people new to the language since it's not documented anywhere - prefer_relative_imports - prefer_single_quotes - prefer_spread_collections @@ -194,9 +190,7 @@ linter: # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml - recursive_getters # - require_trailing_commas # blocked on https://github.com/dart-lang/sdk/issues/47441 - - secure_pubspec_urls - sized_box_for_whitespace - # - sized_box_shrink_expand # not yet tested - slash_for_doc_comments - sort_child_properties_last - sort_constructors_first @@ -215,7 +209,6 @@ linter: # - unnecessary_final # conflicts with prefer_final_locals - unnecessary_getters_setters # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 - - unnecessary_late - unnecessary_new - unnecessary_null_aware_assignments - unnecessary_null_checks @@ -231,7 +224,6 @@ linter: - unrelated_type_equality_checks - unsafe_html - use_build_context_synchronously - # - use_decorated_box # not yet tested - use_full_hex_values_for_flutter_colors - use_function_type_syntax_for_parameters # - use_if_null_to_convert_nulls_to_bools # blocked on https://github.com/dart-lang/sdk/issues/47436 diff --git a/bin/flutter b/bin/flutter index 591b0107cb329..a6ca46d48ffd5 100755 --- a/bin/flutter +++ b/bin/flutter @@ -13,11 +13,6 @@ set -e -# To debug the tool, you can uncomment the following lines to enable debug -# mode and set an observatory port: -# FLUTTER_TOOL_ARGS="--enable-asserts $FLUTTER_TOOL_ARGS" -# FLUTTER_TOOL_ARGS="$FLUTTER_TOOL_ARGS --observe=65432" - # Needed because if it is set, cd may print the path it changed to. unset CDPATH diff --git a/bin/flutter.bat b/bin/flutter.bat index 06c9a353c9c6b..7c3ba962d6365 100644 --- a/bin/flutter.bat +++ b/bin/flutter.bat @@ -13,9 +13,6 @@ REM -------------------------------------------------------------------------- SETLOCAL ENABLEDELAYEDEXPANSION -REM To debug the tool, you can uncomment the following line to enable debug mode: -REM SET FLUTTER_TOOL_ARGS="--enable-asserts %FLUTTER_TOOL_ARGS%" - FOR %%i IN ("%~dp0..") DO SET FLUTTER_ROOT=%%~fi REM If available, add location of bundled mingit to PATH @@ -43,6 +40,9 @@ SET snapshot_path=%cache_dir%\flutter_tools.snapshot SET dart_sdk_path=%cache_dir%\dart-sdk SET dart=%dart_sdk_path%\bin\dart.exe +REM To debug the tool, you can uncomment the following lines to enable checked mode and set an observatory port: +REM SET FLUTTER_TOOL_ARGS="--enable-asserts %FLUTTER_TOOL_ARGS%" + REM Chaining the call to 'dart' and 'exit' with an ampersand ensures that REM Windows reads both commands into memory once before executing them. This REM avoids nasty errors that may otherwise occur when the dart command (e.g. as diff --git a/bin/internal/canvaskit.version b/bin/internal/canvaskit.version index b21f6ab0be3f1..f0a872ba6ed87 100644 --- a/bin/internal/canvaskit.version +++ b/bin/internal/canvaskit.version @@ -1 +1 @@ -CQJGaIvKwSuYCIi4hxn3jdY-Pcrdkcnnu65ZVt18oW8C +1e8cK_8LOs0dz4lqd20LwTUYNqfu_4YL-dFG5yK1xXQC diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8f699df9c90b9..e4d51ed7cc425 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -83d99a58097b20ac206dce723103a2ca65bdf00d +890a5fca2e34db413be624fc83aeea8e61d42ce6 diff --git a/bin/internal/flutter_plugins.version b/bin/internal/flutter_plugins.version index e6c3d95e496e2..604ca080d206f 100644 --- a/bin/internal/flutter_plugins.version +++ b/bin/internal/flutter_plugins.version @@ -1 +1 @@ -07f48a6034b4f44b80512cf615dcdbe4ecceb238 +e51cc1df7b75ddac344eb8f8835863c7c2f53055 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index fe92ab3f85fe6..96eaa5d2c574c 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -V541xkYVrdUCYfZXqyr7_A0D6vukI4kPqTu5Su7yde0C +tBL8VjITEMr2lN4iUgYcOl_MnOZ7-K0bgCFlF0_XGTEC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index ab2429d336919..884ac3d978a3f 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -bGW3xlB1DoAmVsFugvQ9CfapwZ1zCVXelfK-Op0yFzcC +iK9xdlMLDiH-cDa1f82jz6cNMcMn-DdAP3tCu9xClc0C diff --git a/bin/internal/material_fonts.version b/bin/internal/material_fonts.version index 795d74fba6245..18a9e017d38d0 100644 --- a/bin/internal/material_fonts.version +++ b/bin/internal/material_fonts.version @@ -1 +1 @@ -flutter_infra_release/flutter/fonts/3ebf18904a0b2d50fe311ff41e9e1e4894bc270d/fonts.zip +flutter_infra_release/flutter/fonts/bd151aa3c2f7231344411a01dba4ef61b3cd56b2/fonts.zip diff --git a/bin/internal/shared.bat b/bin/internal/shared.bat index 05cbac1c9fa5b..d4ee4552aa61d 100644 --- a/bin/internal/shared.bat +++ b/bin/internal/shared.bat @@ -69,14 +69,6 @@ GOTO :after_subroutine PUSHD "%flutter_root%" FOR /f %%r IN ('git rev-parse HEAD') DO SET revision=%%r POPD - SET compilekey="%revision%:%FLUTTER_TOOL_ARGS%" - - REM Invalidate cache if: - REM * SNAPSHOT_PATH is not a file, or - REM * STAMP_PATH is not a file, or - REM * STAMP_PATH is an empty file, or - REM * Contents of STAMP_PATH is not what we are going to compile, or - REM * pubspec.yaml last modified after pubspec.lock REM The following IF conditions are all linked with a logical OR. However, REM there is no OR operator in batch and a GOTO construct is used as replacement. @@ -88,7 +80,7 @@ GOTO :after_subroutine IF NOT EXIST "%snapshot_path%" GOTO do_snapshot IF NOT EXIST "%stamp_path%" GOTO do_snapshot SET /P stamp_value=<"%stamp_path%" - IF !stamp_value! NEQ !compilekey! GOTO do_snapshot + IF !stamp_value! NEQ !revision! GOTO do_snapshot SET pubspec_yaml_path=%flutter_tools_dir%\pubspec.yaml SET pubspec_lock_path=%flutter_tools_dir%\pubspec.lock FOR /F %%i IN ('DIR /B /O:D "%pubspec_yaml_path%" "%pubspec_lock_path%"') DO SET newer_file=%%i @@ -172,7 +164,7 @@ GOTO :after_subroutine SET exit_code=%ERRORLEVEL% GOTO :final_exit ) - >"%stamp_path%" ECHO %compilekey% + >"%stamp_path%" ECHO %revision% REM Exit Subroutine EXIT /B diff --git a/bin/internal/shared.sh b/bin/internal/shared.sh index 50ffcd4c28701..05cba4393b1d9 100644 --- a/bin/internal/shared.sh +++ b/bin/internal/shared.sh @@ -17,7 +17,7 @@ set -e # Needed because if it is set, cd may print the path it changed to. unset CDPATH -function pub_upgrade_with_retry { +function retry_upgrade { local total_tries="10" local remaining_tries=$((total_tries - 1)) while [[ "$remaining_tries" -gt 0 ]]; do @@ -115,15 +115,13 @@ function upgrade_flutter () ( mkdir -p "$FLUTTER_ROOT/bin/cache" local revision="$(cd "$FLUTTER_ROOT"; git rev-parse HEAD)" - local compilekey="$revision:$FLUTTER_TOOL_ARGS" # Invalidate cache if: # * SNAPSHOT_PATH is not a file, or - # * STAMP_PATH is not a file, or - # * STAMP_PATH is an empty file, or - # * Contents of STAMP_PATH is not what we are going to compile, or + # * STAMP_PATH is not a file with nonzero size, or + # * Contents of STAMP_PATH is not our local git HEAD revision, or # * pubspec.yaml last modified after pubspec.lock - if [[ ! -f "$SNAPSHOT_PATH" || ! -s "$STAMP_PATH" || "$(cat "$STAMP_PATH")" != "$compilekey" || "$FLUTTER_TOOLS_DIR/pubspec.yaml" -nt "$FLUTTER_TOOLS_DIR/pubspec.lock" ]]; then + if [[ ! -f "$SNAPSHOT_PATH" || ! -s "$STAMP_PATH" || "$(cat "$STAMP_PATH")" != "$revision" || "$FLUTTER_TOOLS_DIR/pubspec.yaml" -nt "$FLUTTER_TOOLS_DIR/pubspec.lock" ]]; then # Waits for the update lock to be acquired. Placing this check inside the # conditional allows the majority of flutter/dart installations to bypass # the lock entirely, but as a result this required a second verification that @@ -131,32 +129,31 @@ function upgrade_flutter () ( _wait_for_lock # A different shell process might have updated the tool/SDK. - if [[ -f "$SNAPSHOT_PATH" && -s "$STAMP_PATH" && "$(cat "$STAMP_PATH")" == "$compilekey" && "$FLUTTER_TOOLS_DIR/pubspec.yaml" -ot "$FLUTTER_TOOLS_DIR/pubspec.lock" ]]; then + if [[ -f "$SNAPSHOT_PATH" && -s "$STAMP_PATH" && "$(cat "$STAMP_PATH")" == "$revision" && "$FLUTTER_TOOLS_DIR/pubspec.yaml" -ot "$FLUTTER_TOOLS_DIR/pubspec.lock" ]]; then exit $? fi - # Fetch Dart... rm -f "$FLUTTER_ROOT/version" touch "$FLUTTER_ROOT/bin/cache/.dartignore" "$FLUTTER_ROOT/bin/internal/update_dart_sdk.sh" + VERBOSITY="--verbosity=error" >&2 echo Building flutter tool... - - # Prepare packages... - VERBOSITY="--verbosity=error" if [[ "$CI" == "true" || "$BOT" == "true" || "$CONTINUOUS_INTEGRATION" == "true" || "$CHROME_HEADLESS" == "1" ]]; then PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_bot" VERBOSITY="--verbosity=normal" fi + export PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_install" + if [[ -d "$FLUTTER_ROOT/.pub-cache" ]]; then export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_ROOT/.pub-cache"}" fi - pub_upgrade_with_retry - # Compile... + retry_upgrade + "$DART" --verbosity=error --disable-dart-dev $FLUTTER_TOOL_ARGS --snapshot="$SNAPSHOT_PATH" --packages="$FLUTTER_TOOLS_DIR/.packages" --no-enable-mirrors "$SCRIPT_PATH" - echo "$compilekey" > "$STAMP_PATH" + echo "$revision" > "$STAMP_PATH" fi # The exit here is extraneous since the function is run in a subshell, but # this serves as documentation that running the function in a subshell is @@ -215,6 +212,11 @@ function shared::execute() { exit 1 fi + # To debug the tool, you can uncomment the following lines to enable checked + # mode and set an observatory port: + # FLUTTER_TOOL_ARGS="--enable-asserts $FLUTTER_TOOL_ARGS" + # FLUTTER_TOOL_ARGS="$FLUTTER_TOOL_ARGS --observe=65432" + upgrade_flutter 7< "$PROG_NAME" BIN_NAME="$(basename "$PROG_NAME")" diff --git a/bin/internal/update_dart_sdk.sh b/bin/internal/update_dart_sdk.sh index 6f07d75997db9..67d9cdc6c9da9 100755 --- a/bin/internal/update_dart_sdk.sh +++ b/bin/internal/update_dart_sdk.sh @@ -116,21 +116,6 @@ if [ ! -f "$ENGINE_STAMP" ] || [ "$ENGINE_VERSION" != `cat "$ENGINE_STAMP"` ]; t fi curl ${verbose_curl} --retry 3 --continue-at - --location --output "$DART_SDK_ZIP" "$DART_SDK_URL" 2>&1 || { - curlExitCode=$? - # Handle range errors specially: retry again with disabled ranges (`--continue-at -` argument) - # When this could happen: - # - missing support of ranges in proxy servers - # - curl with broken handling of completed downloads - # This is not a proper fix, but doesn't require any user input - # - mirror of flutter storage without support of ranges - # - # 33 HTTP range error. The range "command" didn't work. - # https://man7.org/linux/man-pages/man1/curl.1.html#EXIT_CODES - if [ $curlExitCode != 33 ]; then - return $curlExitCode - fi - curl ${verbose_curl} --retry 3 --location --output "$DART_SDK_ZIP" "$DART_SDK_URL" 2>&1 - } || { >&2 echo >&2 echo "Failed to retrieve the Dart SDK from: $DART_SDK_URL" >&2 echo "If you're located in China, please see this page:" @@ -143,7 +128,7 @@ if [ ! -f "$ENGINE_STAMP" ] || [ "$ENGINE_VERSION" != `cat "$ENGINE_STAMP"` ]; t >&2 echo >&2 echo "It appears that the downloaded file is corrupt; please try again." >&2 echo "If this problem persists, please report the problem at:" - >&2 echo " https://github.com/flutter/flutter/issues/new?template=1_activation.md" + >&2 echo " https://github.com/flutter/flutter/issues/new?template=ACTIVATION.md" >&2 echo rm -f -- "$DART_SDK_ZIP" exit 1 diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index ad0fdd3ecc994..21c949240ab6e 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -12,11 +12,11 @@ dependencies: sdk: flutter integration_test: sdk: flutter - platform: 3.1.0 - test: 1.20.1 + platform: 3.0.2 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -35,15 +35,15 @@ dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,11 +58,11 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ flutter: assets: - icon/ -# PUBSPEC CHECKSUM: 1257 +# PUBSPEC CHECKSUM: 60c1 diff --git a/dev/benchmarks/complex_layout/android/app/src/main/AndroidManifest.xml b/dev/benchmarks/complex_layout/android/app/src/main/AndroidManifest.xml index f550d95c2a2b7..8200a24452c57 100644 --- a/dev/benchmarks/complex_layout/android/app/src/main/AndroidManifest.xml +++ b/dev/benchmarks/complex_layout/android/app/src/main/AndroidManifest.xml @@ -7,8 +7,8 @@ found in the LICENSE file. --> - - + - diff --git a/dev/benchmarks/complex_layout/android/project-app.lockfile b/dev/benchmarks/complex_layout/android/project-app.lockfile index 3f551d0cc82b5..61abb33e0ad15 100644 --- a/dev/benchmarks/complex_layout/android/project-app.lockfile +++ b/dev/benchmarks/complex_layout/android/project-app.lockfile @@ -26,8 +26,6 @@ androidx.test:runner:1.2.0=debugAndroidTestCompileClasspath,debugCompileClasspat androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:30.0.0=lintClassPath com.android.tools.analytics-library:shared:30.0.0=lintClassPath com.android.tools.analytics-library:tracker:30.0.0=lintClassPath @@ -141,17 +139,10 @@ org.jacoco:org.jacoco.report:0.8.3=androidJacocoAnt org.jetbrains.intellij.deps:trove4j:1.0.20181211=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.4.32=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.junit.jupiter:junit-jupiter-api:5.7.0=lintClassPath org.junit.jupiter:junit-jupiter-engine:5.7.0=lintClassPath org.junit.platform:junit-platform-commons:1.7.0=lintClassPath diff --git a/dev/benchmarks/complex_layout/android/project-integration_test.lockfile b/dev/benchmarks/complex_layout/android/project-integration_test.lockfile index 8c6d32928f3c8..2708f4c619729 100644 --- a/dev/benchmarks/complex_layout/android/project-integration_test.lockfile +++ b/dev/benchmarks/complex_layout/android/project-integration_test.lockfile @@ -26,8 +26,6 @@ androidx.test:runner:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRunt androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:30.0.0=lintClassPath com.android.tools.analytics-library:shared:30.0.0=lintClassPath com.android.tools.analytics-library:tracker:30.0.0=lintClassPath @@ -140,17 +138,10 @@ org.jacoco:org.jacoco.report:0.8.3=androidJacocoAnt org.jetbrains.intellij.deps:trove4j:1.0.20181211=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.4.32=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.4.32=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.junit.jupiter:junit-jupiter-api:5.7.0=lintClassPath org.junit.jupiter:junit-jupiter-engine:5.7.0=lintClassPath org.junit.platform:junit-platform-commons:1.7.0=lintClassPath diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index a4fd1739108f0..781e964ad21b7 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -16,31 +16,30 @@ dependencies: # flutter update-packages --force-upgrade flutter_gallery_assets: 1.0.2 - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.20.1 + test: 1.17.12 integration_test: sdk: flutter - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -55,11 +54,12 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,8 +72,8 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 2065 +# PUBSPEC CHECKSUM: 18cc diff --git a/dev/benchmarks/complex_layout/test_driver/semantics_perf_test.dart b/dev/benchmarks/complex_layout/test_driver/semantics_perf_test.dart index 491a296f128de..e37603b7a2329 100644 --- a/dev/benchmarks/complex_layout/test_driver/semantics_perf_test.dart +++ b/dev/benchmarks/complex_layout/test_driver/semantics_perf_test.dart @@ -33,9 +33,9 @@ void main() { expect(await driver.setSemantics(true), isTrue); }); - final Iterable? semanticsEvents = timeline.events?.where((TimelineEvent event) => event.name == 'SEMANTICS'); + final Iterable? semanticsEvents = timeline.events?.where((TimelineEvent event) => event.name == 'Semantics'); if (semanticsEvents?.length != 2) - fail('Expected exactly two "SEMANTICS" events, got ${semanticsEvents?.length}:\n$semanticsEvents'); + fail('Expected exactly two semantics events, got ${semanticsEvents?.length}'); final Duration semanticsTreeCreation = Duration(microseconds: semanticsEvents!.last.timestampMicros! - semanticsEvents.first.timestampMicros!); final String jsonEncoded = json.encode({'initialSemanticsTreeCreation': semanticsTreeCreation.inMilliseconds}); diff --git a/dev/benchmarks/macrobenchmarks/android/app/src/main/AndroidManifest.xml b/dev/benchmarks/macrobenchmarks/android/app/src/main/AndroidManifest.xml index c0f2c6be78295..643354e9643ff 100644 --- a/dev/benchmarks/macrobenchmarks/android/app/src/main/AndroidManifest.xml +++ b/dev/benchmarks/macrobenchmarks/android/app/src/main/AndroidManifest.xml @@ -11,13 +11,13 @@ found in the LICENSE file. --> --> - + FlutterApplication and put your custom class here. --> const StackSizePage(), kAnimationWithMicrotasksRouteName: (BuildContext context) => const AnimationWithMicrotasks(), kAnimatedImageRouteName: (BuildContext context) => const AnimatedImagePage(), - kOpacityPeepholeRouteName: (BuildContext context) => const OpacityPeepholePage(), - ...opacityPeepholeRoutes, }, ); } @@ -213,13 +210,6 @@ class HomePage extends StatelessWidget { Navigator.pushNamed(context, kAnimatedImageRouteName); }, ), - ElevatedButton( - key: const Key(kOpacityPeepholeRouteName), - child: const Text('Opacity Peephole tests'), - onPressed: () { - Navigator.pushNamed(context, kOpacityPeepholeRouteName); - }, - ), ], ), ); diff --git a/dev/benchmarks/macrobenchmarks/lib/src/opacity_peephole.dart b/dev/benchmarks/macrobenchmarks/lib/src/opacity_peephole.dart deleted file mode 100644 index 19001375d0be5..0000000000000 --- a/dev/benchmarks/macrobenchmarks/lib/src/opacity_peephole.dart +++ /dev/null @@ -1,332 +0,0 @@ -// 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 'package:flutter/material.dart'; - -import '../common.dart'; - -// Various tests to verify that the Opacity layer propagates the opacity to various -// combinations of children that can apply it themselves. -// See https://github.com/flutter/flutter/issues/75697 -class OpacityPeepholePage extends StatelessWidget { - const OpacityPeepholePage({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Opacity Peephole tests')), - body: ListView( - key: const Key(kOpacityScrollableName), - children: [ - for (OpacityPeepholeCase variant in allOpacityPeepholeCases) - ElevatedButton( - key: Key(variant.route), - child: Text(variant.name), - onPressed: () { - Navigator.pushNamed(context, variant.route); - }, - ) - ], - ), - ); - } -} - -typedef ValueBuilder = Widget Function(double v); -typedef AnimationBuilder = Widget Function(Animation animation); - -double _opacity(double v) => v * 0.5 + 0.25; -int _red(double v) => (v * 255).round(); -int _green(double v) => _red(1 - v); -int _blue(double v) => 0; - -class OpacityPeepholeCase { - OpacityPeepholeCase.forValue({required String route, required String name, required ValueBuilder builder}) - : this.forAnimation( - route: route, - name: name, - builder: (Animation animation) => AnimatedBuilder( - animation: animation, - builder: (BuildContext context, Widget? child) => builder(animation.value), - ), - ); - - OpacityPeepholeCase.forAnimation({required this.route, required this.name, required AnimationBuilder builder}) - : animationBuilder = builder; - - final String route; - final String name; - final AnimationBuilder animationBuilder; - - Widget buildPage(BuildContext context) { - return VariantPage(variant: this); - } -} - -List allOpacityPeepholeCases = [ - // Tests that Opacity can hand down value to a simple child - OpacityPeepholeCase.forValue( - route: kOpacityPeepholeOneRectRouteName, - name: 'One Big Rectangle', - builder: (double v) { - return Opacity( - opacity: _opacity(v), - child: Container( - width: 300, - height: 400, - color: Color.fromARGB(255, _red(v), _green(v), _blue(v)), - ), - ); - } - ), - // Tests that a column of Opacity widgets can individually hand their values down to simple children - OpacityPeepholeCase.forValue( - route: kOpacityPeepholeColumnOfOpacityRouteName, - name: 'Column of Opacity', - builder: (double v) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - for (int i = 0; i < 10; i++, v = 1 - v) - Opacity( - opacity: _opacity(v), - child: Padding( - padding: const EdgeInsets.all(5), - child: Container( - width: 300, - height: 30, - color: Color.fromARGB(255, _red(v), _green(v), _blue(v)), - ), - ), - ), - ], - ); - }, - ), - // Tests that an Opacity can hand value down to a cached child - OpacityPeepholeCase.forValue( - route: kOpacityPeepholeOpacityOfCachedChildRouteName, - name: 'Opacity of Cached Child', - builder: (double v) { - // ChildV starts as a constant so the same color pattern always appears and the child will be cached - double childV = 0; - return Opacity( - opacity: _opacity(v), - child: RepaintBoundary( - child: SizedBox( - width: 300, - height: 400, - child: Stack( - children: [ - for (double i = 0; i < 100; i += 10, childV = 1 - childV) - Positioned.fromRelativeRect( - rect: RelativeRect.fromLTRB(i, i, i, i), - child: Container( - color: Color.fromARGB(255, _red(childV), _green(childV), _blue(childV)), - ), - ), - ], - ), - ), - ), - ); - } - ), - // Tests that an Opacity can hand a value down to a Column of simple non-overlapping children - OpacityPeepholeCase.forValue( - route: kOpacityPeepholeOpacityOfColumnRouteName, - name: 'Opacity of Column', - builder: (double v) { - return Opacity( - opacity: _opacity(v), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - for (int i = 0; i < 10; i++, v = 1 - v) - Padding( - padding: const EdgeInsets.all(5), - // RepaintBoundary here to avoid combining children into 1 big Picture - child: RepaintBoundary( - child: Container( - width: 300, - height: 30, - color: Color.fromARGB(255, _red(v), _green(v), _blue(v)), - ), - ), - ), - ], - ), - ); - }, - ), - // Tests that an entire grid of Opacity objects can hand their values down to their simple children - OpacityPeepholeCase.forValue( - route: kOpacityPeepholeGridOfOpacityRouteName, - name: 'Grid of Opacity', - builder: (double v) { - double rowV = v; - double colV = rowV; - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - for (int i = 0; i < 10; i++, rowV = 1 - rowV, colV = rowV) - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - for (int j = 0; j < 7; j++, colV = 1 - colV) - Opacity( - opacity: _opacity(colV), - child: Padding( - padding: const EdgeInsets.all(5), - child: Container( - width: 30, - height: 30, - color: Color.fromARGB(255, _red(colV), _green(colV), _blue(colV)), - ), - ), - ), - ], - ), - ], - ); - }, - ), - // tests if an Opacity can hand its value down to a 2D grid of simple non-overlapping children. - // The success of this case would depend on the sophistication of the non-overlapping tests. - OpacityPeepholeCase.forValue( - route: kOpacityPeepholeOpacityOfGridRouteName, - name: 'Opacity of Grid', - builder: (double v) { - double rowV = v; - double colV = rowV; - return Opacity( - opacity: _opacity(v), - child: SizedBox( - width: 300, - height: 400, - child: Stack( - children: [ - for (int i = 0; i < 10; i++, rowV = 1 - rowV, colV = rowV) - for (int j = 0; j < 7; j++, colV = 1 - colV) - Positioned.fromRect( - rect: Rect.fromLTWH(j * 40 + 5, i * 40 + 5, 30, 30), - // RepaintBoundary here to avoid combining the 70 children into a single Picture - child: RepaintBoundary( - child: Container( - color: Color.fromARGB(255, _red(colV), _green(colV), _blue(colV)), - ), - ), - ), - ], - ), - ), - ); - }, - ), - // tests if an Opacity can hand its value down to a Column of non-overlapping rows of non-overlapping simple children. - // This test only requires linear non-overlapping tests to succeed. - OpacityPeepholeCase.forValue( - route: kOpacityPeepholeOpacityOfColOfRowsRouteName, - name: 'Opacity of Column of Rows', - builder: (double v) { - double rowV = v; - double colV = v; - return Opacity( - opacity: _opacity(v), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - for (int i = 0; i < 10; i++, rowV = 1 - rowV, colV = rowV) - Padding( - padding: const EdgeInsets.only(top: 5, bottom: 5), - // RepaintBoundary here to separate each row into a separate layer child - child: RepaintBoundary( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - for (int j = 0; j < 7; j++, colV = 1 - colV) - Padding( - padding: const EdgeInsets.only(left: 5, right: 5), - // RepaintBoundary here to prevent the row children combining into a single Picture - child: RepaintBoundary( - child: Container( - width: 30, - height: 30, - color: Color.fromARGB(255, _red(colV), _green(colV), _blue(colV)), - ), - ), - ), - ], - ), - ), - ), - ], - ), - ); - }, - ), - OpacityPeepholeCase.forAnimation( - route: kOpacityPeepholeFadeTransitionTextRouteName, - name: 'FadeTransition text', - builder: (Animation animation) { - return FadeTransition( - opacity: Tween(begin: 0.25, end: 0.75).animate(animation), - child: const SizedBox( - width: 300, - height: 400, - child: Center( - child: Text('Hello, World', - style: TextStyle(fontSize: 48), - ), - ), - ), - ); - }, - ), -]; - -Map opacityPeepholeRoutes = { - for (OpacityPeepholeCase variant in allOpacityPeepholeCases) - variant.route: variant.buildPage, -}; - -class VariantPage extends StatefulWidget { - const VariantPage({Key? key, required this.variant}) : super(key: key); - - final OpacityPeepholeCase variant; - - @override - State createState() => VariantPageState(); -} - -class VariantPageState extends State with SingleTickerProviderStateMixin { - late AnimationController _controller; - - @override - void initState() { - super.initState(); - - _controller = AnimationController(vsync: this, duration: const Duration(seconds: 4)); - _controller.repeat(reverse: true); - } - - @override - void dispose() { - _controller.dispose(); - - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.variant.name), - ), - body: Center( - child: widget.variant.animationBuilder(_controller), - ), - ); - } -} diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_dynamic_clip_on_static_picture.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_dynamic_clip_on_static_picture.dart index db87f09af80ff..e69381166c1e5 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_dynamic_clip_on_static_picture.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_dynamic_clip_on_static_picture.dart @@ -36,7 +36,7 @@ class BenchDynamicClipOnStaticPicture extends SceneBuilderRecorder { // If the scrollable extent is too small, the benchmark may end up // scrolling the picture out of the clip area entirely, resulting in // bogus metric values. - const double maxScrollExtent = kDefaultTotalSampleCount * kScrollDelta; + const double maxScrollExtent = kTotalSampleCount * kScrollDelta; const double pictureHeight = kRows * kRowHeight; if (maxScrollExtent > pictureHeight) { throw Exception( diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_image_decoding.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_image_decoding.dart deleted file mode 100644 index 18792d55001aa..0000000000000 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_image_decoding.dart +++ /dev/null @@ -1,93 +0,0 @@ -// 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:html' as html; -import 'dart:typed_data'; -import 'dart:ui' as ui; - -import 'recorder.dart'; - -/// Measures the performance of image decoding. -/// -/// The benchmark measures the decoding latency and not impact on jank. It -/// cannot distinguish between blocking and non-blocking decoding. It simply -/// measures the total time it takes to decode image frames. For example, the -/// WASM codecs execute on the main thread and block the UI, leading to jank, -/// but the browser's WebCodecs API is asynchronous running on a separate thread -/// and does not jank. However, the benchmark result may be the same. -/// -/// This benchmark does not support the HTML renderer because the HTML renderer -/// cannot decode image frames (it always returns 1 dummy frame, even for -/// animated images). -class BenchImageDecoding extends RawRecorder { - BenchImageDecoding() : super( - name: benchmarkName, - useCustomWarmUp: true, - ); - - static const String benchmarkName = 'bench_image_decoding'; - - // These test images are taken from https://github.com/flutter/flutter_gallery_assets/tree/master/lib/splash_effects - static const List _imageUrls = [ - 'assets/packages/flutter_gallery_assets/splash_effects/splash_effect_1.gif', - 'assets/packages/flutter_gallery_assets/splash_effects/splash_effect_2.gif', - 'assets/packages/flutter_gallery_assets/splash_effects/splash_effect_3.gif', - ]; - - final List _imageData = []; - - @override - Future setUpAll() async { - if (_imageData.isNotEmpty) { - return; - } - for (final String imageUrl in _imageUrls) { - final html.Body image = await html.window.fetch(imageUrl) as html.Body; - _imageData.add((await image.arrayBuffer() as ByteBuffer).asUint8List()); - } - } - - // The number of samples recorded so far. - int _sampleCount = 0; - - // The number of samples used for warm-up. - static const int _warmUpSampleCount = 5; - - // The number of samples used to measure performance after the warm-up. - static const int _measuredSampleCount = 20; - - @override - Future body(Profile profile) async { - await profile.recordAsync('recordImageDecode', () async { - final List> allDecodes = >[ - for (final Uint8List data in _imageData) - _decodeImage(data), - ]; - await Future.wait(allDecodes); - }, reported: true); - - _sampleCount += 1; - if (_sampleCount == _warmUpSampleCount) { - profile.stopWarmingUp(); - } - if (_sampleCount >= _warmUpSampleCount + _measuredSampleCount) { - profile.stopBenchmark(); - } - } -} - -Future _decodeImage(Uint8List data) async { - final ui.Codec codec = await ui.instantiateImageCodec(data); - const int decodeFrameCount = 5; - if (codec.frameCount < decodeFrameCount) { - throw Exception( - 'Test image contains too few frames for this benchmark (${codec.frameCount}). ' - 'Choose a test image with at least $decodeFrameCount frames.' - ); - } - for (int i = 0; i < decodeFrameCount; i++) { - (await codec.getNextFrame()).image.dispose(); - } - codec.dispose(); -} diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_text_layout.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_text_layout.dart index 4a25d4452647c..282b1bcabcfb8 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_text_layout.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_text_layout.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:html' as html; +import 'dart:js_util' as js_util; import 'dart:math'; import 'dart:ui' as ui; @@ -50,25 +52,59 @@ enum _TestMode { /// Uses the HTML rendering backend with the canvas 2D text layout. useCanvasTextLayout, + /// Uses the HTML rendering backend with the DOM text layout. + useDomTextLayout, + /// Uses CanvasKit for everything. useCanvasKit, } +/// Sends a platform message to the web engine to enable/disable the usage of +/// the canvas-based text measurement implementation. +void _setTestMode(_TestMode? mode) { + bool? useCanvasText; // null means do not force DOM or canvas, works for CanvasKit + switch (mode) { + case _TestMode.useDomTextLayout: + useCanvasText = false; + break; + case _TestMode.useCanvasTextLayout: + useCanvasText = true; + break; + case _TestMode.useCanvasKit: + case null: + // Keep as null. + break; + } + // ignore: implicit_dynamic_function + js_util.callMethod( + html.window, + '_flutter_internal_update_experiment', + ['useCanvasText', useCanvasText], + ); +} + /// Repeatedly lays out a paragraph. /// /// Creates a different paragraph each time in order to avoid hitting the cache. class BenchTextLayout extends RawRecorder { + BenchTextLayout.dom() + : _mode = _TestMode.useDomTextLayout, super(name: domBenchmarkName); + BenchTextLayout.canvas() - : super(name: canvasBenchmarkName); + : _mode = _TestMode.useCanvasTextLayout, super(name: canvasBenchmarkName); BenchTextLayout.canvasKit() - : super(name: canvasKitBenchmarkName); + : _mode = _TestMode.useCanvasKit, super(name: canvasKitBenchmarkName); + static const String domBenchmarkName = 'text_dom_layout'; static const String canvasBenchmarkName = 'text_canvas_layout'; static const String canvasKitBenchmarkName = 'text_canvaskit_layout'; final ParagraphGenerator generator = ParagraphGenerator(); + /// Whether to use the new canvas-based text measurement implementation. + final _TestMode _mode; + static const String singleLineText = '*** ** ****'; static const String multiLineText = '*** ****** **** *** ******** * *** ' '******* **** ********** *** ******* ' @@ -77,6 +113,8 @@ class BenchTextLayout extends RawRecorder { @override void body(Profile profile) { + _setTestMode(_mode); + recordParagraphOperations( profile: profile, paragraph: generator.generate(singleLineText), @@ -108,6 +146,8 @@ class BenchTextLayout extends RawRecorder { keyPrefix: 'ellipsis', maxWidth: 200.0, ); + + _setTestMode(null); } void recordParagraphOperations({ @@ -143,17 +183,25 @@ class BenchTextLayout extends RawRecorder { /// use the same paragraph instance because the layout method will shortcircuit /// in that case. class BenchTextCachedLayout extends RawRecorder { + BenchTextCachedLayout.dom() + : _mode = _TestMode.useDomTextLayout, super(name: domBenchmarkName); + BenchTextCachedLayout.canvas() - : super(name: canvasBenchmarkName); + : _mode = _TestMode.useCanvasTextLayout, super(name: canvasBenchmarkName); BenchTextCachedLayout.canvasKit() - : super(name: canvasKitBenchmarkName); + : _mode = _TestMode.useCanvasKit, super(name: canvasKitBenchmarkName); + static const String domBenchmarkName = 'text_dom_cached_layout'; static const String canvasBenchmarkName = 'text_canvas_cached_layout'; static const String canvasKitBenchmarkName = 'text_canvas_kit_cached_layout'; + /// Whether to use the new canvas-based text measurement implementation. + final _TestMode _mode; + @override void body(Profile profile) { + _setTestMode(_mode); final ui.ParagraphBuilder builder = ui.ParagraphBuilder(ui.ParagraphStyle(fontFamily: 'sans-serif')) ..pushStyle(ui.TextStyle(fontSize: 12.0)) ..addText( @@ -164,6 +212,7 @@ class BenchTextCachedLayout extends RawRecorder { profile.record('layout', () { paragraph.layout(const ui.ParagraphConstraints(width: double.infinity)); }, reported: true); + _setTestMode(null); } } @@ -181,7 +230,8 @@ int _counter = 0; class BenchBuildColorsGrid extends WidgetBuildRecorder { BenchBuildColorsGrid.canvas() : _mode = _TestMode.useCanvasTextLayout, super(name: canvasBenchmarkName); - + BenchBuildColorsGrid.dom() + : _mode = _TestMode.useDomTextLayout, super(name: domBenchmarkName); BenchBuildColorsGrid.canvasKit() : _mode = _TestMode.useCanvasKit, super(name: canvasKitBenchmarkName); @@ -190,9 +240,12 @@ class BenchBuildColorsGrid extends WidgetBuildRecorder { /// When tracing is enabled, DOM layout takes longer to complete. This has a /// significant effect on the benchmark since we do a lot of text layout /// operations that trigger synchronous DOM layout. + /// + /// Tracing has a negative effect only in [_TestMode.useDomTextLayout] mode. @override bool get isTracingEnabled => false; + static const String domBenchmarkName = 'text_dom_color_grid'; static const String canvasBenchmarkName = 'text_canvas_color_grid'; static const String canvasKitBenchmarkName = 'text_canvas_kit_color_grid'; @@ -203,6 +256,7 @@ class BenchBuildColorsGrid extends WidgetBuildRecorder { @override Future setUpAll() async { + _setTestMode(_mode); registerEngineBenchmarkValueListener('text_layout', (num value) { _textLayoutMicros += value; }); @@ -210,6 +264,7 @@ class BenchBuildColorsGrid extends WidgetBuildRecorder { @override Future tearDownAll() async { + _setTestMode(null); stopListeningToEngineBenchmarkValues('text_layout'); } diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart index 3da4dbd180614..9bdcb0fe9e397 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart @@ -16,22 +16,16 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:meta/meta.dart'; -/// The default number of samples from warm-up iterations. +/// The number of samples from warm-up iterations. /// -/// This value is used when [Profile.useCustomWarmUp] is set to false. -/// -/// The benchmark is warmed up prior to measuring to allow JIT and caches to settle. -const int _kDefaultWarmUpSampleCount = 200; +/// We warm-up the benchmark prior to measuring to allow JIT and caches to settle. +const int _kWarmUpSampleCount = 200; -/// The default number of samples collected to compute benchmark statistics. -/// -/// This value is used when [Profile.useCustomWarmUp] is set to false. -const int _kDefaultMeasuredSampleCount = 100; +/// The number of samples we use to collect statistics from. +const int _kMeasuredSampleCount = 100; -/// The default total number of samples collected by a benchmark. -/// -/// This value is used when [Profile.useCustomWarmUp] is set to false. -const int kDefaultTotalSampleCount = _kDefaultWarmUpSampleCount + _kDefaultMeasuredSampleCount; +/// The total number of samples collected by a benchmark. +const int kTotalSampleCount = _kWarmUpSampleCount + _kMeasuredSampleCount; /// A benchmark metric that includes frame-related computations prior to /// submitting layer and picture operations to the underlying renderer, such as @@ -44,10 +38,6 @@ const String kProfilePrerollFrame = 'preroll_frame'; const String kProfileApplyFrame = 'apply_frame'; /// Measures the amount of time [action] takes. -/// -/// See also: -/// -/// * [timeAsyncAction], which measures the time of asynchronous work. Duration timeAction(VoidCallback action) { final Stopwatch stopwatch = Stopwatch()..start(); action(); @@ -55,18 +45,6 @@ Duration timeAction(VoidCallback action) { return stopwatch.elapsed; } -/// Measures the amount of time the future returned by [action] takes to complete. -/// -/// See also: -/// -/// * [timeAction], which measures the time of synchronous work. -Future timeAsyncAction(AsyncCallback action) async { - final Stopwatch stopwatch = Stopwatch()..start(); - await action(); - stopwatch.stop(); - return stopwatch.elapsed; -} - /// A function that performs asynchronous work. typedef AsyncVoidCallback = Future Function(); @@ -183,16 +161,12 @@ abstract class Recorder { /// } /// ``` abstract class RawRecorder extends Recorder { - RawRecorder({required String name, bool useCustomWarmUp = false}) - : _useCustomWarmUp = useCustomWarmUp, super._(name, false); - - /// Whether to delimit warm-up frames in a custom way. - final bool _useCustomWarmUp; + RawRecorder({required String name}) : super._(name, false); /// The body of the benchmark. /// /// This is the part that records measurements of the benchmark. - FutureOr body(Profile profile); + void body(Profile profile); @override Profile? get profile => _profile; @@ -201,13 +175,10 @@ abstract class RawRecorder extends Recorder { @override @nonVirtual Future run() async { - _profile = Profile(name: name, useCustomWarmUp: _useCustomWarmUp); + _profile = Profile(name: name); do { await Future.delayed(Duration.zero); - final FutureOr result = body(_profile!); - if (result is Future) { - await result; - } + body(_profile!); } while (shouldContinue()); return _profile!; } @@ -581,15 +552,13 @@ class _WidgetBuildRecorderHostState extends State<_WidgetBuildRecorderHost> { /// Series of time recordings indexed in time order. /// -/// A timeseries is expected to contain at least one warm-up frame added by -/// calling [add] with `isWarmUpValue` set to true, followed by at least one -/// measured value added by calling [add] with `isWarmUpValue` set to false. +/// It can calculate [average], [standardDeviation] and [noise]. If the amount +/// of data collected is higher than [_kMeasuredSampleCount], then these +/// calculations will only apply to the latest [_kMeasuredSampleCount] data +/// points. class Timeseries { - /// Creates an empty timeseries. - /// - /// The [name] is a unique name of this timeseries. If [isReported] is true - /// this timeseries is reported to the benchmark dashboard. - Timeseries(this.name, this.isReported); + Timeseries(this.name, this.isReported, {this.useCustomWarmUp = false}) + : _warmUpFrameCount = useCustomWarmUp ? 0 : null; /// The label of this timeseries used for debugging and result inspection. final String name; @@ -604,8 +573,17 @@ class Timeseries { /// but that are too fine-grained to be useful for tracking on the dashboard. final bool isReported; - /// The number of samples ignored as warm-up frames. - int _warmUpSampleCount = 0; + /// Whether to delimit warm-up frames in a custom way. + final bool useCustomWarmUp; + + /// The number of frames ignored as warm-up frames, used only + /// when [useCustomWarmUp] is true. + int? _warmUpFrameCount; + + /// The number of frames ignored as warm-up frames. + int get warmUpFrameCount => useCustomWarmUp + ? _warmUpFrameCount! + : count - _kMeasuredSampleCount; /// List of all the values that have been recorded. /// @@ -620,26 +598,15 @@ class Timeseries { /// /// See [TimeseriesStats] for more details. TimeseriesStats computeStats() { - // Assertions do not use the `assert` keyword because benchmarks run in - // profile mode, where asserts are tree-shaken out. - if (_warmUpSampleCount == 0) { - throw StateError( - 'The benchmark did not warm-up. Use at least one sample to warm-up ' - 'the benchmark to reduce noise.'); - } - if (_warmUpSampleCount >= count) { - throw StateError( - 'The benchmark did not report any measured samples. Add at least one ' - 'sample after warm-up is done. There were $_warmUpSampleCount warm-up ' - 'samples, and no measured samples in this timeseries.' - ); - } + final int finalWarmUpFrameCount = warmUpFrameCount; + + assert(finalWarmUpFrameCount >= 0 && finalWarmUpFrameCount < count); // The first few values we simply discard and never look at. They're from the warm-up phase. - final List warmUpValues = _allValues.sublist(0, _warmUpSampleCount); + final List warmUpValues = _allValues.sublist(0, finalWarmUpFrameCount); // Values we analyze. - final List candidateValues = _allValues.sublist(_warmUpSampleCount); + final List candidateValues = _allValues.sublist(finalWarmUpFrameCount); // The average that includes outliers. final double dirtyAverage = _computeAverage(name, candidateValues); @@ -696,9 +663,6 @@ class Timeseries { ); } - // Whether the timeseries is in the warm-up phase. - bool _isWarmingUp = true; - /// Adds a value to this timeseries. void add(double value, {required bool isWarmUpValue}) { if (value < 0.0) { @@ -706,17 +670,10 @@ class Timeseries { 'Timeseries $name: negative metric values are not supported. Got: $value', ); } - if (isWarmUpValue) { - if (!_isWarmingUp) { - throw StateError( - 'A warm-up value was added to the timeseries after the warm-up phase finished.' - ); - } - _warmUpSampleCount += 1; - } else if (_isWarmingUp) { - _isWarmingUp = false; - } _allValues.add(value); + if (useCustomWarmUp && isWarmUpValue) { + _warmUpFrameCount = (_warmUpFrameCount ?? 0) + 1; + } } } @@ -830,17 +787,9 @@ class AnnotatedSample { /// Base class for a profile collected from running a benchmark. class Profile { - /// Creates an empty profile that can be populated with benchmark samples - /// using [record], [recordAsync], and [addDataPoint] methods. - /// - /// The [name] is the unique name of this profile that distinguishes is from - /// other profiles. Typically, the name will describe the benchmark. - /// - /// If [useCustomWarmUp] is true the benchmark will continue running until - /// [stopBenchmark] is called. Otherwise, the benchmark collects the - /// [kDefaultTotalSampleCount] samples and stops automatically. Profile({required this.name, this.useCustomWarmUp = false}) - : assert(name != null); + : assert(name != null), + _isWarmingUp = useCustomWarmUp; /// The name of the benchmark that produced this profile. final String name; @@ -848,48 +797,26 @@ class Profile { /// Whether to delimit warm-up frames in a custom way. final bool useCustomWarmUp; - /// True if the benchmark is currently measuring warm-up frames. + /// Whether we are measuring warm-up frames currently. bool get isWarmingUp => _isWarmingUp; - bool _isWarmingUp = true; - /// True if the benchmark is currently running. - bool get isRunning => _isRunning; - bool _isRunning = true; + bool _isWarmingUp; - /// Stops the warm-up phase. - /// - /// After calling this method, subsequent calls to [record], [recordAsync], - /// and [addDataPoint] will record measured data samples. + /// Stop the warm-up phase. /// - /// Call this method only once for each profile and only when [isWarmingUp] - /// is true. + /// Call this method only when [useCustomWarmUp] and [isWarmingUp] are both + /// true. + /// Call this method only once for each profile. void stopWarmingUp() { - if (!_isWarmingUp) { - throw StateError('Warm-up already stopped.'); + if (!useCustomWarmUp) { + throw Exception('`stopWarmingUp` should be used only when `useCustomWarmUp` is true.'); + } else if (!_isWarmingUp) { + throw Exception('Warm-up already stopped.'); } else { _isWarmingUp = false; } } - /// Stops the benchmark. - /// - /// Call this method only once for each profile and only when [isWarmingUp] - /// is false (i.e. after calling [stopWarmingUp]). - void stopBenchmark() { - if (_isWarmingUp) { - throw StateError( - 'Warm-up has not finished yet. Benchmark should only be stopped after ' - 'it recorded at least one sample after the warm-up.' - ); - } else if (scoreData.isEmpty) { - throw StateError( - 'The benchmark did not collect any data.' - ); - } else { - _isRunning = false; - } - } - /// This data will be used to display cards in the Flutter Dashboard. final Map scoreData = {}; @@ -897,27 +824,12 @@ class Profile { final Map extraData = {}; /// Invokes [callback] and records the duration of its execution under [key]. - /// - /// See also: - /// - /// * [recordAsync], which records asynchronous work. Duration record(String key, VoidCallback callback, { required bool reported }) { final Duration duration = timeAction(callback); addDataPoint(key, duration, reported: reported); return duration; } - /// Invokes [callback] and records the amount of time the returned future takes. - /// - /// See also: - /// - /// * [record], which records synchronous work. - Future recordAsync(String key, AsyncCallback callback, { required bool reported }) async { - final Duration duration = await timeAsyncAction(callback); - addDataPoint(key, duration, reported: reported); - return duration; - } - /// Adds a timed sample to the timeseries corresponding to [key]. /// /// Set [reported] to `true` to report the timeseries to the dashboard UI. @@ -927,43 +839,8 @@ class Profile { void addDataPoint(String key, Duration duration, { required bool reported }) { scoreData.putIfAbsent( key, - () => Timeseries(key, reported), + () => Timeseries(key, reported, useCustomWarmUp: useCustomWarmUp), ).add(duration.inMicroseconds.toDouble(), isWarmUpValue: isWarmingUp); - - if (!useCustomWarmUp) { - // The stopWarmingUp and stopBenchmark will not be called. Use the - // auto-stopping logic. - _autoUpdateBenchmarkPhase(); - } - } - - /// Checks the samples collected so far and sets the appropriate benchmark phase. - /// - /// If enough warm-up samples have been collected, stops the warm-up phase and - /// begins the measuring phase. - /// - /// If enough total samples have been collected, stops the benchmark. - void _autoUpdateBenchmarkPhase() { - if (useCustomWarmUp) { - StateError( - 'Must not call _autoUpdateBenchmarkPhase if custom warm-up is used. ' - 'Call `stopWarmingUp` and `stopBenchmark` instead.' - ); - } - - if (_isWarmingUp) { - final bool doesHaveEnoughWarmUpSamples = scoreData.keys - .every((String key) => scoreData[key]!.count >= _kDefaultWarmUpSampleCount); - if (doesHaveEnoughWarmUpSamples) { - stopWarmingUp(); - } - } else if (_isRunning) { - final bool doesHaveEnoughTotalSamples = scoreData.keys - .every((String key) => scoreData[key]!.count >= kDefaultTotalSampleCount); - if (doesHaveEnoughTotalSamples) { - stopBenchmark(); - } - } } /// Decides whether the data collected so far is sufficient to stop, or @@ -981,7 +858,9 @@ class Profile { return true; } - return isRunning; + // We have recorded something, but do we have enough samples? If every + // timeseries has collected enough samples, stop the benchmark. + return !scoreData.keys.every((String key) => scoreData[key]!.count >= kTotalSampleCount); } /// Returns a JSON representation of the profile that will be sent to the diff --git a/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart b/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart index bfa02bbe76f54..4fff78f065857 100644 --- a/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart +++ b/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart @@ -15,7 +15,6 @@ import 'src/web/bench_clipped_out_pictures.dart'; import 'src/web/bench_default_target_platform.dart'; import 'src/web/bench_draw_rect.dart'; import 'src/web/bench_dynamic_clip_on_static_picture.dart'; -import 'src/web/bench_image_decoding.dart'; import 'src/web/bench_mouse_region_grid_hover.dart'; import 'src/web/bench_mouse_region_grid_scroll.dart'; import 'src/web/bench_mouse_region_mixed_grid_hover.dart'; @@ -63,17 +62,15 @@ final Map benchmarks = { BenchTextLayout.canvasKitBenchmarkName: () => BenchTextLayout.canvasKit(), BenchBuildColorsGrid.canvasKitBenchmarkName: () => BenchBuildColorsGrid.canvasKit(), BenchTextCachedLayout.canvasKitBenchmarkName: () => BenchTextCachedLayout.canvasKit(), - - // The HTML renderer does not decode frame-by-frame. It just drops an - // element and lets it animate automatically with no feedback to the - // framework. So this benchmark only makes sense in CanvasKit. - BenchImageDecoding.benchmarkName: () => BenchImageDecoding(), }, // HTML-only benchmarks if (!isCanvasKit) ...{ + BenchTextLayout.domBenchmarkName: () => BenchTextLayout.dom(), BenchTextLayout.canvasBenchmarkName: () => BenchTextLayout.canvas(), + BenchTextCachedLayout.domBenchmarkName: () => BenchTextCachedLayout.dom(), BenchTextCachedLayout.canvasBenchmarkName: () => BenchTextCachedLayout.canvas(), + BenchBuildColorsGrid.domBenchmarkName: () => BenchBuildColorsGrid.dom(), BenchBuildColorsGrid.canvasBenchmarkName: () => BenchBuildColorsGrid.canvas(), }, }; diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index b8b2c53fb0aeb..41feed6df9854 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # flutter update-packages --force-upgrade flutter_gallery_assets: 1.0.2 - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -29,28 +29,27 @@ dependencies: fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.20.1 + test: 1.17.12 integration_test: sdk: flutter - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,11 +59,12 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,7 +73,7 @@ dev_dependencies: shelf_web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -211,4 +211,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 2065 +# PUBSPEC CHECKSUM: 18cc diff --git a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_col_of_rows_perf_e2e.dart b/dev/benchmarks/macrobenchmarks/test/opacity_peephole_col_of_rows_perf_e2e.dart deleted file mode 100644 index cf9129ef88c00..0000000000000 --- a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_col_of_rows_perf_e2e.dart +++ /dev/null @@ -1,19 +0,0 @@ -// 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 'package:macrobenchmarks/common.dart'; - -import 'util.dart'; - -void main() { - macroPerfTestMultiPageE2E( - 'opacity_peephole_col_of_rows_perf', - [ - ScrollableButtonRoute(kScrollableName, kOpacityPeepholeRouteName), - ScrollableButtonRoute(kOpacityScrollableName, kOpacityPeepholeOpacityOfColOfRowsRouteName) - ], - pageDelay: const Duration(seconds: 1), - duration: const Duration(seconds: 10), - ); -} diff --git a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_fade_transition_text_perf_e2e.dart b/dev/benchmarks/macrobenchmarks/test/opacity_peephole_fade_transition_text_perf_e2e.dart deleted file mode 100644 index 269cfd1e8b858..0000000000000 --- a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_fade_transition_text_perf_e2e.dart +++ /dev/null @@ -1,19 +0,0 @@ -// 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 'package:macrobenchmarks/common.dart'; - -import 'util.dart'; - -void main() { - macroPerfTestMultiPageE2E( - 'opacity_peephole_fade_transition_text_perf', - [ - ScrollableButtonRoute(kScrollableName, kOpacityPeepholeRouteName), - ScrollableButtonRoute(kOpacityScrollableName, kOpacityPeepholeFadeTransitionTextRouteName) - ], - pageDelay: const Duration(seconds: 1), - duration: const Duration(seconds: 10), - ); -} diff --git a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_grid_of_opacity_perf_e2e.dart b/dev/benchmarks/macrobenchmarks/test/opacity_peephole_grid_of_opacity_perf_e2e.dart deleted file mode 100644 index 068c21cce65d4..0000000000000 --- a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_grid_of_opacity_perf_e2e.dart +++ /dev/null @@ -1,19 +0,0 @@ -// 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 'package:macrobenchmarks/common.dart'; - -import 'util.dart'; - -void main() { - macroPerfTestMultiPageE2E( - 'opacity_peephole_grid_of_opacity_perf', - [ - ScrollableButtonRoute(kScrollableName, kOpacityPeepholeRouteName), - ScrollableButtonRoute(kOpacityScrollableName, kOpacityPeepholeGridOfOpacityRouteName) - ], - pageDelay: const Duration(seconds: 1), - duration: const Duration(seconds: 10), - ); -} diff --git a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_one_rect_perf_e2e.dart b/dev/benchmarks/macrobenchmarks/test/opacity_peephole_one_rect_perf_e2e.dart deleted file mode 100644 index 63313da61861a..0000000000000 --- a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_one_rect_perf_e2e.dart +++ /dev/null @@ -1,19 +0,0 @@ -// 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 'package:macrobenchmarks/common.dart'; - -import 'util.dart'; - -void main() { - macroPerfTestMultiPageE2E( - 'opacity_peephole_one_rect_perf', - [ - ScrollableButtonRoute(kScrollableName, kOpacityPeepholeRouteName), - ScrollableButtonRoute(kOpacityScrollableName, kOpacityPeepholeOneRectRouteName) - ], - pageDelay: const Duration(seconds: 1), - duration: const Duration(seconds: 10), - ); -} diff --git a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_opacity_of_grid_perf_e2e.dart b/dev/benchmarks/macrobenchmarks/test/opacity_peephole_opacity_of_grid_perf_e2e.dart deleted file mode 100644 index ca6082830bd40..0000000000000 --- a/dev/benchmarks/macrobenchmarks/test/opacity_peephole_opacity_of_grid_perf_e2e.dart +++ /dev/null @@ -1,19 +0,0 @@ -// 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 'package:macrobenchmarks/common.dart'; - -import 'util.dart'; - -void main() { - macroPerfTestMultiPageE2E( - 'opacity_peephole_opacity_of_grid_perf', - [ - ScrollableButtonRoute(kScrollableName, kOpacityPeepholeRouteName), - ScrollableButtonRoute(kOpacityScrollableName, kOpacityPeepholeOpacityOfGridRouteName) - ], - pageDelay: const Duration(seconds: 1), - duration: const Duration(seconds: 10), - ); -} diff --git a/dev/benchmarks/macrobenchmarks/test/util.dart b/dev/benchmarks/macrobenchmarks/test/util.dart index 015da804494cf..3905a60de75c4 100644 --- a/dev/benchmarks/macrobenchmarks/test/util.dart +++ b/dev/benchmarks/macrobenchmarks/test/util.dart @@ -10,13 +10,6 @@ import 'package:macrobenchmarks/main.dart' as app; typedef ControlCallback = Future Function(WidgetController controller); -class ScrollableButtonRoute { - ScrollableButtonRoute(this.listViewKey, this.buttonKey); - - final String listViewKey; - final String buttonKey; -} - void macroPerfTestE2E( String testName, String routeName, { @@ -25,19 +18,6 @@ void macroPerfTestE2E( ControlCallback? body, ControlCallback? setup, }) { - macroPerfTestMultiPageE2E(testName, [ - ScrollableButtonRoute(kScrollableName, routeName), - ]); -} - -void macroPerfTestMultiPageE2E( - String testName, - List routes, { - Duration? pageDelay, - Duration duration = const Duration(seconds: 3), - ControlCallback? body, - ControlCallback? setup, - }) { final WidgetsBinding _binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); assert(_binding is IntegrationTestWidgetsFlutterBinding); final IntegrationTestWidgetsFlutterBinding binding = _binding as IntegrationTestWidgetsFlutterBinding; @@ -54,31 +34,17 @@ void macroPerfTestMultiPageE2E( // See: https://github.com/flutter/flutter/issues/19434 await tester.binding.delayed(const Duration(microseconds: 250)); - for (final ScrollableButtonRoute route in routes) { - expect(route.listViewKey, startsWith('/')); - expect(route.buttonKey, startsWith('/')); - - // Make sure each list view page is settled - await tester.pumpAndSettle(); - - final Finder listView = find.byKey(ValueKey(route.listViewKey)); - // ListView is not a Scrollable, but it contains one - final Finder scrollable = find.descendant(of: listView, matching: find.byType(Scrollable)); - // scrollable should find one widget as soon as the page is loaded - expect(scrollable, findsOneWidget); - - final Finder button = find.byKey(ValueKey(route.buttonKey), skipOffstage: false); - // button may or may not find a widget right away until we scroll to it - await tester.scrollUntilVisible(button, 50, scrollable: scrollable); - // After scrolling, button should find one Widget - expect(button, findsOneWidget); - - // Allow scrolling to settle - await tester.pumpAndSettle(); - await tester.tap(button); - // Cannot be pumpAndSettle because some tests have infinite animation. - await tester.pump(const Duration(milliseconds: 20)); - } + final Finder scrollable = + find.byKey(const ValueKey(kScrollableName)); + expect(scrollable, findsOneWidget); + final Finder button = + find.byKey(ValueKey(routeName), skipOffstage: false); + await tester.scrollUntilVisible(button, 50); + expect(button, findsOneWidget); + await tester.pumpAndSettle(); + await tester.tap(button); + // Cannot be pumpAndSettle because some tests have infinite animation. + await tester.pump(const Duration(milliseconds: 20)); if (pageDelay != null) { // Wait for the page to load diff --git a/dev/benchmarks/microbenchmarks/android/app/src/main/AndroidManifest.xml b/dev/benchmarks/microbenchmarks/android/app/src/main/AndroidManifest.xml index ddc953db7e5a0..fc38010373a17 100644 --- a/dev/benchmarks/microbenchmarks/android/app/src/main/AndroidManifest.xml +++ b/dev/benchmarks/microbenchmarks/android/app/src/main/AndroidManifest.xml @@ -7,8 +7,8 @@ found in the LICENSE file. --> - - + - - diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 1e00907485b8c..3f62c3c693c6d 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -12,10 +12,10 @@ dependencies: sdk: flutter stocks: path: ../test_apps/stocks - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -37,14 +37,14 @@ dependencies: intl: 0.17.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" isolate: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,11 +58,11 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +71,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 9709 +# PUBSPEC CHECKSUM: 7472 diff --git a/dev/benchmarks/multiple_flutters/android/app/build.gradle b/dev/benchmarks/multiple_flutters/android/app/build.gradle index 9c43ffbaa8e46..b84fbef8be893 100644 --- a/dev/benchmarks/multiple_flutters/android/app/build.gradle +++ b/dev/benchmarks/multiple_flutters/android/app/build.gradle @@ -13,7 +13,7 @@ android { } } - compileSdkVersion 31 + compileSdkVersion 30 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -27,7 +27,7 @@ android { defaultConfig { applicationId "dev.flutter.multipleflutters" minSdkVersion 24 - targetSdkVersion 31 + targetSdkVersion 30 versionCode 1 versionName "1.0" diff --git a/dev/benchmarks/multiple_flutters/android/app/src/main/java/dev/flutter/multipleflutters/MainActivity.kt b/dev/benchmarks/multiple_flutters/android/app/src/main/java/dev/flutter/multipleflutters/MainActivity.kt index 4e96ded2a24fe..374bdf2f948f4 100644 --- a/dev/benchmarks/multiple_flutters/android/app/src/main/java/dev/flutter/multipleflutters/MainActivity.kt +++ b/dev/benchmarks/multiple_flutters/android/app/src/main/java/dev/flutter/multipleflutters/MainActivity.kt @@ -15,12 +15,11 @@ import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentManager import io.flutter.FlutterInjector import io.flutter.embedding.android.FlutterFragment -import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.FlutterEngineCache import io.flutter.embedding.engine.dart.DartExecutor class MainActivity : FragmentActivity() { - private val numberOfFlutters = 20 + private val numberOfFlutters = 2 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -41,10 +40,8 @@ class MainActivity : FragmentActivity() { DartExecutor.DartEntrypoint( FlutterInjector.instance().flutterLoader().findAppBundlePath(), "main" ) - val engines = generateSequence(0) { it + 1 } - .take(numberOfFlutters) - .map { app.engines.createAndRunEngine(this, dartEntrypoint) } - .toList() + val topEngine = app.engines.createAndRunEngine(this, dartEntrypoint) + val bottomEngine = app.engines.createAndRunEngine(this, dartEntrypoint) for (i in 0 until numberOfFlutters) { val flutterContainer = FrameLayout(this) root.addView(flutterContainer) @@ -54,7 +51,7 @@ class MainActivity : FragmentActivity() { FrameLayout.LayoutParams.MATCH_PARENT, 1.0f ) - val engine = engines[i] + val engine = if (i == 0) topEngine else bottomEngine FlutterEngineCache.getInstance().put(i.toString(), engine) val flutterFragment = FlutterFragment.withCachedEngine(i.toString()).build() diff --git a/dev/benchmarks/multiple_flutters/android/build.gradle b/dev/benchmarks/multiple_flutters/android/build.gradle index aa058334c9057..529092bfc25c5 100644 --- a/dev/benchmarks/multiple_flutters/android/build.gradle +++ b/dev/benchmarks/multiple_flutters/android/build.gradle @@ -4,7 +4,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.4.32" + ext.kotlin_version = "1.3.72" repositories { google() mavenCentral() diff --git a/dev/benchmarks/multiple_flutters/module/lib/main.dart b/dev/benchmarks/multiple_flutters/module/lib/main.dart index 2b35ddcec0a77..2a48ad1f10943 100644 --- a/dev/benchmarks/multiple_flutters/module/lib/main.dart +++ b/dev/benchmarks/multiple_flutters/module/lib/main.dart @@ -3,8 +3,6 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; -import 'package:flutter/semantics.dart'; -import 'package:google_fonts/google_fonts.dart'; void main() => runApp(const MyApp(Colors.blue)); @@ -39,55 +37,6 @@ class MyHomePage extends StatefulWidget { State createState() => _MyHomePageState(); } -class Sky extends CustomPainter { - @override - void paint(Canvas canvas, Size size) { - final Rect rect = Offset.zero & size; - const RadialGradient gradient = RadialGradient( - center: Alignment(0.7, -0.6), - radius: 0.2, - colors: [Color(0xFFFFFF00), Color(0xFF0099FF)], - stops: [0.4, 1.0], - ); - canvas.drawRect( - rect, - Paint()..shader = gradient.createShader(rect), - ); - } - - @override - SemanticsBuilderCallback get semanticsBuilder { - return (Size size) { - // Annotate a rectangle containing the picture of the sun - // with the label "Sun". When text to speech feature is enabled on the - // device, a user will be able to locate the sun on this picture by - // touch. - Rect rect = Offset.zero & size; - final double width = size.shortestSide * 0.4; - rect = const Alignment(0.8, -0.9).inscribe(Size(width, width), rect); - return [ - CustomPainterSemantics( - rect: rect, - properties: const SemanticsProperties( - label: 'Sun', - textDirection: TextDirection.ltr, - ), - ), - ]; - }; - } - - // Since this Sky painter has no fields, it always paints - // the same thing and semantics information is the same. - // Therefore we return false here. If we had fields (set - // from the constructor) then we would return true if any - // of them differed from the same fields on the oldDelegate. - @override - bool shouldRepaint(Sky oldDelegate) => false; - @override - bool shouldRebuildSemantics(Sky oldDelegate) => false; -} - class _MyHomePageState extends State { @override Widget build(BuildContext context) { @@ -96,85 +45,25 @@ class _MyHomePageState extends State { title: Text(widget.title ?? ''), ), body: Center( - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'You have pushed the button this many times:', - style: GoogleFonts.lato(), - ), - Text( - '0', - style: Theme.of(context).textTheme.headline4, - ), - TextButton( - onPressed: () {}, - child: const Text('Add'), - ), - TextButton( - onPressed: () {}, - child: const Text('Next'), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - const Icon( - Icons.favorite, - color: Colors.pink, - size: 24.0, - semanticLabel: 'Text to announce in accessibility modes', - ), - const Icon( - Icons.audiotrack, - color: Colors.green, - size: 30.0, - ), - const Icon( - Icons.beach_access, - color: Colors.blue, - size: 36.0, - ), - const Icon( - Icons.zoom_out, - color: Colors.amber, - size: 36.0, - ), - const Icon( - Icons.money, - color: Colors.lightGreen, - size: 36.0, - ), - const Icon( - Icons.bug_report, - color: Colors.teal, - size: 36.0, - ), - Container( - width: 36.0, - height: 36.0, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment(0.8, - 0.0), // 10% of the width, so there are ten blinds. - colors: [ - Color(0xffee0000), - Color(0xffeeee00) - ], // red to yellow - tileMode: TileMode - .repeated, // repeats the gradient over the canvas - ), - ), - ), - ], - ), - CustomPaint( - painter: Sky(), - size: const Size(200.0, 36.0), - ) - ], - ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'You have pushed the button this many times:', + ), + Text( + '0', + style: Theme.of(context).textTheme.headline4, + ), + TextButton( + onPressed: () {}, + child: const Text('Add'), + ), + TextButton( + onPressed: () {}, + child: const Text('Next'), + ), + ], ), ), ); diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index f45c71aef3714..a2815b82c8961 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -4,44 +4,19 @@ description: A module that is embedded in the multiple_flutters benchmark test. version: 1.0.0+1 environment: - sdk: ">=2.12.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: sdk: flutter - cupertino_icons: 1.0.4 - google_fonts: 2.2.0 + cupertino_icons: 1.0.3 - async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - charcode: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - ffi: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http: 0.13.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_android: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_ios: 2.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_macos: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 2.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -51,4 +26,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 5764 +# PUBSPEC CHECKSUM: ac15 diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index 9553f3fb86be5..96de0e1f3d1d4 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -14,10 +14,10 @@ dependencies: sdk: flutter microbenchmarks: path: ../microbenchmarks - cupertino_icons: 1.0.4 + cupertino_icons: 1.0.3 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,15 +36,15 @@ dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,12 +58,12 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.20.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.17.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 8bf6 +# PUBSPEC CHECKSUM: e95f diff --git a/dev/benchmarks/platform_views_layout/android/app/src/main/AndroidManifest.xml b/dev/benchmarks/platform_views_layout/android/app/src/main/AndroidManifest.xml index 8809178900ff0..b947c94d96bee 100644 --- a/dev/benchmarks/platform_views_layout/android/app/src/main/AndroidManifest.xml +++ b/dev/benchmarks/platform_views_layout/android/app/src/main/AndroidManifest.xml @@ -7,7 +7,7 @@ found in the LICENSE file. --> - + - + kCorePackageAllowList = { 'js', 'logging', 'matcher', - 'material_color_utilities', 'meta', 'mime', 'node_preamble', 'package_config', 'path', + 'pedantic', // resolving the pin on `test` should remove this, see https://github.com/dart-lang/test/issues/1594 'pool', 'pub_semver', 'shelf', diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart index 119784dd269fa..a642f49c156c3 100644 --- a/dev/bots/analyze.dart +++ b/dev/bots/analyze.dart @@ -24,14 +24,8 @@ import 'utils.dart'; final String flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); final String flutter = path.join(flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'); final String flutterPackages = path.join(flutterRoot, 'packages'); -final String flutterExamples = path.join(flutterRoot, 'examples'); - -/// The path to the `dart` executable; set at the top of `main` -late final String dart; - -/// The path to the `pub` executable; set at the top of `main` -late final String pub; - +final String dart = path.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', Platform.isWindows ? 'dart.exe' : 'dart'); +final String pub = path.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', Platform.isWindows ? 'pub.bat' : 'pub'); final String pubCache = path.join(flutterRoot, '.pub-cache'); /// When you call this, you can pass additional arguments to pass custom @@ -41,12 +35,6 @@ final String pubCache = path.join(flutterRoot, '.pub-cache'); /// For example: /// bin/cache/dart-sdk/bin/dart dev/bots/analyze.dart --dart-sdk=/tmp/dart-sdk Future main(List arguments) async { - final String dartSdk = path.join( - Directory.current.absolute.path, - _getDartSdkFromArguments(arguments) ?? path.join(flutterRoot, 'bin', 'cache', 'dart-sdk'), - ); - dart = path.join(dartSdk, 'bin', Platform.isWindows ? 'dart.exe' : 'dart'); - pub = path.join(dartSdk, 'bin', Platform.isWindows ? 'pub.bat' : 'pub'); print('$clock STARTING ANALYSIS'); try { await run(arguments); @@ -56,31 +44,6 @@ Future main(List arguments) async { print('$clock ${bold}Analysis successful.$reset'); } -/// Scans [arguments] for an argument of the form `--dart-sdk` or -/// `--dart-sdk=...` and returns the configured SDK, if any. -String? _getDartSdkFromArguments(List arguments) { - String? result; - for (int i = 0; i < arguments.length; i += 1) { - if (arguments[i] == '--dart-sdk') { - if (result != null) { - exitWithError(['The --dart-sdk argument must not be used more than once.']); - } - if (i + 1 < arguments.length) { - result = arguments[i + 1]; - } else { - exitWithError(['--dart-sdk must be followed by a path.']); - } - } - if (arguments[i].startsWith('--dart-sdk=')) { - if (result != null) { - exitWithError(['The --dart-sdk argument must not be used more than once.']); - } - result = arguments[i].substring('--dart-sdk='.length); - } - } - return result; -} - Future run(List arguments) async { bool assertsEnabled = false; assert(() { assertsEnabled = true; return true; }()); @@ -88,19 +51,12 @@ Future run(List arguments) async { exitWithError(['The analyze.dart script must be run with --enable-asserts.']); } - print('$clock No sync*/async*'); - await verifyNoSyncAsyncStar(flutterPackages); - await verifyNoSyncAsyncStar(flutterExamples, minimumMatches: 200); - - print('$clock No runtimeType in toString...'); + print('$clock runtimeType in toString...'); await verifyNoRuntimeTypeInToString(flutterRoot); - print('$clock Debug mode instead of checked mode...'); + print('$clock debug mode instead of checked mode...'); await verifyNoCheckedMode(flutterRoot); - print('$clock Links for creating GitHub issues'); - await verifyIssueLinks(flutterRoot); - print('$clock Unexpected binaries...'); await verifyNoBinaries(flutterRoot); @@ -134,9 +90,6 @@ Future run(List arguments) async { print('$clock Integration test timeouts...'); await verifyIntegrationTestTimeouts(flutterRoot); - print('$clock null initialized debug fields...'); - await verifyNullInitializedDebugExpensiveFields(flutterRoot); - // Ensure that all package dependencies are in sync. print('$clock Package dependencies...'); await runCommand(flutter, ['update-packages', '--verify-only'], @@ -197,45 +150,6 @@ Future run(List arguments) async { // TESTS -Future verifyNoSyncAsyncStar(String workingDirectory, {int minimumMatches = 2000 }) async { - final RegExp syncPattern = RegExp(r'\s*?a?sync\*\s*?{'); - final RegExp ignorePattern = RegExp(r'^\s*?// The following uses a?sync\* because:? '); - final RegExp commentPattern = RegExp(r'^\s*?//'); - final List errors = []; - await for (final File file in _allFiles(workingDirectory, 'dart', minimumMatches: minimumMatches)) { - if (file.path.contains('test')) { - continue; - } - final List lines = file.readAsLinesSync(); - for (int index = 0; index < lines.length; index += 1) { - final String line = lines[index]; - if (line.startsWith(commentPattern)) { - continue; - } - if (line.contains(syncPattern)) { - int lookBehindIndex = index - 1; - bool hasExplanation = false; - while (lookBehindIndex >= 0 && lines[lookBehindIndex].startsWith(commentPattern)) { - if (lines[lookBehindIndex].startsWith(ignorePattern)) { - hasExplanation = true; - break; - } - lookBehindIndex -= 1; - } - if (!hasExplanation) { - errors.add('${file.path}:$index: sync*/async* without an explanation.'); - } - } - } - } - if (errors.isNotEmpty) { - exitWithError([ - '${bold}Do not use sync*/async* methods. See https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-syncasync for details.$reset', - ...errors, - ]); - } -} - final RegExp _findGoldenTestPattern = RegExp(r'matchesGoldenFile\('); final RegExp _findGoldenDefinitionPattern = RegExp(r'matchesGoldenFile\(Object'); final RegExp _leadingComment = RegExp(r'\/\/'); @@ -406,62 +320,42 @@ String _generateLicense(String prefix) { Future verifyNoMissingLicense(String workingDirectory, { bool checkMinimums = true }) async { final int? overrideMinimumMatches = checkMinimums ? null : 0; - int failed = 0; - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'dart', overrideMinimumMatches ?? 2000, _generateLicense('// ')); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'java', overrideMinimumMatches ?? 39, _generateLicense('// ')); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'h', overrideMinimumMatches ?? 30, _generateLicense('// ')); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'm', overrideMinimumMatches ?? 30, _generateLicense('// ')); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'swift', overrideMinimumMatches ?? 10, _generateLicense('// ')); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'gradle', overrideMinimumMatches ?? 80, _generateLicense('// ')); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'gn', overrideMinimumMatches ?? 0, _generateLicense('# ')); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'sh', overrideMinimumMatches ?? 1, _generateLicense('# '), header: r'#!/usr/bin/env bash\n',); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'bat', overrideMinimumMatches ?? 1, _generateLicense('REM '), header: r'@ECHO off\n'); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'ps1', overrideMinimumMatches ?? 1, _generateLicense('# ')); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'html', overrideMinimumMatches ?? 1, '', trailingBlank: false, header: r'\n'); - failed += await _verifyNoMissingLicenseForExtension(workingDirectory, 'xml', overrideMinimumMatches ?? 1, '', header: r'(<\?xml version="1.0" encoding="utf-8"\?>\n)?'); - if (failed > 0) { - exitWithError(['License check failed.']); - } + await _verifyNoMissingLicenseForExtension(workingDirectory, 'dart', overrideMinimumMatches ?? 2000, _generateLicense('// ')); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'java', overrideMinimumMatches ?? 39, _generateLicense('// ')); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'h', overrideMinimumMatches ?? 30, _generateLicense('// ')); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'm', overrideMinimumMatches ?? 30, _generateLicense('// ')); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'swift', overrideMinimumMatches ?? 10, _generateLicense('// ')); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'gradle', overrideMinimumMatches ?? 80, _generateLicense('// ')); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'gn', overrideMinimumMatches ?? 0, _generateLicense('# ')); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'sh', overrideMinimumMatches ?? 1, '#!/usr/bin/env bash\n${_generateLicense('# ')}'); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'bat', overrideMinimumMatches ?? 1, '@ECHO off\n${_generateLicense('REM ')}'); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'ps1', overrideMinimumMatches ?? 1, _generateLicense('# ')); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'html', overrideMinimumMatches ?? 1, '\n', trailingBlank: false); + await _verifyNoMissingLicenseForExtension(workingDirectory, 'xml', overrideMinimumMatches ?? 1, ''); } -Future _verifyNoMissingLicenseForExtension( - String workingDirectory, - String extension, - int minimumMatches, - String license, { - bool trailingBlank = true, - // The "header" is a regular expression matching the header that comes before - // the license in some files. - String header = '', -}) async { +Future _verifyNoMissingLicenseForExtension(String workingDirectory, String extension, int minimumMatches, String license, { bool trailingBlank = true }) async { assert(!license.endsWith('\n')); - final String licensePattern = RegExp.escape('$license\n${trailingBlank ? '\n' : ''}'); + final String licensePattern = '$license\n${trailingBlank ? '\n' : ''}'; final List errors = []; await for (final File file in _allFiles(workingDirectory, extension, minimumMatches: minimumMatches)) { final String contents = file.readAsStringSync().replaceAll('\r\n', '\n'); if (contents.isEmpty) continue; // let's not go down the /bin/true rabbit hole - if (!contents.startsWith(RegExp(header + licensePattern))) + if (!contents.startsWith(licensePattern)) errors.add(file.path); } // Fail if any errors if (errors.isNotEmpty) { - final String redLine = '$red━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━$reset'; - final String fileDoes = errors.length == 1 ? 'file does' : '${errors.length} files do'; - print([ - redLine, - '${bold}The following $fileDoes not have the right license header for $extension files:$reset', - ...errors.map((String error) => ' $error'), + final String s = errors.length == 1 ? ' does' : 's do'; + exitWithError([ + '${bold}The following ${errors.length} file$s not have the right license header:$reset', + ...errors, 'The expected license header is:', - if (header.isNotEmpty) 'A header matching the regular expression "$header",', - if (header.isNotEmpty) 'followed by the following license text:', license, if (trailingBlank) '...followed by a blank line.', - redLine, - ].join('\n')); - return 1; + ]); } - return 0; } class _TestSkip { @@ -834,81 +728,6 @@ Future verifyNoTrailingSpaces(String workingDirectory, { int minimumMatche exitWithError(problems); } -String _bullets(String value) => ' * $value'; - -Future verifyIssueLinks(String workingDirectory) async { - const String issueLinkPrefix = 'https://github.com/flutter/flutter/issues/new'; - const Set stops = { '\n', ' ', "'", '"', r'\', ')', '>' }; - assert(!stops.contains('.')); // instead of "visit https://foo." say "visit: https://", it copy-pastes better - const String kGiveTemplates = - 'Prefer to provide a link either to $issueLinkPrefix/choose (the list of issue ' - 'templates) or to a specific template directly ($issueLinkPrefix?template=...).\n'; - final Set templateNames = - Directory(path.join(workingDirectory, '.github', 'ISSUE_TEMPLATE')) - .listSync() - .whereType() - .where((File file) => path.extension(file.path) == '.md') - .map((File file) => path.basename(file.path)) - .toSet(); - final String kTemplates = 'The available templates are:\n${templateNames.map(_bullets).join("\n")}'; - final List problems = []; - final Set suggestions = {}; - final List files = await _gitFiles(workingDirectory); - for (final File file in files) { - if (path.basename(file.path).endsWith('_test.dart') || path.basename(file.path) == 'analyze.dart') - continue; // Skip tests, they're not public-facing. - final Uint8List bytes = file.readAsBytesSync(); - // We allow invalid UTF-8 here so that binaries don't trip us up. - // There's a separate test in this file that verifies that all text - // files are actually valid UTF-8 (see verifyNoBinaries below). - final String contents = utf8.decode(bytes, allowMalformed: true); - int start = 0; - while ((start = contents.indexOf(issueLinkPrefix, start)) >= 0) { - int end = start + issueLinkPrefix.length; - while (end < contents.length && !stops.contains(contents[end])) { - end += 1; - } - final String url = contents.substring(start, end); - if (url == issueLinkPrefix) { - if (file.path != path.join(workingDirectory, 'dev', 'bots', 'analyze.dart')) { - problems.add('${file.path} contains a direct link to $issueLinkPrefix.'); - suggestions.add(kGiveTemplates); - suggestions.add(kTemplates); - } - } else if (url.startsWith('$issueLinkPrefix?')) { - final Uri parsedUrl = Uri.parse(url); - final List? templates = parsedUrl.queryParametersAll['template']; - if (templates == null) { - problems.add('${file.path} contains $url, which has no "template" argument specified.'); - suggestions.add(kGiveTemplates); - suggestions.add(kTemplates); - } else if (templates.length != 1) { - problems.add('${file.path} contains $url, which has ${templates.length} templates specified.'); - suggestions.add(kGiveTemplates); - suggestions.add(kTemplates); - } else if (!templateNames.contains(templates.single)) { - problems.add('${file.path} contains $url, which specifies a non-existent template ("${templates.single}").'); - suggestions.add(kTemplates); - } else if (parsedUrl.queryParametersAll.keys.length > 1) { - problems.add('${file.path} contains $url, which the analyze.dart script is not sure how to handle.'); - suggestions.add('Update analyze.dart to handle the URLs above, or change them to the expected pattern.'); - } - } else if (url != '$issueLinkPrefix/choose') { - problems.add('${file.path} contains $url, which the analyze.dart script is not sure how to handle.'); - suggestions.add('Update analyze.dart to handle the URLs above, or change them to the expected pattern.'); - } - start = end; - } - } - assert(problems.isEmpty == suggestions.isEmpty); - if (problems.isNotEmpty) { - exitWithError([ - ...problems, - ...suggestions, - ]); - } -} - @immutable class Hash256 { const Hash256(this.a, this.b, this.c, this.d); @@ -1344,7 +1163,7 @@ Future verifyNoBinaries(String workingDirectory, { Set? legacyBin ); legacyBinaries ??= _legacyBinaries; if (!Platform.isWindows) { // TODO(ianh): Port this to Windows - final List files = await _gitFiles(workingDirectory); + final List files = await _gitFiles(workingDirectory, runSilently: false); final List problems = []; for (final File file in files) { final Uint8List bytes = file.readAsBytesSync(); @@ -1562,40 +1381,6 @@ Future _checkConsumerDependencies() async { } } -const String _kDebugOnlyAnnotation = '@_debugOnly'; -final RegExp _nullInitializedField = RegExp(r'kDebugMode \? [\w\<\> ,{}()]+ : null;'); - -Future verifyNullInitializedDebugExpensiveFields(String workingDirectory, {int minimumMatches = 400}) async { - final String flutterLib = path.join(workingDirectory, 'packages', 'flutter', 'lib'); - final List files = await _allFiles(flutterLib, 'dart', minimumMatches: minimumMatches) - .toList(); - final List errors = []; - for (final File file in files) { - final List lines = file.readAsLinesSync(); - for (int i = 0; i < lines.length; i += 1) { - final String line = lines[i]; - if (!line.contains(_kDebugOnlyAnnotation)) { - continue; - } - final String nextLine = lines[i + 1]; - if (_nullInitializedField.firstMatch(nextLine) == null) { - errors.add('${file.path} L$i'); - } - } - } - - if (errors.isNotEmpty) { - exitWithError([ - '${bold}ERROR: ${red}fields annotated with @_debugOnly must null initialize.$reset', - 'to ensure both the field and initializer are removed from profile/release mode.', - 'These fields should be written as:\n', - 'field = kDebugMode ? : null;\n', - 'Errors were found in the following files:', - ...errors, - ]); - } -} - Future _runFlutterAnalyze(String workingDirectory, { List options = const [], }) async { diff --git a/dev/bots/analyze_sample_code.dart b/dev/bots/analyze_sample_code.dart index 4e860819b984e..3fcd63bbe4b68 100644 --- a/dev/bots/analyze_sample_code.dart +++ b/dev/bots/analyze_sample_code.dart @@ -169,8 +169,8 @@ class _TaskQueueItem { Future run() async { try { _completer.complete(await _closure()); - } catch (e, st) { - _completer.completeError(e, st); + } catch (e) { + _completer.completeError(e); } finally { onComplete?.call(); } diff --git a/dev/bots/docs.sh b/dev/bots/docs.sh index 2d154430ec2b7..ef68ae1b2447e 100755 --- a/dev/bots/docs.sh +++ b/dev/bots/docs.sh @@ -75,6 +75,9 @@ function create_docset() { } function deploy_docs() { + # Ensure google webmaster tools can verify our site. + cp "$FLUTTER_ROOT/dev/docs/google2ed1af765c529f57.html" "$FLUTTER_ROOT/dev/docs/doc" + case "$LUCI_BRANCH" in master) echo "$(date): Updating $LUCI_BRANCH docs: https://master-api.flutter.dev/" diff --git a/dev/bots/prepare_package.dart b/dev/bots/prepare_package.dart index 01a5625104004..433b7be48e43e 100644 --- a/dev/bots/prepare_package.dart +++ b/dev/bots/prepare_package.dart @@ -24,8 +24,6 @@ const String gsBase = 'gs://flutter_infra_release'; const String gsReleaseFolder = '$gsBase$releaseFolder'; const String baseUrl = 'https://storage.googleapis.com/flutter_infra_release'; const int shortCacheSeconds = 60; -const String frameworkVersionTag = 'frameworkVersionFromGit'; -const String dartVersionTag = 'dartSdkVersion'; /// Exception class for when a process fails to run, so we can catch /// it and provide something more readable than a stack trace. @@ -253,7 +251,7 @@ class ArchiveCreator { final HttpReader httpReader; late File _outputFile; - final Map _version = {}; + late String _version; late String _flutter; /// Get the name of the channel as a string. @@ -271,24 +269,21 @@ class ArchiveCreator { // unpacking it!) So, we use .zip for Mac, and the files are about // 220MB larger than they need to be. :-( final String suffix = platform.isLinux ? 'tar.xz' : 'zip'; - return 'flutter_${os}_${_version[frameworkVersionTag]}-$branchName.$suffix'; + return 'flutter_${os}_$_version-$branchName.$suffix'; } /// Checks out the flutter repo and prepares it for other operations. /// - /// Returns the version for this release as obtained from the git tags, and - /// the dart version as obtained from `flutter --version`. - Future> initializeRepo() async { + /// Returns the version for this release, as obtained from the git tags. + Future initializeRepo() async { await _checkoutFlutter(); - if (_version.isEmpty) { - _version.addAll(await _getVersion()); - } + _version = await _getVersion(); return _version; } /// Performs all of the steps needed to create an archive. Future createArchive() async { - assert(_version.isNotEmpty, 'Must run initializeRepo before createArchive'); + assert(_version != null, 'Must run initializeRepo before createArchive'); _outputFile = File(path.join(outputDir.absolute.path, _archiveName)); await _installMinGitIfNeeded(); await _populateCaches(); @@ -333,8 +328,8 @@ class ArchiveCreator { } } - /// Returns the version map of this release, according the to tags in the - /// repo and the output of `flutter --version --machine`. + /// Returns the version number of this release, according the to tags in the + /// repo. /// /// This looks for the tag attached to [revision] and, if it doesn't find one, /// git will give an error. @@ -342,15 +337,10 @@ class ArchiveCreator { /// If [strict] is true, the exact [revision] must be tagged to return the /// version. If [strict] is not true, will look backwards in time starting at /// [revision] to find the most recent version tag. - /// - /// The version found as a git tag is added to the information given by - /// `flutter --version --machine` with the `frameworkVersionFromGit` tag, and - /// returned. - Future> _getVersion() async { - String gitVersion; + Future _getVersion() async { if (strict) { try { - gitVersion = await _runGit(['describe', '--tags', '--exact-match', revision]); + return _runGit(['describe', '--tags', '--exact-match', revision]); } on PreparePackageException catch (exception) { throw PreparePackageException( 'Git error when checking for a version tag attached to revision $revision.\n' @@ -359,18 +349,8 @@ class ArchiveCreator { ); } } else { - gitVersion = await _runGit(['describe', '--tags', '--abbrev=0', revision]); + return _runGit(['describe', '--tags', '--abbrev=0', revision]); } - // Run flutter command twice, once to make sure the flutter command is built - // and ready (and thus won't output any junk on stdout the second time), and - // once to capture theJSON output. The second run should be fast. - await _runFlutter(['--version', '--machine']); - final String versionJson = await _runFlutter(['--version', '--machine']); - final Map versionMap = {}; - final Map result = json.decode(versionJson) as Map; - result.forEach((String key, dynamic value) => versionMap[key] = value.toString()); - versionMap[frameworkVersionTag] = gitVersion; - return versionMap; } /// Clone the Flutter repo and make sure that the git environment is sane @@ -566,7 +546,7 @@ class ArchivePublisher { final String metadataGsPath; final Branch branch; final String revision; - final Map version; + final String version; final Directory tempDir; final File outputFile; final ProcessRunner _processRunner; @@ -621,8 +601,7 @@ class ArchivePublisher { final Map newEntry = {}; newEntry['hash'] = revision; newEntry['channel'] = branchName; - newEntry['version'] = version[frameworkVersionTag]; - newEntry['dart_sdk_version'] = version[dartVersionTag]; + newEntry['version'] = version; newEntry['release_date'] = DateTime.now().toUtc().toIso8601String(); newEntry['archive'] = destinationArchivePath; newEntry['sha256'] = await _getChecksum(outputFile); @@ -651,25 +630,24 @@ class ArchivePublisher { path.join(tempDir.absolute.path, getMetadataFilename(platform)), ); await _runGsUtil(['cp', gsPath, metadataFile.absolute.path]); - Map jsonData = {}; if (!dryRun) { final String currentMetadata = metadataFile.readAsStringSync(); if (currentMetadata.isEmpty) { throw PreparePackageException('Empty metadata received from server'); } + + Map jsonData; try { jsonData = json.decode(currentMetadata) as Map; } on FormatException catch (e) { throw PreparePackageException('Unable to parse JSON metadata received from cloud: $e'); } - } - // Run _addRelease, even on a dry run, so we can inspect the metadata on a - // dry run. On a dry run, the only thing in the metadata file be the new - // release. - jsonData = await _addRelease(jsonData); - const JsonEncoder encoder = JsonEncoder.withIndent(' '); - metadataFile.writeAsStringSync(encoder.convert(jsonData)); + jsonData = await _addRelease(jsonData); + + const JsonEncoder encoder = JsonEncoder.withIndent(' '); + metadataFile.writeAsStringSync(encoder.convert(jsonData)); + } await _cloudCopy( src: metadataFile.absolute.path, dest: gsPath, @@ -854,7 +832,7 @@ Future main(List rawArguments) async { int exitCode = 0; late String message; try { - final Map version = await creator.initializeRepo(); + final String version = await creator.initializeRepo(); final File outputFile = await creator.createArchive(); if (parsedArguments['publish'] as bool) { final ArchivePublisher publisher = ArchivePublisher( diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index ef7e4aa8325ca..6a554fa4b9c47 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -11,15 +11,15 @@ dependencies: path: ../devicelab http_parser: 4.0.0 meta: 1.7.0 - path: 1.8.1 - platform: 3.1.0 + path: 1.8.0 + platform: 3.0.2 process: 4.2.4 - test: 1.20.1 - archive: 3.1.8 + test: 1.17.12 _discoveryapis_commons: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" charcode: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,24 +31,25 @@ dependencies: equatable: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + gcloud: 0.8.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - googleapis_auth: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + googleapis_auth: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http: 0.13.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - json_annotation: 4.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + json_annotation: 4.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - metrics_center: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + metrics_center: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pubspec_parse: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pubspec_parse: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_static: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,15 +61,15 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test_api: 0.4.9 + test_api: 0.4.3 -# PUBSPEC CHECKSUM: 4c85 +# PUBSPEC CHECKSUM: d345 diff --git a/dev/bots/test.dart b/dev/bots/test.dart index fdc51b4e7b401..d767b4977ec7e 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -6,9 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:math' as math; -import 'dart:typed_data'; -import 'package:archive/archive.dart'; import 'package:file/file.dart' as fs; import 'package:file/local.dart'; import 'package:path/path.dart' as path; @@ -134,7 +132,6 @@ const Map> kWebTestFileKnownFailures = main(List args) async { try { flutterTestArgs.addAll(args); final Set removeArgs = {}; - bool runSmokeTests = true; for (final String arg in args) { if (arg.startsWith('--local-engine=')) { localEngineEnv['FLUTTER_LOCAL_ENGINE'] = arg.substring('--local-engine='.length); @@ -184,18 +180,12 @@ Future main(List args) async { _shuffleSeed = arg.substring('--test-randomize-ordering-seed='.length); removeArgs.add(arg); } - if (arg == '--no-smoke-tests') { - runSmokeTests = false; - removeArgs.add(arg); - } } flutterTestArgs.removeWhere((String arg) => removeArgs.contains(arg)); if (Platform.environment.containsKey(CIRRUS_TASK_NAME)) print('Running task: ${Platform.environment[CIRRUS_TASK_NAME]}'); print('═' * 80); - if (runSmokeTests) { - await _runSmokeTests(); - } + await _runSmokeTests(); print('═' * 80); await selectShard({ 'add_to_app_life_cycle_tests': _runAddToAppLifeCycleTests, @@ -222,19 +212,17 @@ Future main(List args) async { print('$clock ${bold}Test successful.$reset'); } -final String _luciBotId = Platform.environment['SWARMING_BOT_ID'] ?? ''; -final bool _runningInDartHHHBot = _luciBotId.startsWith('luci-dart-'); - /// Verify the Flutter Engine is the revision in /// bin/cache/internal/engine.version. Future _validateEngineHash() async { - if (_runningInDartHHHBot) { + final String luciBotId = Platform.environment['SWARMING_BOT_ID'] ?? ''; + if (luciBotId.startsWith('luci-dart-')) { // The Dart HHH bots intentionally modify the local artifact cache // and then use this script to run Flutter's test suites. // Because the artifacts have been changed, this particular test will return // a false positive and should be skipped. print('${yellow}Skipping Flutter Engine Version Validation for swarming ' - 'bot $_luciBotId.'); + 'bot $luciBotId.'); return; } final String expectedVersion = File(engineVersionFile).readAsStringSync().trim(); @@ -430,8 +418,6 @@ Future runForbiddenFromReleaseTests() async { '--snapshot', path.join(tempDirectory.path, 'snapshot.arm64-v8a.json'), '--package-config', path.join(flutterRoot, 'examples', 'hello_world', '.dart_tool', 'package_config.json'), '--forbidden-type', 'package:flutter/src/widgets/widget_inspector.dart::WidgetInspectorService', - '--forbidden-type', 'package:flutter/src/widgets/framework.dart::DebugCreator', - '--forbidden-type', 'package:flutter/src/foundation/print.dart::debugPrint', ]; await runCommand( dart, @@ -487,7 +473,7 @@ Future _runBuildTests() async { Future _runExampleProjectBuildTests(Directory exampleDirectory, [File? mainFile]) async { // Only verify caching with flutter gallery. final bool verifyCaching = exampleDirectory.path.contains('flutter_gallery'); - final String examplePath = path.relative(exampleDirectory.path, from: Directory.current.path); + final String examplePath = exampleDirectory.path; final bool hasNullSafety = File(path.join(examplePath, 'null_safety')).existsSync(); final List additionalArgs = [ if (hasNullSafety) '--no-sound-null-safety', @@ -710,12 +696,6 @@ Future _runFrameworkTests() async { options: ['--dart-define=dart.vm.product=true', ...soundNullSafetyOptions], tests: ['test_release${path.separator}'], ); - // Run profile mode tests (see packages/flutter/test_profile/README.md) - await _runFlutterTest( - path.join(flutterRoot, 'packages', 'flutter'), - options: ['--dart-define=dart.vm.product=false', '--dart-define=dart.vm.profile=true', ...soundNullSafetyOptions], - tests: ['test_profile${path.separator}'], - ); } Future runLibraries() async { @@ -754,89 +734,6 @@ Future _runFrameworkTests() async { await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'), options: soundNullSafetyOptions); } - Future runTracingTests() async { - final String tracingDirectory = path.join(flutterRoot, 'dev', 'tracing_tests'); - - // run the tests for debug mode - await _runFlutterTest(tracingDirectory, options: ['--enable-vmservice']); - - Future> verifyTracingAppBuild({ - required String modeArgument, - required String sourceFile, - required Set allowed, - required Set disallowed, - }) async { - await runCommand( - flutter, - [ - 'build', 'appbundle', '--$modeArgument', path.join('lib', sourceFile), - ], - workingDirectory: tracingDirectory, - ); - final Archive archive = ZipDecoder().decodeBytes(File(path.join(tracingDirectory, 'build', 'app', 'outputs', 'bundle', modeArgument, 'app-$modeArgument.aab')).readAsBytesSync()); - final ArchiveFile libapp = archive.findFile('base/lib/arm64-v8a/libapp.so')!; - final Uint8List libappBytes = libapp.content as Uint8List; // bytes decompressed here - final String libappStrings = utf8.decode(libappBytes, allowMalformed: true); - await runCommand(flutter, ['clean'], workingDirectory: tracingDirectory); - final List results = []; - for (final String pattern in allowed) { - if (!libappStrings.contains(pattern)) { - results.add('When building with --$modeArgument, expected to find "$pattern" in libapp.so but could not find it.'); - } - } - for (final String pattern in disallowed) { - if (libappStrings.contains(pattern)) { - results.add('When building with --$modeArgument, expected to not find "$pattern" in libapp.so but did find it.'); - } - } - return results; - } - - final List results = []; - results.addAll(await verifyTracingAppBuild( - modeArgument: 'profile', - sourceFile: 'control.dart', // this is the control, the other two below are the actual test - allowed: { - 'TIMELINE ARGUMENTS TEST CONTROL FILE', - 'toTimelineArguments used in non-debug build', // we call toTimelineArguments directly to check the message does exist - }, - disallowed: { - 'BUILT IN DEBUG MODE', 'BUILT IN RELEASE MODE', - }, - )); - results.addAll(await verifyTracingAppBuild( - modeArgument: 'profile', - sourceFile: 'test.dart', - allowed: { - 'BUILT IN PROFILE MODE', 'RenderTest.performResize called', // controls - 'BUILD', 'LAYOUT', 'PAINT', // we output these to the timeline in profile builds - // (LAYOUT and PAINT also exist because of NEEDS-LAYOUT and NEEDS-PAINT in RenderObject.toStringShort) - }, - disallowed: { - 'BUILT IN DEBUG MODE', 'BUILT IN RELEASE MODE', - 'TestWidget.debugFillProperties called', 'RenderTest.debugFillProperties called', // debug only - 'toTimelineArguments used in non-debug build', // entire function should get dropped by tree shaker - }, - )); - results.addAll(await verifyTracingAppBuild( - modeArgument: 'release', - sourceFile: 'test.dart', - allowed: { - 'BUILT IN RELEASE MODE', 'RenderTest.performResize called', // controls - }, - disallowed: { - 'BUILT IN DEBUG MODE', 'BUILT IN PROFILE MODE', - 'BUILD', 'LAYOUT', 'PAINT', // these are only used in Timeline.startSync calls that should not appear in release builds - 'TestWidget.debugFillProperties called', 'RenderTest.debugFillProperties called', // debug only - 'toTimelineArguments used in non-debug build', // not included in release builds - }, - )); - if (results.isNotEmpty) { - print(results.join('\n')); - exit(1); - } - } - Future runFixTests() async { final List args = [ 'fix', @@ -855,17 +752,30 @@ Future _runFrameworkTests() async { '--sound-null-safety', 'test_private.dart', ]; - final Map environment = { + final Map pubEnvironment = { 'FLUTTER_ROOT': flutterRoot, - if (Directory(pubCache).existsSync()) - 'PUB_CACHE': pubCache, }; - adjustEnvironmentToEnableFlutterAsserts(environment); + if (Directory(pubCache).existsSync()) { + pubEnvironment['PUB_CACHE'] = pubCache; + } + + // If an existing env variable exists append to it, but only if + // it doesn't appear to already include enable-asserts. + String toolsArgs = Platform.environment['FLUTTER_TOOL_ARGS'] ?? ''; + if (!toolsArgs.contains('--enable-asserts')) { + toolsArgs += ' --enable-asserts'; + } + pubEnvironment['FLUTTER_TOOL_ARGS'] = toolsArgs.trim(); + // The flutter_tool will originally have been snapshotted without asserts. + // We need to force it to be regenerated with them enabled. + deleteFile(path.join(flutterRoot, 'bin', 'cache', 'flutter_tools.snapshot')); + deleteFile(path.join(flutterRoot, 'bin', 'cache', 'flutter_tools.stamp')); + await runCommand( pub, args, workingDirectory: path.join(flutterRoot, 'packages', 'flutter', 'test_private'), - environment: environment, + environment: pubEnvironment, ); } @@ -875,11 +785,9 @@ Future _runFrameworkTests() async { await _pubRunTest(path.join(flutterRoot, 'dev', 'bots')); await _pubRunTest(path.join(flutterRoot, 'dev', 'devicelab'), ensurePrecompiledTool: false); // See https://github.com/flutter/flutter/issues/86209 await _pubRunTest(path.join(flutterRoot, 'dev', 'conductor', 'core'), forceSingleCore: true); - // TODO(gspencergoog): Remove the exception for fatalWarnings once https://github.com/flutter/flutter/pull/91127 has landed. - await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'), fatalWarnings: false); + await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing')); await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests')); await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'vitool')); - await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'gen_defaults')); await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'gen_keycodes')); await _runFlutterTest(path.join(flutterRoot, 'dev', 'benchmarks', 'test_apps', 'stocks')); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tests: [path.join('test', 'src', 'real_tests')], options: soundNullSafetyOptions); @@ -889,7 +797,10 @@ Future _runFrameworkTests() async { await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), options: soundNullSafetyOptions); await _runFlutterTest(path.join(flutterRoot, 'packages', 'fuchsia_remote_debug_protocol'), options: soundNullSafetyOptions); await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable'), options: mixedModeNullSafetyOptions); - await runTracingTests(); + await _runFlutterTest( + path.join(flutterRoot, 'dev', 'tracing_tests'), + options: ['--enable-vmservice'], + ); await runFixTests(); await runPrivateTests(); const String httpClientWarning = @@ -1532,10 +1443,6 @@ Future _runWebDebugTest(String target, { }) async { final String testAppDirectory = path.join(flutterRoot, 'dev', 'integration_tests', 'web'); bool success = false; - final Map environment = { - 'FLUTTER_WEB': 'true', - }; - adjustEnvironmentToEnableFlutterAsserts(environment); final CommandResult result = await runCommand( flutter, [ @@ -1565,7 +1472,9 @@ Future _runWebDebugTest(String target, { } }, workingDirectory: testAppDirectory, - environment: environment, + environment: { + 'FLUTTER_WEB': 'true', + }, ); if (success) { @@ -1588,7 +1497,6 @@ Future _runFlutterWebTest(String webRenderer, String workingDirectory, Lis '-v', '--platform=chrome', '--web-renderer=$webRenderer', - '--dart-define=DART_HHH_BOT=$_runningInDartHHHBot', '--sound-null-safety', ...flutterTestArgs, ...tests, @@ -1653,21 +1561,30 @@ Future _pubRunTest(String workingDirectory, { for (final String testPath in testPaths) testPath, ]; - final Map environment = { + final Map pubEnvironment = { 'FLUTTER_ROOT': flutterRoot, - if (includeLocalEngineEnv) - ...localEngineEnv, - if (Directory(pubCache).existsSync()) - 'PUB_CACHE': pubCache, + if (includeLocalEngineEnv) ...localEngineEnv, }; + if (Directory(pubCache).existsSync()) { + pubEnvironment['PUB_CACHE'] = pubCache; + } if (enableFlutterToolAsserts) { - adjustEnvironmentToEnableFlutterAsserts(environment); + // If an existing env variable exists append to it, but only if + // it doesn't appear to already include enable-asserts. + String toolsArgs = Platform.environment['FLUTTER_TOOL_ARGS'] ?? ''; + if (!toolsArgs.contains('--enable-asserts')) + toolsArgs += ' --enable-asserts'; + pubEnvironment['FLUTTER_TOOL_ARGS'] = toolsArgs.trim(); + // The flutter_tool will originally have been snapshotted without asserts. + // We need to force it to be regenerated with them enabled. + deleteFile(path.join(flutterRoot, 'bin', 'cache', 'flutter_tools.snapshot')); + deleteFile(path.join(flutterRoot, 'bin', 'cache', 'flutter_tools.stamp')); } if (ensurePrecompiledTool) { // We rerun the `flutter` tool here just to make sure that it is compiled // before tests run, because the tests might time out if they have to rebuild // the tool themselves. - await runCommand(flutter, ['--version'], environment: environment); + await runCommand(flutter, ['--version'], environment: pubEnvironment); } if (useFlutterTestFormatter) { final FlutterCompactFormatter formatter = FlutterCompactFormatter(); @@ -1677,7 +1594,7 @@ Future _pubRunTest(String workingDirectory, { pub, args, workingDirectory: workingDirectory, - environment: environment, + environment: pubEnvironment, ); } finally { formatter.finish(); @@ -1688,7 +1605,7 @@ Future _pubRunTest(String workingDirectory, { pub, args, workingDirectory: workingDirectory, - environment: environment, + environment: pubEnvironment, removeLine: useBuildRunner ? (String line) => line.startsWith('[INFO]') : null, ); } @@ -1703,7 +1620,6 @@ Future _runFlutterTest(String workingDirectory, { Map? environment, List tests = const [], bool shuffleTests = true, - bool fatalWarnings = true, }) async { assert(!printOutput || outputChecker == null, 'Output either can be printed or checked but not both'); @@ -1717,7 +1633,6 @@ Future _runFlutterTest(String workingDirectory, { final List args = [ 'test', if (shuffleTests) '--test-randomize-ordering-seed=$shuffleSeed', - if (fatalWarnings) '--fatal-warnings', ...options, ...tags, ...flutterTestArgs, @@ -1789,18 +1704,6 @@ Future _runFlutterTest(String workingDirectory, { } } -/// This will force the next run of the Flutter tool (if it uses the provided -/// environment) to have asserts enabled, by setting an environment variable. -void adjustEnvironmentToEnableFlutterAsserts(Map environment) { - // If an existing env variable exists append to it, but only if - // it doesn't appear to already include enable-asserts. - String toolsArgs = Platform.environment['FLUTTER_TOOL_ARGS'] ?? ''; - if (!toolsArgs.contains('--enable-asserts')) { - toolsArgs += ' --enable-asserts'; - } - environment['FLUTTER_TOOL_ARGS'] = toolsArgs.trim(); -} - Map _initGradleEnvironment() { final String? androidSdkRoot = (Platform.environment['ANDROID_HOME']?.isEmpty ?? true) ? Platform.environment['ANDROID_SDK_ROOT'] diff --git a/dev/bots/test/analyze-test-input/root/packages/flutter/lib/bar.dart b/dev/bots/test/analyze-test-input/root/packages/flutter/lib/bar.dart deleted file mode 100644 index 52fe6897a0eb6..0000000000000 --- a/dev/bots/test/analyze-test-input/root/packages/flutter/lib/bar.dart +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -class _DebugOnly { - const _DebugOnly(); -} - -const _DebugOnly _debugOnly = _DebugOnly(); -const bool kDebugMode = bool.fromEnvironment('test-only'); - -class Foo { - @_debugOnly - final Map? foo = kDebugMode ? {} : null; - - @_debugOnly - final Map? bar = kDebugMode ? null : {}; -} diff --git a/dev/bots/test/analyze_test.dart b/dev/bots/test/analyze_test.dart index 1d6668e0f010d..04e6a4b61e856 100644 --- a/dev/bots/test/analyze_test.dart +++ b/dev/bots/test/analyze_test.dart @@ -120,21 +120,18 @@ void main() { test('analyze.dart - verifyNoMissingLicense', () async { final String result = await capture(() => verifyNoMissingLicense(testRootPath, checkMinimums: false), exitCode: 1); - final String file = 'test/analyze-test-input/root/packages/foo/foo.dart' + final String lines = 'test/analyze-test-input/root/packages/foo/foo.dart' .replaceAll('/', Platform.isWindows ? r'\' : '/'); expect(result, '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' - 'The following file does not have the right license header for dart files:\n' - ' $file\n' + 'The following 1 file does not have the right license header:\n' + '$lines\n' 'The expected license header is:\n' '// Copyright 2014 The Flutter Authors. All rights reserved.\n' '// Use of this source code is governed by a BSD-style license that can be\n' '// found in the LICENSE file.\n' '...followed by a blank line.\n' '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' - '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' - 'License check failed.\n' - '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' ); }); @@ -159,7 +156,9 @@ void main() { legacyBinaries: {const Hash256(0x39A050CD69434936, 0, 0, 0)}, ), exitCode: Platform.isWindows ? 0 : 1); if (!Platform.isWindows) { - expect(result, + // The output starts with the call to git ls-files, the details of which + // change from run to run, so we only check the trailing end of the output. + expect(result, endsWith('\n' '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' 'test/analyze-test-input/root/packages/foo/serviceaccount.enc:0: file is not valid UTF-8\n' 'All files in this repository must be UTF-8. In particular, images and other binaries\n' @@ -168,7 +167,7 @@ void main() { 'to which you need access, you should consider how to fetch it from another repository;\n' 'for example, the "assets-for-api-docs" repository is used for images in API docs.\n' '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' - ); + )); } }); @@ -196,14 +195,4 @@ void main() { }, )); }); - - test('analyze.dart - verifyNullInitializedDebugExpensiveFields', () async { - final String result = await capture(() => verifyNullInitializedDebugExpensiveFields( - testRootPath, - minimumMatches: 1, - ), exitCode: 1); - - expect(result, contains('L15')); - expect(result, isNot(contains('L12'))); - }); } diff --git a/dev/bots/test/prepare_package_test.dart b/dev/bots/test/prepare_package_test.dart index 2c4e9cd512987..d1f89aed93938 100644 --- a/dev/bots/test/prepare_package_test.dart +++ b/dev/bots/test/prepare_package_test.dart @@ -7,7 +7,7 @@ import 'dart:io' hide Platform; import 'dart:typed_data'; import 'package:path/path.dart' as path; -import 'package:platform/platform.dart' show FakePlatform, Platform; +import 'package:platform/platform.dart' show FakePlatform; import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; import '../prepare_package.dart'; @@ -34,7 +34,7 @@ void main() { )), ); }); - for (final String platformName in [Platform.macOS, Platform.linux, Platform.windows]) { + for (final String platformName in ['macos', 'linux', 'windows']) { final FakePlatform platform = FakePlatform( operatingSystem: platformName, environment: { @@ -123,10 +123,6 @@ void main() { 'git reset --hard $testRef': null, 'git remote set-url origin https://github.com/flutter/flutter.git': null, 'git describe --tags --exact-match $testRef': [ProcessResult(0, 0, 'v1.2.3', '')], - '$flutter --version --machine': [ - ProcessResult(0, 0, '{"dartSdkVersion": "3.2.1"}', ''), - ProcessResult(0, 0, '{"dartSdkVersion": "3.2.1"}', ''), - ], if (platform.isWindows) '7za x ${path.join(tempDir.path, 'mingit.zip')}': null, '$flutter doctor': null, '$flutter update-packages': null, @@ -156,10 +152,6 @@ void main() { 'git reset --hard $testRef': null, 'git remote set-url origin https://github.com/flutter/flutter.git': null, 'git describe --tags --exact-match $testRef': [ProcessResult(0, 0, 'v1.2.3', '')], - '$flutter --version --machine': [ - ProcessResult(0, 0, '{"dartSdkVersion": "3.2.1"}', ''), - ProcessResult(0, 0, '{"dartSdkVersion": "3.2.1"}', ''), - ], if (platform.isWindows) '7za x ${path.join(tempDir.path, 'mingit.zip')}': null, '$flutter doctor': null, '$flutter update-packages': null, @@ -210,10 +202,6 @@ void main() { 'git reset --hard $testRef': null, 'git remote set-url origin https://github.com/flutter/flutter.git': null, 'git describe --tags --abbrev=0 $testRef': [ProcessResult(0, 0, 'v1.2.3', '')], - '$flutter --version --machine': [ - ProcessResult(0, 0, '{"dartSdkVersion": "3.2.1"}', ''), - ProcessResult(0, 0, '{"dartSdkVersion": "3.2.1"}', ''), - ], if (platform.isWindows) '7za x ${path.join(tempDir.path, 'mingit.zip')}': null, '$flutter doctor': null, '$flutter update-packages': null, @@ -256,10 +244,6 @@ void main() { 'git reset --hard $testRef': null, 'git remote set-url origin https://github.com/flutter/flutter.git': null, 'git describe --tags --exact-match $testRef': [ProcessResult(0, 0, 'v1.2.3', '')], - '$flutter --version --machine': [ - ProcessResult(0, 0, '{"dartSdkVersion": "3.2.1"}', ''), - ProcessResult(0, 0, '{"dartSdkVersion": "3.2.1"}', ''), - ], if (platform.isWindows) '7za x ${path.join(tempDir.path, 'mingit.zip')}': null, '$flutter doctor': null, '$flutter update-packages': null, @@ -378,7 +362,7 @@ void main() { tempDir, testRef, Branch.stable, - {'frameworkVersionFromGit': 'v1.2.3', 'dartSdkVersion': '3.2.1'}, + 'v1.2.3', outputFile, false, processManager: processManager, @@ -474,7 +458,7 @@ void main() { tempDir, testRef, Branch.stable, - {'frameworkVersionFromGit': 'v1.2.3', 'dartSdkVersion': '3.2.1'}, + 'v1.2.3', outputFile, false, processManager: processManager, @@ -498,7 +482,7 @@ void main() { tempDir, testRef, Branch.stable, - {'frameworkVersionFromGit': 'v1.2.3', 'dartSdkVersion': '3.2.1'}, + 'v1.2.3', outputFile, false, processManager: processManager, @@ -520,7 +504,7 @@ void main() { tempDir, testRef, Branch.stable, - {'frameworkVersionFromGit': 'v1.2.3', 'dartSdkVersion': '3.2.1'}, + 'v1.2.3', outputFile, false, processManager: processManager, diff --git a/dev/conductor/README.md b/dev/conductor/README.md index 54b34793125ab..6a38d5eb415dd 100644 --- a/dev/conductor/README.md +++ b/dev/conductor/README.md @@ -15,14 +15,6 @@ Some basic requirements to conduct a release are: [framework](https://github.com/flutter/flutter) and [engine](https://github.com/flutter/engine) repositories. -For the best experience, it is recommended to use ssh protocol for connecting to -GitHub remote repositories (i.e. for `--framework-mirror` and `--engine-mirror` -specify the remote with the format `git@github.com:username/reponame`). If your -local ssh key is password-protected, it is recommended to use ssh-agent to -unlock your ssh key for the session; if you do not, each time the conductor -attempts to interact with a remote, the user will be prompted to enter their ssh -key password. - ## Usage The main entrypoint for the conductor is [bin/conductor](bin/conductor). For @@ -49,17 +41,11 @@ conductor start \ For more details on these command line arguments, see `conductor help start`. This command will write to disk a state file that will persist until the release -is completed. If you already have a persistent state file, this command will -fail with an error message. To see the current status of the release (at any -time), issue the command: +is completed. To see the current status of the release (at any time), issue the +command: `conductor status` -To delete a persistent state file (either because the release was successfully -completed or abandoned), use the command: - -`conductor clean` - Once initializing the release, the conductor tool will issue instructions for manual steps that must be executed by the user. At any time these instructions can be seen via `conductor status`. Once these manual steps have been completed, @@ -67,6 +53,11 @@ you can proceed to the next step by using the command: `conductor next` +Upon successful completion of the release, the following command will remove the +persistent state file: + +`conductor clean` + ## Steps Once the user has finished manual steps for each step, they proceed to the next @@ -104,19 +95,15 @@ $REVISION`) and resolve the merge conflict in their checkout. ### Publish Version This step will add a version git tag to the final Framework commit and push it -to the upstream repository. The presence of a tag affects what the flutter CLI -tool reports the current version is. +to the upstream repository. ### Publish Channel This step will push the Framework candidate branch to the upstream release -branch (e.g. the `stable` branch). Once this push happens upstream, the release -has officially been published, and the code will be available to existing -Flutter users via `flutter upgrade`. +branch. ### Verify Release For the final step, the user must manually verify that packaging builds have -finished successfully. The SDK compressed archives will not be available from -the website until the packaging build has finished. The conductor will produce -links to the dashboards for monitoring CI builds. +finished successfully. The conductor will produce links to the dashboards for +monitoring CI builds. diff --git a/dev/conductor/core/bin/cli.dart b/dev/conductor/core/bin/cli.dart index 0e86f13c79b95..f3770dbf05cea 100644 --- a/dev/conductor/core/bin/cli.dart +++ b/dev/conductor/core/bin/cli.dart @@ -46,6 +46,12 @@ Future main(List args) async { )).trim(); >[ + RollDevCommand( + checkouts: checkouts, + fileSystem: fileSystem, + platform: platform, + stdio: stdio, + ), CodesignCommand( checkouts: checkouts, flutterRoot: _localFlutterRoot, diff --git a/dev/conductor/core/lib/conductor_core.dart b/dev/conductor/core/lib/conductor_core.dart index f1203be73f07d..9bb127659af8d 100644 --- a/dev/conductor/core/lib/conductor_core.dart +++ b/dev/conductor/core/lib/conductor_core.dart @@ -11,6 +11,7 @@ export 'src/git.dart'; export 'src/globals.dart'; export 'src/next.dart' hide kStateOption, kYesFlag; export 'src/repository.dart'; +export 'src/roll_dev.dart'; export 'src/start.dart' hide kStateOption; export 'src/state.dart'; export 'src/status.dart' hide kStateOption; diff --git a/dev/conductor/core/lib/src/clean.dart b/dev/conductor/core/lib/src/clean.dart index 7ff71310eddba..30324bc20d399 100644 --- a/dev/conductor/core/lib/src/clean.dart +++ b/dev/conductor/core/lib/src/clean.dart @@ -49,11 +49,12 @@ class CleanCommand extends Command { 'This will abort a work in progress release.'; @override - Future run() { + void run() { final ArgResults argumentResults = argResults!; final File stateFile = checkouts.fileSystem.file(argumentResults[kStateOption]); if (!stateFile.existsSync()) { - throw ConductorException('No persistent state file found at ${stateFile.path}!'); + throw ConductorException( + 'No persistent state file found at ${stateFile.path}!'); } if (!(argumentResults[kYesFlag] as bool)) { @@ -66,28 +67,10 @@ class CleanCommand extends Command { // Only proceed if the first character of stdin is 'y' or 'Y' if (response.isEmpty || response[0].toLowerCase() != 'y') { stdio.printStatus('Aborting clean operation.'); + return; } } stdio.printStatus('Deleting persistent state file ${stateFile.path}...'); - - final CleanContext cleanContext = CleanContext( - stateFile: stateFile, - ); - return cleanContext.run(); - } -} - -/// Context for cleaning up persistent state file. -/// -/// This is a frontend-agnostic implementation. -class CleanContext { - CleanContext({ - required this.stateFile, - }); - - final File stateFile; - - Future run() { - return stateFile.delete(); + stateFile.deleteSync(); } } diff --git a/dev/conductor/core/lib/src/codesign.dart b/dev/conductor/core/lib/src/codesign.dart index 8fa00992c9b5a..7622551b33a16 100644 --- a/dev/conductor/core/lib/src/codesign.dart +++ b/dev/conductor/core/lib/src/codesign.dart @@ -43,13 +43,15 @@ class CodesignCommand extends Command { } argParser.addFlag( kVerify, - help: 'Only verify expected binaries exist and are codesigned with entitlements.', + help: + 'Only verify expected binaries exist and are codesigned with entitlements.', ); argParser.addFlag( kSignatures, defaultsTo: true, - help: 'When off, this command will only verify the existence of binaries, and not their\n' - 'signatures or entitlements. Must be used with --verify flag.', + help: + 'When off, this command will only verify the existence of binaries, and not their\n' + 'signatures or entitlements. Must be used with --verify flag.', ); argParser.addOption( kUpstream, @@ -90,25 +92,24 @@ class CodesignCommand extends Command { Future run() async { if (!platform.isMacOS) { throw ConductorException( - 'Error! Expected operating system "macos", actual operating system is: ' - '"${platform.operatingSystem}"', - ); + 'Error! Expected operating system "macos", actual operating system is: ' + '"${platform.operatingSystem}"'); } if (argResults!['verify'] as bool != true) { throw ConductorException( - 'Sorry, but codesigning is not implemented yet. Please pass the ' - '--$kVerify flag to verify signatures.', - ); + 'Sorry, but codesigning is not implemented yet. Please pass the ' + '--$kVerify flag to verify signatures.'); } String revision; if (argResults!.wasParsed(kRevision)) { - stdio.printWarning( - 'Warning! When providing an arbitrary revision, the contents of the cache may not ' - 'match the expected binaries in the conductor tool. It is preferred to check out ' - 'the desired revision and run that version of the conductor.\n', - ); + stdio.printError( + 'Warning! When providing an arbitrary revision, the contents of the cache may not'); + stdio.printError( + 'match the expected binaries in the conductor tool. It is preferred to check out'); + stdio.printError( + 'the desired revision and run that version of the conductor.\n'); revision = argResults![kRevision] as String; } else { revision = ((await processManager.run( @@ -224,11 +225,13 @@ class CodesignCommand extends Command { ) .toList(); stdio.printError( - 'Expected binaries not found in cache:\n\n${unfoundFiles.join('\n')}\n\n' - 'If this commit is removing binaries from the cache, this test should be fixed by\n' - 'removing the relevant entry from either the "binariesWithEntitlements" or\n' - '"binariesWithoutEntitlements" getters in dev/tools/lib/codesign.dart.', - ); + 'Expected binaries not found in cache:\n\n${unfoundFiles.join('\n')}\n'); + stdio.printError( + 'If this commit is removing binaries from the cache, this test should be fixed by'); + stdio.printError( + 'removing the relevant entry from either the `binariesWithEntitlements` or'); + stdio.printError( + '`binariesWithoutEntitlements` getters in dev/tools/lib/codesign.dart.'); throw ConductorException('Did not find all expected binaries!'); } @@ -268,10 +271,9 @@ class CodesignCommand extends Command { if (codeSignResult.exitCode != 0) { unsignedBinaries.add(binaryPath); stdio.printError( - 'File "$binaryPath" does not appear to be codesigned.\n' - 'The `codesign` command failed with exit code ${codeSignResult.exitCode}:\n' - '${codeSignResult.stderr}\n', - ); + 'File "$binaryPath" does not appear to be codesigned.\n' + 'The `codesign` command failed with exit code ${codeSignResult.exitCode}:\n' + '${codeSignResult.stderr}\n'); continue; } if (verifyEntitlements) { @@ -289,39 +291,42 @@ class CodesignCommand extends Command { } if (wrongEntitlementBinaries.isNotEmpty) { - stdio.printError('Found ${wrongEntitlementBinaries.length} binaries with unexpected entitlements:'); + stdio.printError( + 'Found ${wrongEntitlementBinaries.length} binaries with unexpected entitlements:'); wrongEntitlementBinaries.forEach(stdio.printError); } if (unexpectedBinaries.isNotEmpty) { - stdio.printError('Found ${unexpectedBinaries.length} unexpected binaries in the cache:'); + stdio.printError( + 'Found ${unexpectedBinaries.length} unexpected binaries in the cache:'); unexpectedBinaries.forEach(print); } // Finally, exit on any invalid state if (unsignedBinaries.isNotEmpty) { - throw ConductorException('Test failed because unsigned binaries detected.'); + throw ConductorException( + 'Test failed because unsigned binaries detected.'); } if (wrongEntitlementBinaries.isNotEmpty) { throw ConductorException( - 'Test failed because files found with the wrong entitlements:\n' - '${wrongEntitlementBinaries.join('\n')}', - ); + 'Test failed because files found with the wrong entitlements:\n' + '${wrongEntitlementBinaries.join('\n')}'); } if (unexpectedBinaries.isNotEmpty) { - throw ConductorException('Test failed because unexpected binaries found in the cache.'); + throw ConductorException( + 'Test failed because unexpected binaries found in the cache.'); } final String? desiredRevision = argResults![kRevision] as String?; if (desiredRevision == null) { - stdio.printStatus('Verified that binaries are codesigned and have expected entitlements.'); + stdio.printStatus( + 'Verified that binaries are codesigned and have expected entitlements.'); } else { stdio.printStatus( - 'Verified that binaries for commit $desiredRevision are codesigned and have ' - 'expected entitlements.', - ); + 'Verified that binaries for commit $desiredRevision are codesigned and have ' + 'expected entitlements.'); } } @@ -382,9 +387,8 @@ class CodesignCommand extends Command { if (entitlementResult.exitCode != 0) { stdio.printError( - 'The `codesign --entitlements` command failed with exit code ${entitlementResult.exitCode}:\n' - '${entitlementResult.stderr}\n', - ); + 'The `codesign --entitlements` command failed with exit code ${entitlementResult.exitCode}:\n' + '${entitlementResult.stderr}\n'); return false; } @@ -395,9 +399,8 @@ class CodesignCommand extends Command { (await binariesWithEntitlements).contains(binaryPath); if (output.contains(entitlement) != entitlementExpected) { stdio.printError( - 'File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} ' - 'entitlement $entitlement.', - ); + 'File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} ' + 'entitlement $entitlement.'); passes = false; } } diff --git a/dev/conductor/core/lib/src/context.dart b/dev/conductor/core/lib/src/context.dart deleted file mode 100644 index e15b9c0939d01..0000000000000 --- a/dev/conductor/core/lib/src/context.dart +++ /dev/null @@ -1,54 +0,0 @@ -// 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 'package:file/file.dart' show File; - -import 'globals.dart'; -import 'proto/conductor_state.pb.dart' as pb; -import 'repository.dart'; -import 'state.dart'; -import 'stdio.dart' show Stdio; - -/// Interface for shared functionality across all sub-commands. -/// -/// Different frontends (e.g. CLI vs desktop) can share [Context]s, although -/// methods for capturing user interaction may be overridden. -abstract class Context { - const Context({ - required this.checkouts, - required this.stateFile, - }); - - final Checkouts checkouts; - final File stateFile; - Stdio get stdio => checkouts.stdio; - - /// Confirm an action with the user before proceeding. - /// - /// The default implementation reads from STDIN. This can be overriden in UI - /// implementations that capture user interaction differently. - Future prompt(String message) async { - stdio.write('${message.trim()} (y/n) '); - final String response = stdio.readLineSync().trim(); - final String firstChar = response[0].toUpperCase(); - if (firstChar == 'Y') { - return true; - } - if (firstChar == 'N') { - return false; - } - throw ConductorException( - 'Unknown user input (expected "y" or "n"): $response', - ); - } - - /// Save the release's [state]. - /// - /// This can be overridden by frontends that may not persist the state to - /// disk, and/or may need to call additional update hooks each time the state - /// is updated. - void updateState(pb.ConductorState state, [List logs = const []]) { - writeStateToFile(stateFile, state, logs); - } -} diff --git a/dev/conductor/core/lib/src/git.dart b/dev/conductor/core/lib/src/git.dart index 7fb5addc0c6f0..5d39e2781c240 100644 --- a/dev/conductor/core/lib/src/git.dart +++ b/dev/conductor/core/lib/src/git.dart @@ -33,12 +33,7 @@ class Git { bool allowNonZeroExitCode = false, required String workingDirectory, }) async { - late final ProcessResult result; - try { - result = await _run(args, workingDirectory); - } on ProcessException { - _reportFailureAndExit(args, workingDirectory, result, explanation); - } + final ProcessResult result = await _run(args, workingDirectory); if (result.exitCode != 0 && !allowNonZeroExitCode) { _reportFailureAndExit(args, workingDirectory, result, explanation); } @@ -74,55 +69,15 @@ class Git { if ((result.stderr as String).isNotEmpty) { message.writeln('stderr from git:\n${result.stderr}\n'); } - throw GitException(message.toString(), args); + throw GitException(message.toString()); } } -enum GitExceptionType { - /// Git push failed because the remote branch contained commits the local did - /// not. - /// - /// Either the local branch was wrong, and needs a rebase before pushing - /// again, or the remote branch needs to be overwritten with a force push. - /// - /// Example output: - /// - /// ``` - /// To github.com:user/engine.git - /// - /// ! [rejected] HEAD -> cherrypicks-flutter-2.8-candidate.3 (non-fast-forward) - /// error: failed to push some refs to 'github.com:user/engine.git' - /// hint: Updates were rejected because the tip of your current branch is behind - /// hint: its remote counterpart. Integrate the remote changes (e.g. - /// hint: 'git pull ...') before pushing again. - /// hint: See the 'Note about fast-forwards' in 'git push --help' for details. - /// ``` - PushRejected, -} - -/// An exception created because a git subprocess failed. -/// -/// Known git failures will be assigned a [GitExceptionType] in the [type] -/// field. If this field is null it means and unknown git failure. class GitException implements Exception { - GitException(this.message, this.args) { - if (_pushRejectedPattern.hasMatch(message)) { - type = GitExceptionType.PushRejected; - } else { - // because type is late final, it must be explicitly set before it is - // accessed. - type = null; - } - } - - static final RegExp _pushRejectedPattern = RegExp( - r'Updates were rejected because the tip of your current branch is behind', - ); + GitException(this.message); final String message; - final List args; - late final GitExceptionType? type; @override - String toString() => 'Exception on command "${args.join(' ')}": $message'; + String toString() => 'Exception: $message'; } diff --git a/dev/conductor/core/lib/src/globals.dart b/dev/conductor/core/lib/src/globals.dart index b0a5d25afb8d4..82396c9df17a5 100644 --- a/dev/conductor/core/lib/src/globals.dart +++ b/dev/conductor/core/lib/src/globals.dart @@ -5,33 +5,24 @@ import 'package:args/args.dart'; import 'proto/conductor_state.pb.dart' as pb; -import 'repository.dart'; const String gsutilBinary = 'gsutil.py'; -const String kFrameworkDefaultBranch = 'master'; -const String kForceFlag = 'force'; - -const List kBaseReleaseChannels = ['stable', 'beta', 'dev']; - -const List kReleaseChannels = [...kBaseReleaseChannels, FrameworkRepository.defaultBranch]; - -const List kReleaseIncrements = ['y', 'z', 'm', 'n']; +const List kReleaseChannels = [ + 'stable', + 'beta', + 'dev', + 'master', +]; const String kReleaseDocumentationUrl = 'https://github.com/flutter/flutter/wiki/Flutter-Cherrypick-Process'; const String kLuciPackagingConsoleLink = 'https://ci.chromium.org/p/flutter/g/packaging/console'; -const String kWebsiteReleasesUrl = 'https://docs.flutter.dev/development/tools/sdk/releases'; - final RegExp releaseCandidateBranchRegex = RegExp( r'flutter-(\d+)\.(\d+)-candidate\.(\d+)', ); -/// Whether all releases published to the beta channel should be mirrored to -/// dev. -const bool kSynchronizeDevWithBeta = true; - /// Cast a dynamic to String and trim. String stdoutToString(dynamic input) { final String str = input as String; @@ -83,20 +74,9 @@ String? getValueFromEnvOrArgs( if (allowNull) { return null; } - throw ConductorException('Expected either the CLI arg --$name or the environment variable $envName ' - 'to be provided!'); -} - -bool getBoolFromEnvOrArgs( - String name, - ArgResults argResults, - Map env, -) { - final String envName = fromArgToEnvName(name); - if (env[envName] != null) { - return (env[envName]?.toUpperCase()) == 'TRUE'; - } - return argResults[name] as bool; + throw ConductorException( + 'Expected either the CLI arg --$name or the environment variable $envName ' + 'to be provided!'); } /// Return multiple values from the environment or fall back to [argResults]. @@ -122,8 +102,9 @@ List getValuesFromEnvOrArgs( return argValues; } - throw ConductorException('Expected either the CLI arg --$name or the environment variable $envName ' - 'to be provided!'); + throw ConductorException( + 'Expected either the CLI arg --$name or the environment variable $envName ' + 'to be provided!'); } /// Translate CLI arg names to env variable names. diff --git a/dev/conductor/core/lib/src/next.dart b/dev/conductor/core/lib/src/next.dart index 258706c1d32fb..1b1937af335b2 100644 --- a/dev/conductor/core/lib/src/next.dart +++ b/dev/conductor/core/lib/src/next.dart @@ -4,18 +4,17 @@ import 'package:args/command_runner.dart'; import 'package:file/file.dart' show File; -import 'package:meta/meta.dart' show visibleForTesting; - -import 'context.dart'; -import 'git.dart'; -import 'globals.dart'; -import 'proto/conductor_state.pb.dart' as pb; -import 'proto/conductor_state.pbenum.dart'; -import 'repository.dart'; -import 'state.dart' as state_import; +import 'package:meta/meta.dart' show visibleForTesting, visibleForOverriding; +import './globals.dart'; +import './proto/conductor_state.pb.dart' as pb; +import './proto/conductor_state.pbenum.dart'; +import './repository.dart'; +import './state.dart' as state_import; +import './stdio.dart'; const String kStateOption = 'state-file'; const String kYesFlag = 'yes'; +const String kForceFlag = 'force'; /// Command to proceed from one [pb.ReleasePhase] to the next. class NextCommand extends Command { @@ -48,21 +47,13 @@ class NextCommand extends Command { String get description => 'Proceed to the next release phase.'; @override - Future run() { - final File stateFile = checkouts.fileSystem.file(argResults![kStateOption]); - if (!stateFile.existsSync()) { - throw ConductorException( - 'No persistent state file found at ${stateFile.path}.', - ); - } - final pb.ConductorState state = state_import.readStateFromFile(stateFile); - - return NextContext( + Future run() async { + await NextContext( autoAccept: argResults![kYesFlag] as bool, checkouts: checkouts, force: argResults![kForceFlag] as bool, - stateFile: stateFile, - ).run(state); + stateFile: checkouts.fileSystem.file(argResults![kStateOption]), + ).run(); } } @@ -70,25 +61,33 @@ class NextCommand extends Command { /// /// Any calls to functions that cause side effects are wrapped in methods to /// allow overriding in unit tests. -class NextContext extends Context { - const NextContext({ +class NextContext { + NextContext({ required this.autoAccept, required this.force, - required Checkouts checkouts, - required File stateFile, - }) : super( - checkouts: checkouts, - stateFile: stateFile, - ); + required this.checkouts, + required this.stateFile, + }); final bool autoAccept; final bool force; + final Checkouts checkouts; + final File stateFile; - Future run(pb.ConductorState state) async { + Future run() async { + final Stdio stdio = checkouts.stdio; const List finishedStates = [ CherrypickState.COMPLETED, CherrypickState.ABANDONED, ]; + if (!stateFile.existsSync()) { + throw ConductorException( + 'No persistent state file found at ${stateFile.path}.', + ); + } + + final pb.ConductorState state = readStateFromFile(stateFile); + switch (state.currentPhase) { case pb.ReleasePhase.APPLY_ENGINE_CHERRYPICKS: final Remote upstream = Remote( @@ -101,6 +100,22 @@ class NextContext extends Context { upstreamRemote: upstream, previousCheckoutLocation: state.engine.checkoutPath, ); + // check if the candidate branch is enabled in .ci.yaml + final CiYaml engineCiYaml = await engine.ciYaml; + if (!engineCiYaml.enabledBranches.contains(state.engine.candidateBranch)) { + engineCiYaml.enableBranch(state.engine.candidateBranch); + // commit + final String revision = await engine.commit( + 'add branch ${state.engine.candidateBranch} to enabled_branches in .ci.yaml', + addFirst: true, + ); + // append to list of cherrypicks so we know a PR is required + state.engine.cherrypicks.add(pb.Cherrypick( + appliedRevision: revision, + state: pb.CherrypickState.COMPLETED, + )); + } + if (!state_import.requiresEnginePR(state)) { stdio.printStatus( 'This release has no engine cherrypicks. No Engine PR is necessary.\n', @@ -127,18 +142,25 @@ class NextContext extends Context { '${state.engine.checkoutPath} before proceeding.\n'); } if (autoAccept == false) { - final bool response = await prompt( - 'Are you ready to push your engine branch to the repository ' - '${state.engine.mirror.url}?', + final bool response = prompt( + 'Are you ready to push your engine branch to the repository ' + '${state.engine.mirror.url}?', + stdio, ); if (!response) { stdio.printError('Aborting command.'); - updateState(state, stdio.logs); + writeStateToFile(stateFile, state, stdio.logs); return; } } - await pushWorkingBranch(engine, state.engine); + await engine.pushRef( + fromRef: 'HEAD', + // Explicitly create new branch + toRef: 'refs/heads/${state.engine.workingBranch}', + remote: state.engine.mirror.name, + ); + break; case pb.ReleasePhase.CODESIGN_ENGINE_BINARIES: stdio.printStatus([ @@ -147,12 +169,13 @@ class NextContext extends Context { ].join('\n')); if (autoAccept == false) { // TODO(fujino): actually test if binaries have been codesigned on macOS - final bool response = await prompt( - 'Has CI passed for the engine PR and binaries been codesigned?', + final bool response = prompt( + 'Has CI passed for the engine PR and binaries been codesigned?', + stdio, ); if (!response) { stdio.printError('Aborting command.'); - updateState(state, stdio.logs); + writeStateToFile(stateFile, state, stdio.logs); return; } } @@ -187,16 +210,31 @@ class NextContext extends Context { final String engineRevision = await engine.reverseParse('HEAD'); final Remote upstream = Remote( - name: RemoteName.upstream, - url: state.framework.upstream.url, + name: RemoteName.upstream, + url: state.framework.upstream.url, ); final FrameworkRepository framework = FrameworkRepository( - checkouts, - initialRef: state.framework.workingBranch, - upstreamRemote: upstream, - previousCheckoutLocation: state.framework.checkoutPath, + checkouts, + initialRef: state.framework.workingBranch, + upstreamRemote: upstream, + previousCheckoutLocation: state.framework.checkoutPath, ); + // Check if the current candidate branch is enabled + if (!(await framework.ciYaml).enabledBranches.contains(state.framework.candidateBranch)) { + (await framework.ciYaml).enableBranch(state.framework.candidateBranch); + // commit + final String revision = await framework.commit( + 'add branch ${state.framework.candidateBranch} to enabled_branches in .ci.yaml', + addFirst: true, + ); + // append to list of cherrypicks so we know a PR is required + state.framework.cherrypicks.add(pb.Cherrypick( + appliedRevision: revision, + state: pb.CherrypickState.COMPLETED, + )); + } + stdio.printStatus('Rolling new engine hash $engineRevision to framework checkout...'); final bool needsCommit = await framework.updateEngineRevision(engineRevision); if (needsCommit) { @@ -239,18 +277,24 @@ class NextContext extends Context { } if (autoAccept == false) { - final bool response = await prompt( - 'Are you ready to push your framework branch to the repository ' - '${state.framework.mirror.url}?', + final bool response = prompt( + 'Are you ready to push your framework branch to the repository ' + '${state.framework.mirror.url}?', + stdio, ); if (!response) { stdio.printError('Aborting command.'); - updateState(state, stdio.logs); + writeStateToFile(stateFile, state, stdio.logs); return; } } - await pushWorkingBranch(framework, state.framework); + await framework.pushRef( + fromRef: 'HEAD', + // Explicitly create new branch + toRef: 'refs/heads/${state.framework.workingBranch}', + remote: state.framework.mirror.name, + ); break; case pb.ReleasePhase.PUBLISH_VERSION: stdio.printStatus('Please ensure that you have merged your framework PR and that'); @@ -268,13 +312,14 @@ class NextContext extends Context { ); final String headRevision = await framework.reverseParse('HEAD'); if (autoAccept == false) { - final bool response = await prompt( - 'Are you ready to tag commit $headRevision as ${state.releaseVersion}\n' - 'and push to remote ${state.framework.upstream.url}?', + final bool response = prompt( + 'Are you ready to tag commit $headRevision as ${state.releaseVersion}\n' + 'and push to remote ${state.framework.upstream.url}?', + stdio, ); if (!response) { stdio.printError('Aborting command.'); - updateState(state, stdio.logs); + writeStateToFile(stateFile, state, stdio.logs); return; } } @@ -293,37 +338,32 @@ class NextContext extends Context { previousCheckoutLocation: state.framework.checkoutPath, ); final String headRevision = await framework.reverseParse('HEAD'); - final List releaseRefs = [state.releaseChannel]; - if (kSynchronizeDevWithBeta && state.releaseChannel == 'beta') { - releaseRefs.add('dev'); - } - for (final String releaseRef in releaseRefs) { - if (autoAccept == false) { - // dryRun: true means print out git command - await framework.pushRef( + if (autoAccept == false) { + // dryRun: true means print out git command + await framework.pushRef( fromRef: headRevision, - toRef: releaseRef, + toRef: state.releaseChannel, remote: state.framework.upstream.url, force: force, dryRun: true, - ); + ); - final bool response = await prompt( - 'Are you ready to publish version ${state.releaseVersion} to $releaseRef?', - ); - if (!response) { - stdio.printError('Aborting command.'); - updateState(state, stdio.logs); - return; - } + final bool response = prompt( + 'Are you ready to publish this release?', + stdio, + ); + if (!response) { + stdio.printError('Aborting command.'); + writeStateToFile(stateFile, state, stdio.logs); + return; } - await framework.pushRef( + } + await framework.pushRef( fromRef: headRevision, - toRef: releaseRef, + toRef: state.releaseChannel, remote: state.framework.upstream.url, force: force, - ); - } + ); break; case pb.ReleasePhase.VERIFY_RELEASE: stdio.printStatus( @@ -331,10 +371,13 @@ class NextContext extends Context { '\t$kLuciPackagingConsoleLink', ); if (autoAccept == false) { - final bool response = await prompt('Have all packaging builds finished successfully?'); + final bool response = prompt( + 'Have all packaging builds finished successfully?', + stdio, + ); if (!response) { stdio.printError('Aborting command.'); - updateState(state, stdio.logs); + writeStateToFile(stateFile, state, stdio.logs); return; } } @@ -347,39 +390,32 @@ class NextContext extends Context { state.currentPhase = nextPhase; stdio.printStatus(state_import.phaseInstructions(state)); - updateState(state, stdio.logs); + writeStateToFile(stateFile, state, stdio.logs); + } + + /// Persist the state to a file. + @visibleForOverriding + void writeStateToFile(File file, pb.ConductorState state, [List logs = const []]) { + state_import.writeStateToFile(file, state, logs); } - /// Push the working branch to the user's mirror. - /// - /// [repository] represents the actual Git repository on disk, and is used to - /// call `git push`, while [pbRepository] represents the user-specified - /// configuration for the repository, and is used to read the name of the - /// working branch and the mirror's remote name. - /// - /// May throw either a [ConductorException] if the user already has a branch - /// of the same name on their mirror, or a [GitException] for any other - /// failures from the underlying git process call. @visibleForTesting - Future pushWorkingBranch(Repository repository, pb.Repository pbRepository) async { - try { - await repository.pushRef( - fromRef: 'HEAD', - // Explicitly create new branch - toRef: 'refs/heads/${pbRepository.workingBranch}', - remote: pbRepository.mirror.name, - force: force, - ); - } on GitException catch (exception) { - if (exception.type == GitExceptionType.PushRejected && force == false) { - throw ConductorException( - 'Push failed because the working branch named ' - '${pbRepository.workingBranch} already exists on your mirror. ' - 'Re-run this command with --force to overwrite the remote branch.\n' - '${exception.message}', - ); - } - rethrow; + bool prompt(String message, Stdio stdio) { + stdio.write('${message.trim()} (y/n) '); + final String response = stdio.readLineSync().trim(); + final String firstChar = response[0].toUpperCase(); + if (firstChar == 'Y') { + return true; + } + if (firstChar == 'N') { + return false; } + throw ConductorException( + 'Unknown user input (expected "y" or "n"): $response', + ); } + + /// Read the state from a file. + @visibleForOverriding + pb.ConductorState readStateFromFile(File file) => state_import.readStateFromFile(file); } diff --git a/dev/conductor/core/lib/src/repository.dart b/dev/conductor/core/lib/src/repository.dart index f33dc472adc51..e1f9e087234fc 100644 --- a/dev/conductor/core/lib/src/repository.dart +++ b/dev/conductor/core/lib/src/repository.dart @@ -56,24 +56,17 @@ abstract class Repository { required this.platform, required this.fileSystem, required this.parentDirectory, - required this.requiredLocalBranches, this.initialRef, this.localUpstream = false, this.previousCheckoutLocation, this.mirrorRemote, }) : git = Git(processManager), + assert(localUpstream != null), assert(upstreamRemote.url.isNotEmpty); final String name; final Remote upstreamRemote; - /// Branches that must exist locally in this [Repository]. - /// - /// If this [Repository] is used as a local upstream for another, the - /// downstream may try to fetch these branches, and git will fail if they do - /// not exist. - final List requiredLocalBranches; - /// Remote for user's mirror. /// /// This value can be null, in which case attempting to access it will lead to @@ -124,13 +117,11 @@ abstract class Repository { workingDirectory: _checkoutDirectory!.path, ); } - return _checkoutDirectory!; } _checkoutDirectory = parentDirectory.childDirectory(name); await lazilyInitialize(_checkoutDirectory!); - return _checkoutDirectory!; } @@ -171,7 +162,7 @@ abstract class Repository { if (localUpstream) { // These branches must exist locally for the repo that depends on it // to fetch and push to. - for (final String channel in requiredLocalBranches) { + for (final String channel in kReleaseChannels) { await git.run( ['checkout', channel, '--'], 'check out branch $channel locally', @@ -182,7 +173,7 @@ abstract class Repository { if (initialRef != null) { await git.run( - ['checkout', initialRef!], + ['checkout', '${upstreamRemote.name}/$initialRef'], 'Checking out initialRef $initialRef', workingDirectory: checkoutDirectory.path, ); @@ -472,9 +463,8 @@ class FrameworkRepository extends Repository { name: RemoteName.upstream, url: FrameworkRepository.defaultUpstream), bool localUpstream = false, String? previousCheckoutLocation, - String initialRef = FrameworkRepository.defaultBranch, + String? initialRef, Remote? mirrorRemote, - List? additionalRequiredLocalBranches, }) : super( name: name, upstreamRemote: upstreamRemote, @@ -487,10 +477,6 @@ class FrameworkRepository extends Repository { processManager: checkouts.processManager, stdio: checkouts.stdio, previousCheckoutLocation: previousCheckoutLocation, - requiredLocalBranches: [ - ...?additionalRequiredLocalBranches, - ...kReleaseChannels, - ], ); /// A [FrameworkRepository] with the host conductor's repo set as upstream. @@ -501,7 +487,6 @@ class FrameworkRepository extends Repository { Checkouts checkouts, { String name = 'framework', String? previousCheckoutLocation, - String initialRef = FrameworkRepository.defaultBranch, required String upstreamPath, }) { return FrameworkRepository( @@ -512,12 +497,13 @@ class FrameworkRepository extends Repository { url: 'file://$upstreamPath/', ), previousCheckoutLocation: previousCheckoutLocation, - initialRef: initialRef, ); } final Checkouts checkouts; - static const String defaultUpstream = 'git@github.com:flutter/flutter.git'; + static const String defaultUpstream = + 'git@github.com:flutter/flutter.git'; + static const String defaultBranch = 'master'; Future get ciYaml async { @@ -556,7 +542,7 @@ class FrameworkRepository extends Repository { } @override - Future cloneRepository(String? cloneName) async { + Future cloneRepository(String? cloneName) async { assert(localUpstream); cloneName ??= 'clone-of-$name'; return FrameworkRepository( @@ -731,7 +717,6 @@ class EngineRepository extends Repository { bool localUpstream = false, String? previousCheckoutLocation, Remote? mirrorRemote, - List? additionalRequiredLocalBranches, }) : super( name: name, upstreamRemote: upstreamRemote, @@ -744,7 +729,6 @@ class EngineRepository extends Repository { processManager: checkouts.processManager, stdio: checkouts.stdio, previousCheckoutLocation: previousCheckoutLocation, - requiredLocalBranches: additionalRequiredLocalBranches ?? const [], ); final Checkouts checkouts; @@ -755,7 +739,7 @@ class EngineRepository extends Repository { } static const String defaultUpstream = 'git@github.com:flutter/engine.git'; - static const String defaultBranch = 'main'; + static const String defaultBranch = 'master'; /// Update the `dart_revision` entry in the DEPS file. Future updateDartRevision( @@ -844,4 +828,46 @@ class CiYaml { /// This is not cached as the contents can be written to while the conductor /// is running. YamlMap get contents => loadYaml(stringContents) as YamlMap; + + List get enabledBranches { + final YamlList yamlList = contents['enabled_branches'] as YamlList; + return yamlList.map((dynamic element) { + return element as String; + }).toList(); + } + + static final RegExp _enabledBranchPattern = RegExp(r'enabled_branches:'); + + /// Update this .ci.yaml file with the given branch name. + /// + /// The underlying [File] is written to, but not committed to git. This method + /// will throw a [ConductorException] if the [branchName] is already present + /// in the file or if the file does not have an "enabled_branches:" field. + void enableBranch(String branchName) { + final List newStrings = []; + if (enabledBranches.contains(branchName)) { + throw ConductorException('${file.path} already contains the branch $branchName'); + } + if (!_enabledBranchPattern.hasMatch(stringContents)) { + throw ConductorException( + 'Did not find the expected string "enabled_branches:" in the file ${file.path}', + ); + } + final List lines = stringContents.split('\n'); + bool insertedCurrentBranch = false; + for (final String line in lines) { + // Every existing line should be copied to the new Yaml + newStrings.add(line); + if (insertedCurrentBranch) { + continue; + } + if (_enabledBranchPattern.hasMatch(line)) { + insertedCurrentBranch = true; + // Indent two spaces + final String indent = ' ' * 2; + newStrings.add('$indent- ${branchName.trim()}'); + } + } + file.writeAsStringSync(newStrings.join('\n'), flush: true); + } } diff --git a/dev/conductor/core/lib/src/roll_dev.dart b/dev/conductor/core/lib/src/roll_dev.dart new file mode 100644 index 0000000000000..41ae61ac891a4 --- /dev/null +++ b/dev/conductor/core/lib/src/roll_dev.dart @@ -0,0 +1,204 @@ +// 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 'package:args/args.dart'; +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:meta/meta.dart'; +import 'package:platform/platform.dart'; + +import './repository.dart'; +import './stdio.dart'; +import './version.dart'; + +const String kIncrement = 'increment'; +const String kCandidateBranch = 'candidate-branch'; +const String kRemoteName = 'remote'; +const String kJustPrint = 'just-print'; +const String kYes = 'yes'; +const String kForce = 'force'; +const String kSkipTagging = 'skip-tagging'; + +/// Create a new dev release without cherry picks. +class RollDevCommand extends Command { + RollDevCommand({ + required this.checkouts, + required this.fileSystem, + required this.platform, + required this.stdio, + }) { + argParser.addOption( + kIncrement, + help: 'Specifies which part of the x.y.z version number to increment. Required.', + valueHelp: 'level', + allowed: ['y', 'z', 'm'], + allowedHelp: { + 'y': 'Indicates the first dev release after a beta release.', + 'z': 'Indicates a hotfix to a stable release.', + 'm': 'Indicates a standard dev release.', + }, + ); + argParser.addOption( + kCandidateBranch, + help: 'Specifies which git branch to roll to the dev branch. Required.', + valueHelp: 'branch', + ); + argParser.addFlag( + kForce, + abbr: 'f', + help: 'Force push. Necessary when the previous release had cherry-picks.', + negatable: false, + ); + argParser.addFlag( + kJustPrint, + negatable: false, + help: + "Don't actually roll the dev channel; " + 'just print the would-be version and quit.', + ); + argParser.addFlag( + kSkipTagging, + negatable: false, + help: 'Do not create tag and push to remote, only update release branch. ' + 'For recovering when the script fails trying to git push to the release branch.' + ); + argParser.addFlag( + kYes, + negatable: false, + abbr: 'y', + help: 'Skip the confirmation prompt.', + ); + argParser.addOption( + kRemoteName, + help: 'Specifies which git remote to fetch from.', + defaultsTo: 'upstream', + ); + } + + final Checkouts checkouts; + final FileSystem fileSystem; + final Platform platform; + final Stdio stdio; + + @override + String get name => 'roll-dev'; + + @override + String get description => + 'For publishing a dev release without cherry picks.'; + + @override + Future run() async { + await rollDev( + argResults: argResults!, + repository: FrameworkRepository(checkouts), + stdio: stdio, + usage: argParser.usage, + ); + } +} + +/// Main script execution. +/// +/// Returns true if publishing was successful, else false. +@visibleForTesting +Future rollDev({ + required String usage, + required ArgResults argResults, + required Stdio stdio, + required FrameworkRepository repository, +}) async { + final String remoteName = argResults[kRemoteName] as String; + final String? level = argResults[kIncrement] as String?; + final String candidateBranch = argResults[kCandidateBranch] as String; + final bool justPrint = argResults[kJustPrint] as bool; + final bool autoApprove = argResults[kYes] as bool; + final bool force = argResults[kForce] as bool; + final bool skipTagging = argResults[kSkipTagging] as bool; + + if (level == null || candidateBranch == null) { + throw Exception( + 'roll_dev.dart --$kIncrement=level --$kCandidateBranch=branch • update the version tags ' + 'and roll a new dev build.\n$usage'); + } + + final String remoteUrl = await repository.remoteUrl(remoteName); + + if (!(await repository.gitCheckoutClean())) { + throw Exception( + 'Your git repository is not clean. Try running "git clean -fd". Warning, ' + 'this will delete files! Run with -n to find out which ones.'); + } + + await repository.fetch(remoteName); + + // Verify [commit] is valid + final String commit = await repository.reverseParse(candidateBranch); + + stdio.printStatus('remoteName is $remoteName'); + // Get the name of the last dev release + final Version lastVersion = Version.fromString( + await repository.getFullTag(remoteName, 'dev'), + ); + + final Version version = + skipTagging ? lastVersion : Version.fromCandidateBranch(candidateBranch); + final String tagName = version.toString(); + + if ((await repository.reverseParse(lastVersion.toString())).contains(commit.trim())) { + throw Exception( + 'Commit $commit is already on the dev branch as $lastVersion.'); + } + + if (justPrint) { + stdio.printStatus(tagName); + return false; + } + + if (skipTagging && !(await repository.isCommitTagged(commit))) { + throw Exception( + 'The $kSkipTagging flag is only supported for tagged commits.'); + } + + if (!force && !(await repository.isAncestor(commit, lastVersion.toString()))) { + throw Exception( + 'The previous dev tag $lastVersion is not a direct ancestor of $commit.\n' + 'The flag "$kForce" is required to force push a new release past a cherry-pick.'); + } + + final String hash = await repository.reverseParse(commit); + + // [commit] can be a prefix for [hash]. + assert(hash.startsWith(commit)); + + // PROMPT + if (autoApprove) { + stdio.printStatus( + 'Publishing Flutter $version ($hash) to the "dev" channel.'); + } else { + stdio.printStatus('Your tree is ready to publish Flutter $version ' + '($hash) to the "dev" channel.'); + stdio.write('Are you? [yes/no] '); + if (stdio.readLineSync() != 'yes') { + stdio.printError('The dev roll has been aborted.'); + return false; + } + } + + if (!skipTagging) { + await repository.tag(commit, version.toString(), remoteName); + } + + await repository.pushRef( + fromRef: commit, + remote: remoteName, + toRef: 'dev', + force: force, + ); + + stdio.printStatus( + 'Flutter version $version has been rolled to the "dev" channel at $remoteUrl.', + ); + return true; +} diff --git a/dev/conductor/core/lib/src/start.dart b/dev/conductor/core/lib/src/start.dart index f4865f22baba0..d45c6c0def67e 100644 --- a/dev/conductor/core/lib/src/start.dart +++ b/dev/conductor/core/lib/src/start.dart @@ -9,15 +9,14 @@ import 'package:fixnum/fixnum.dart'; import 'package:platform/platform.dart'; import 'package:process/process.dart'; -import 'context.dart'; -import 'git.dart'; -import 'globals.dart'; -import 'proto/conductor_state.pb.dart' as pb; -import 'proto/conductor_state.pbenum.dart' show ReleasePhase; -import 'repository.dart'; -import 'state.dart' as state_import; -import 'stdio.dart'; -import 'version.dart'; +import './git.dart'; +import './globals.dart'; +import './proto/conductor_state.pb.dart' as pb; +import './proto/conductor_state.pbenum.dart' show ReleasePhase; +import './repository.dart'; +import './state.dart'; +import './stdio.dart'; +import './version.dart'; const String kCandidateOption = 'candidate-branch'; const String kDartRevisionOption = 'dart-revision'; @@ -40,7 +39,7 @@ class StartCommand extends Command { processManager = checkouts.processManager, fileSystem = checkouts.fileSystem, stdio = checkouts.stdio { - final String defaultPath = state_import.defaultStateFilePath(platform); + final String defaultPath = defaultStateFilePath(platform); argParser.addOption( kCandidateOption, help: 'The candidate branch the release will be based on.', @@ -48,12 +47,13 @@ class StartCommand extends Command { argParser.addOption( kReleaseOption, help: 'The target release channel for the release.', - allowed: kBaseReleaseChannels, + allowed: ['stable', 'beta', 'dev'], ); argParser.addOption( kFrameworkUpstreamOption, defaultsTo: FrameworkRepository.defaultUpstream, - help: 'Configurable Framework repo upstream remote. Primarily for testing.', + help: + 'Configurable Framework repo upstream remote. Primarily for testing.', hide: true, ); argParser.addOption( @@ -93,7 +93,7 @@ class StartCommand extends Command { kIncrementOption, help: 'Specifies which part of the x.y.z version number to increment. Required.', valueHelp: 'level', - allowed: kReleaseIncrements, + allowed: ['y', 'z', 'm', 'n'], allowedHelp: { 'y': 'Indicates the first dev release after a beta release.', 'z': 'Indicates a hotfix to a stable release.', @@ -101,11 +101,6 @@ class StartCommand extends Command { 'n': 'Indicates a hotfix to a dev or beta release.', }, ); - argParser.addFlag( - kForceFlag, - abbr: 'f', - help: 'Override all validations of the command line inputs.', - ); } final Checkouts checkouts; @@ -182,11 +177,6 @@ class StartCommand extends Command { argumentResults, platform.environment, )!; - final bool force = getBoolFromEnvOrArgs( - kForceFlag, - argumentResults, - platform.environment, - ); final File stateFile = checkouts.fileSystem.file( getValueFromEnvOrArgs(kStateOption, argumentResults, platform.environment), ); @@ -206,7 +196,7 @@ class StartCommand extends Command { processManager: processManager, releaseChannel: releaseChannel, stateFile: stateFile, - force: force, + stdio: stdio, ); return context.run(); } @@ -215,9 +205,10 @@ class StartCommand extends Command { /// Context for starting a new release. /// /// This is a frontend-agnostic implementation. -class StartContext extends Context { +class StartContext { StartContext({ required this.candidateBranch, + required this.checkouts, required this.dartRevision, required this.engineCherrypickRevisions, required this.engineMirror, @@ -229,39 +220,12 @@ class StartContext extends Context { required this.incrementLetter, required this.processManager, required this.releaseChannel, - required Checkouts checkouts, - required File stateFile, - this.force = false, - }) : git = Git(processManager), - engine = EngineRepository( - checkouts, - initialRef: 'upstream/$candidateBranch', - upstreamRemote: Remote( - name: RemoteName.upstream, - url: engineUpstream, - ), - mirrorRemote: Remote( - name: RemoteName.mirror, - url: engineMirror, - ), - ), framework = FrameworkRepository( - checkouts, - initialRef: 'upstream/$candidateBranch', - upstreamRemote: Remote( - name: RemoteName.upstream, - url: frameworkUpstream, - ), - mirrorRemote: Remote( - name: RemoteName.mirror, - url: frameworkMirror, - ), - ), - super( - checkouts: checkouts, - stateFile: stateFile, - ); + required this.stateFile, + required this.stdio, + }) : git = Git(processManager); final String candidateBranch; + final Checkouts checkouts; final String? dartRevision; final List engineCherrypickRevisions; final String engineMirror; @@ -274,16 +238,13 @@ class StartContext extends Context { final Git git; final ProcessManager processManager; final String releaseChannel; - - /// If validations should be overridden. - final bool force; - - final EngineRepository engine; - final FrameworkRepository framework; + final File stateFile; + final Stdio stdio; Future run() async { if (stateFile.existsSync()) { - throw ConductorException('Error! A persistent state file already found at ${stateFile.path}.\n\n' + throw ConductorException( + 'Error! A persistent state file already found at ${stateFile.path}.\n\n' 'Run `conductor clean` to cancel a previous release.'); } if (!releaseCandidateBranchRegex.hasMatch(candidateBranch)) { @@ -301,6 +262,19 @@ class StartContext extends Context { state.lastUpdatedDate = unixDate; state.incrementLevel = incrementLetter; + final EngineRepository engine = EngineRepository( + checkouts, + initialRef: candidateBranch, + upstreamRemote: Remote( + name: RemoteName.upstream, + url: engineUpstream, + ), + mirrorRemote: Remote( + name: RemoteName.mirror, + url: engineMirror, + ), + ); + // Create a new branch so that we don't accidentally push to upstream // candidateBranch. final String workingBranchName = 'cherrypicks-$candidateBranch'; @@ -345,7 +319,18 @@ class StartContext extends Context { upstream: pb.Remote(name: 'upstream', url: engine.upstreamRemote.url), mirror: pb.Remote(name: 'mirror', url: engine.mirrorRemote!.url), ); - + final FrameworkRepository framework = FrameworkRepository( + checkouts, + initialRef: candidateBranch, + upstreamRemote: Remote( + name: RemoteName.upstream, + url: frameworkUpstream, + ), + mirrorRemote: Remote( + name: RemoteName.mirror, + url: frameworkMirror, + ), + ); await framework.newBranch(workingBranchName); final List frameworkCherrypicks = (await _sortCherrypicks( repository: framework, @@ -373,18 +358,29 @@ class StartContext extends Context { // Get framework version final Version lastVersion = Version.fromString(await framework.getFullTag( - framework.upstreamRemote.name, - candidateBranch, - exact: false, - )); - // [force] means we know this would fail but need to publish anyway - if (!force) { - lastVersion.ensureValid(candidateBranch, incrementLetter); + framework.upstreamRemote.name, candidateBranch, + exact: false, + ))..ensureValid(candidateBranch, incrementLetter); + Version nextVersion; + if (incrementLetter == 'm') { + nextVersion = Version.fromCandidateBranch(candidateBranch); + } else { + if (incrementLetter == 'z') { + if (lastVersion.type == VersionType.stable) { + nextVersion = Version.increment(lastVersion, incrementLetter); + } else { + // This is the first stable release, so hardcode the z as 0 + nextVersion = Version( + x: lastVersion.x, + y: lastVersion.y, + z: 0, + type: VersionType.stable, + ); + } + } else { + nextVersion = Version.increment(lastVersion, incrementLetter); + } } - - Version nextVersion = calculateNextVersion(lastVersion); - nextVersion = await ensureBranchPointTagged(nextVersion, framework); - state.releaseVersion = nextVersion.toString(); final String frameworkHead = await framework.reverseParse('HEAD'); @@ -405,68 +401,9 @@ class StartContext extends Context { stdio.printTrace('Writing state to file ${stateFile.path}...'); - updateState(state, stdio.logs); - - stdio.printStatus(state_import.presentState(state)); - } - - /// Determine this release's version number from the [lastVersion] and the [incrementLetter]. - Version calculateNextVersion(Version lastVersion) { - if (incrementLetter == 'm') { - return Version.fromCandidateBranch(candidateBranch); - } - if (incrementLetter == 'z') { - if (lastVersion.type == VersionType.stable) { - return Version.increment(lastVersion, incrementLetter); - } - // This is the first stable release, so hardcode the z as 0 - return Version( - x: lastVersion.x, - y: lastVersion.y, - z: 0, - type: VersionType.stable, - ); - } - return Version.increment(lastVersion, incrementLetter); - } - - /// Ensures the branch point [candidateBranch] and `master` has a version tag. - /// - /// This is necessary for version reporting for users on the `master` channel - /// to be correct. - Future ensureBranchPointTagged( - Version requestedVersion, - FrameworkRepository framework, - ) async { - if (incrementLetter != 'm') { - // in this case, there must have been a previous tagged release, so skip - // tagging the branch point - return requestedVersion; - } - final String branchPoint = await framework.branchPoint( - candidateBranch, - FrameworkRepository.defaultBranch, - ); - final bool response = await prompt( - 'About to tag the release candidate branch branchpoint of $branchPoint ' - 'as $requestedVersion and push it to ${framework.upstreamRemote.url}. ' - 'Is this correct?', - ); + writeStateToFile(stateFile, state, stdio.logs); - if (!response) { - throw ConductorException('Aborting command.'); - } - - stdio.printStatus('Applying the tag $requestedVersion at the branch point $branchPoint'); - - await framework.tag( - branchPoint, - requestedVersion.toString(), - frameworkUpstream, - ); - final Version nextVersion = Version.increment(requestedVersion, 'n'); - stdio.printStatus('The actual release will be version $nextVersion.'); - return nextVersion; + stdio.printStatus(presentState(state)); } // To minimize merge conflicts, sort the commits by rev-list order. diff --git a/dev/conductor/core/lib/src/state.dart b/dev/conductor/core/lib/src/state.dart index b56a4db315c33..c76a19e96741b 100644 --- a/dev/conductor/core/lib/src/state.dart +++ b/dev/conductor/core/lib/src/state.dart @@ -15,7 +15,7 @@ const String kStateFileName = '.flutter_conductor_state.json'; String luciConsoleLink(String channel, String groupName) { assert( - kReleaseChannels.contains(channel), + ['stable', 'beta', 'dev', 'master'].contains(channel), 'channel $channel not recognized', ); assert( diff --git a/dev/conductor/core/lib/src/stdio.dart b/dev/conductor/core/lib/src/stdio.dart index 11276d048ed70..90765115f0239 100644 --- a/dev/conductor/core/lib/src/stdio.dart +++ b/dev/conductor/core/lib/src/stdio.dart @@ -9,44 +9,25 @@ import 'package:meta/meta.dart'; abstract class Stdio { final List logs = []; - /// Error messages printed to STDERR. - /// - /// Display an error `message` to the user on stderr. Print errors if the code - /// fails in some way. Errors are typically followed shortly by exiting the - /// app with a non-zero exit status. + /// Error/warning messages printed to STDERR. @mustCallSuper void printError(String message) { logs.add('[error] $message'); } - /// Warning messages printed to STDERR. - /// - /// Display a warning `message` to the user on stderr. Print warnings if there - /// is important information to convey to the user that is not fatal. - @mustCallSuper - void printWarning(String message) { - logs.add('[warning] $message'); - } - /// Ordinary STDOUT messages. - /// - /// Displays normal output on stdout. This should be used for things like - /// progress messages, success messages, or just normal command output. @mustCallSuper void printStatus(String message) { logs.add('[status] $message'); } /// Debug messages that are only printed in verbose mode. - /// - /// Use this for verbose tracing output. Users can turn this output on in order - /// to help diagnose issues. @mustCallSuper void printTrace(String message) { logs.add('[trace] $message'); } - /// Write the `message` string to STDOUT without a trailing newline. + /// Write string to STDOUT without trailing newline. @mustCallSuper void write(String message) { logs.add('[write] $message'); diff --git a/dev/conductor/core/lib/src/version.dart b/dev/conductor/core/lib/src/version.dart index 8477b6d8417a7..0389a3f34f000 100644 --- a/dev/conductor/core/lib/src/version.dart +++ b/dev/conductor/core/lib/src/version.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import './globals.dart' show ConductorException, kReleaseIncrements, releaseCandidateBranchRegex; +import './globals.dart' show releaseCandidateBranchRegex, ConductorException; /// Possible string formats that `flutter --version` can return. enum VersionType { @@ -26,7 +26,6 @@ enum VersionType { /// A master channel flutter version from git describe. /// /// Example: '1.2.3-4.0.pre-10-gabc123'. - /// Example: '1.2.3-10-gabc123'. gitDescribe, } @@ -34,7 +33,7 @@ final Map versionPatterns = { VersionType.stable: RegExp(r'^(\d+)\.(\d+)\.(\d+)$'), VersionType.development: RegExp(r'^(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.pre$'), VersionType.latest: RegExp(r'^(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.pre\.(\d+)$'), - VersionType.gitDescribe: RegExp(r'^(\d+)\.(\d+)\.(\d+)-((\d+)\.(\d+)\.pre-)?(\d+)-g[a-f0-9]+$'), + VersionType.gitDescribe: RegExp(r'^(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.pre-(\d+)-g[a-f0-9]+$'), }; class Version { @@ -64,8 +63,9 @@ class Version { assert(commits != null); break; case VersionType.gitDescribe: - assert(commits != null); - break; + throw ConductorException( + 'VersionType.gitDescribe not supported! Use VersionType.latest instead.', + ); } } @@ -130,20 +130,19 @@ class Version { match = versionPatterns[VersionType.gitDescribe]!.firstMatch(versionString); if (match != null) { // parse latest - final int x = int.parse(match.group(1)!); - final int y = int.parse(match.group(2)!); - final int z = int.parse(match.group(3)!); - final int? m = int.tryParse(match.group(5) ?? ''); - final int? n = int.tryParse(match.group(6) ?? ''); - final int commits = int.parse(match.group(7)!); + final List parts = match.groups( + [1, 2, 3, 4, 5, 6], + ).map( + (String? s) => int.parse(s!), + ).toList(); return Version( - x: x, - y: y, - z: z, - m: m, - n: n, - commits: commits, - type: VersionType.gitDescribe, + x: parts[0], + y: parts[1], + z: parts[2], + m: parts[3], + n: parts[4], + commits: parts[5], + type: VersionType.latest, ); } throw Exception('${versionString.trim()} cannot be parsed'); @@ -239,18 +238,12 @@ class Version { final int y; /// Number of hotfix releases after a stable release. - /// - /// For non-stable releases, this will be 0. final int z; /// Zero-indexed count of dev releases after a beta release. - /// - /// For stable releases, this will be null. final int? m; /// Number of hotfixes required to make a dev release. - /// - /// For stable releases, this will be null. final int? n; /// Number of commits past last tagged dev release. @@ -263,7 +256,7 @@ class Version { /// Will throw a [ConductorException] if the version is not possible given the /// [candidateBranch] and [incrementLetter]. void ensureValid(String candidateBranch, String incrementLetter) { - if (!kReleaseIncrements.contains(incrementLetter)) { + if (!const {'y', 'z', 'm', 'n'}.contains(incrementLetter)) { throw ConductorException('Invalid incrementLetter: $incrementLetter'); } final RegExpMatch? branchMatch = releaseCandidateBranchRegex.firstMatch(candidateBranch); diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 45f87bd35f3fe..ffdb9ffd6033c 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -7,14 +7,14 @@ environment: sdk: ">=2.12.0 <3.0.0" dependencies: - archive: 3.1.8 + archive: 3.1.6 args: 2.3.0 http: 0.13.4 intl: 0.17.0 meta: 1.7.0 - path: 1.8.1 + path: 1.8.0 process: 4.2.4 - protobuf: 2.0.1 + protobuf: 2.0.0 yaml: 3.1.0 async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -25,18 +25,18 @@ dependencies: file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.20.1 - test_api: 0.4.9 + test: 1.17.12 + test_api: 0.4.3 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,12 +45,13 @@ dev_dependencies: glob: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,10 +62,10 @@ dev_dependencies: source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 358f +# PUBSPEC CHECKSUM: db54 diff --git a/dev/conductor/core/test/clean_test.dart b/dev/conductor/core/test/clean_test.dart index c736b67556df6..2ba7a95494a00 100644 --- a/dev/conductor/core/test/clean_test.dart +++ b/dev/conductor/core/test/clean_test.dart @@ -15,7 +15,6 @@ void main() { group('clean command', () { const String flutterRoot = '/flutter'; const String checkoutsParentDirectory = '$flutterRoot/dev/tools/'; - const String stateFilePath = '/state-file.json'; late MemoryFileSystem fileSystem; late FakePlatform platform; @@ -48,36 +47,24 @@ void main() { }); test('throws if no state file found', () async { + const String stateFile = '/state-file.json'; + await expectLater( () async => runner.run([ 'clean', '--$kStateOption', - stateFilePath, + stateFile, '--$kYesFlag', ]), throwsExceptionWith( - 'No persistent state file found at $stateFilePath', + 'No persistent state file found at $stateFile', ), ); }); - test('deletes an empty state file', () async { - final File stateFile = fileSystem.file(stateFilePath); - stateFile.writeAsStringSync(''); - - await runner.run([ - 'clean', - '--$kStateOption', - stateFile.path, - '--$kYesFlag', - ]); - - expect(stateFile.existsSync(), false); - }); - - test('deletes a state file with content', () async { - final File stateFile = fileSystem.file(stateFilePath); - stateFile.writeAsStringSync('{status: pending}'); + test('deletes state file', () async { + final File stateFile = fileSystem.file('/state-file.json'); + stateFile.writeAsStringSync('{}'); await runner.run([ 'clean', diff --git a/dev/conductor/core/test/codesign_integration_test.dart b/dev/conductor/core/test/codesign_integration_test.dart index 15064c6b110f8..2e719ed36dd57 100644 --- a/dev/conductor/core/test/codesign_integration_test.dart +++ b/dev/conductor/core/test/codesign_integration_test.dart @@ -5,7 +5,7 @@ import 'package:args/command_runner.dart'; import 'package:conductor_core/src/codesign.dart' show CodesignCommand; import 'package:conductor_core/src/globals.dart'; -import 'package:conductor_core/src/repository.dart' show Checkouts, FrameworkRepository; +import 'package:conductor_core/src/repository.dart' show Checkouts; import 'package:file/file.dart'; import 'package:file/local.dart'; import 'package:platform/platform.dart'; @@ -35,24 +35,9 @@ void main() { fileSystem.file(platform.executable), ); - final String currentHead = (processManager.runSync( - ['git', 'rev-parse', 'HEAD'], - workingDirectory: flutterRoot.path, - ).stdout as String).trim(); - - final FrameworkRepository framework = FrameworkRepository.localRepoAsUpstream( - checkouts, - upstreamPath: flutterRoot.path, - initialRef: currentHead, - ); - final CommandRunner runner = CommandRunner('codesign-test', ''); - runner.addCommand( - CodesignCommand( - checkouts: checkouts, - framework: framework, - flutterRoot: flutterRoot, - ), - ); + final CommandRunner runner = CommandRunner('codesign-test', '') + ..addCommand( + CodesignCommand(checkouts: checkouts, flutterRoot: flutterRoot)); try { await runner.run([ diff --git a/dev/conductor/core/test/codesign_test.dart b/dev/conductor/core/test/codesign_test.dart index a33cf7687fa39..b85d94da72241 100644 --- a/dev/conductor/core/test/codesign_test.dart +++ b/dev/conductor/core/test/codesign_test.dart @@ -112,11 +112,6 @@ void main() { 'file://$flutterRoot/', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', ]), - const FakeCommand(command: [ - 'git', - 'checkout', - FrameworkRepository.defaultBranch, - ]), const FakeCommand(command: [ 'git', 'rev-parse', @@ -201,11 +196,6 @@ void main() { 'file://$flutterRoot/', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', ]), - const FakeCommand(command: [ - 'git', - 'checkout', - FrameworkRepository.defaultBranch, - ]), const FakeCommand(command: [ 'git', 'rev-parse', @@ -294,11 +284,6 @@ void main() { 'file://$flutterRoot/', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', ]), - const FakeCommand(command: [ - 'git', - 'checkout', - FrameworkRepository.defaultBranch, - ]), const FakeCommand(command: [ 'git', 'rev-parse', @@ -386,11 +371,6 @@ void main() { 'file://$flutterRoot/', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', ]), - const FakeCommand(command: [ - 'git', - 'checkout', - FrameworkRepository.defaultBranch, - ]), const FakeCommand(command: [ 'git', 'rev-parse', @@ -450,11 +430,6 @@ void main() { 'file://$flutterRoot/', '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', ]), - const FakeCommand(command: [ - 'git', - 'checkout', - FrameworkRepository.defaultBranch, - ]), const FakeCommand(command: [ 'git', 'rev-parse', diff --git a/dev/conductor/core/test/common.dart b/dev/conductor/core/test/common.dart index b6612718951a4..f37c86183275f 100644 --- a/dev/conductor/core/test/common.dart +++ b/dev/conductor/core/test/common.dart @@ -34,7 +34,7 @@ class TestStdio extends Stdio { TestStdio({ this.verbose = false, List? stdin, - }) : stdin = stdin ?? []; + }) : _stdin = stdin ?? []; String get error => logs.where((String log) => log.startsWith(r'[error] ')).join('\n'); @@ -43,14 +43,15 @@ class TestStdio extends Stdio { }).join('\n'); final bool verbose; - final List stdin; + late final List _stdin; + List get stdin => _stdin; @override String readLineSync() { - if (stdin.isEmpty) { - throw Exception('Unexpected call to readLineSync! Last stdout was ${logs.last}'); + if (_stdin.isEmpty) { + throw Exception('Unexpected call to readLineSync!'); } - return stdin.removeAt(0); + return _stdin.removeAt(0); } } diff --git a/dev/conductor/core/test/globals_test.dart b/dev/conductor/core/test/globals_test.dart index a5fd147fbe2cd..60ce6e73d2713 100644 --- a/dev/conductor/core/test/globals_test.dart +++ b/dev/conductor/core/test/globals_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:args/args.dart'; import 'package:conductor_core/src/globals.dart'; import 'package:conductor_core/src/proto/conductor_state.pb.dart' as pb; @@ -130,69 +129,4 @@ void main() { ); }); }); - - group('getBoolFromEnvOrArgs', () { - const String flagName = 'a-cli-flag'; - - test('prefers env over argResults', () { - final ArgResults argResults = FakeArgs(results: { - flagName: false, - }); - final Map env = {'A_CLI_FLAG': 'TRUE'}; - final bool result = getBoolFromEnvOrArgs( - flagName, - argResults, - env, - ); - expect(result, true); - }); - - test('falls back to argResults if env is empty', () { - final ArgResults argResults = FakeArgs(results: { - flagName: false, - }); - final Map env = {}; - final bool result = getBoolFromEnvOrArgs( - flagName, - argResults, - env, - ); - expect(result, false); - }); - }); -} - -class FakeArgs implements ArgResults { - FakeArgs({ - this.arguments = const [], - this.name = 'fake-command', - this.results = const {}, - }); - - final Map results; - - @override - final List arguments; - - @override - final String name; - - @override - ArgResults? get command => throw Exception('Unimplemented'); - - @override - List get rest => throw Exception('Unimplemented'); - - @override - Iterable get options => throw Exception('Unimplemented'); - - @override - bool wasParsed(String name) { - return results[name] != null; - } - - @override - Object? operator[](String name) { - return results[name]; - } } diff --git a/dev/conductor/core/test/next_test.dart b/dev/conductor/core/test/next_test.dart index b3aac64443777..a1dfed957acbb 100644 --- a/dev/conductor/core/test/next_test.dart +++ b/dev/conductor/core/test/next_test.dart @@ -3,14 +3,11 @@ // found in the LICENSE file. import 'package:args/command_runner.dart'; -import 'package:conductor_core/src/git.dart'; -import 'package:conductor_core/src/globals.dart'; import 'package:conductor_core/src/next.dart'; import 'package:conductor_core/src/proto/conductor_state.pb.dart' as pb; import 'package:conductor_core/src/proto/conductor_state.pbenum.dart' show ReleasePhase; import 'package:conductor_core/src/repository.dart'; import 'package:conductor_core/src/state.dart'; -import 'package:conductor_core/src/stdio.dart'; import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:platform/platform.dart'; @@ -18,23 +15,23 @@ import 'package:platform/platform.dart'; import './common.dart'; void main() { - const String flutterRoot = '/flutter'; - const String checkoutsParentDirectory = '$flutterRoot/dev/conductor'; - const String candidateBranch = 'flutter-1.2-candidate.3'; - const String workingBranch = 'cherrypicks-$candidateBranch'; - const String remoteUrl = 'https://github.com/org/repo.git'; - const String revision1 = 'd3af60d18e01fcb36e0c0fa06c8502e4935ed095'; - const String revision2 = 'f99555c1e1392bf2a8135056b9446680c2af4ddf'; - const String revision4 = '280e23318a0d8341415c66aa32581352a421d974'; - const String releaseVersion = '1.2.0-3.0.pre'; - const String releaseChannel = 'beta'; - const String stateFile = '/state-file.json'; - final String localPathSeparator = const LocalPlatform().pathSeparator; - final String localOperatingSystem = const LocalPlatform().pathSeparator; - group('next command', () { + const String flutterRoot = '/flutter'; + const String checkoutsParentDirectory = '$flutterRoot/dev/conductor'; + const String candidateBranch = 'flutter-1.2-candidate.3'; + const String workingBranch = 'cherrypicks-$candidateBranch'; + const String remoteUrl = 'https://github.com/org/repo.git'; + final String localPathSeparator = const LocalPlatform().pathSeparator; + final String localOperatingSystem = const LocalPlatform().pathSeparator; + const String revision1 = 'd3af60d18e01fcb36e0c0fa06c8502e4935ed095'; + const String revision2 = 'f99555c1e1392bf2a8135056b9446680c2af4ddf'; + const String revision3 = '98a5ca242b9d270ce000b26309b8a3cdc9c89df5'; + const String revision4 = '280e23318a0d8341415c66aa32581352a421d974'; + const String releaseVersion = '1.2.0-3.0.pre'; + const String releaseChannel = 'beta'; late MemoryFileSystem fileSystem; late TestStdio stdio; + const String stateFile = '/state-file.json'; setUp(() { stdio = TestStdio(); @@ -81,7 +78,12 @@ void main() { group('APPLY_ENGINE_CHERRYPICKS to CODESIGN_ENGINE_BINARIES', () { test('does not prompt user and updates currentPhase if there are no engine cherrypicks', () async { - final FakeProcessManager processManager = FakeProcessManager.empty(); + final FakeProcessManager processManager = FakeProcessManager.list([ + const FakeCommand(command: ['git', 'fetch', 'upstream']), + const FakeCommand( + command: ['git', 'checkout', workingBranch], + ), + ]); final FakePlatform platform = FakePlatform( environment: { 'HOME': ['path', 'to', 'home'].join(localPathSeparator), @@ -139,7 +141,24 @@ void main() { final File ciYaml = fileSystem.file('$checkoutsParentDirectory/engine/.ci.yaml') ..createSync(recursive: true); _initializeCiYamlFile(ciYaml); - final FakeProcessManager processManager = FakeProcessManager.empty(); + final FakeProcessManager processManager = FakeProcessManager.list([ + const FakeCommand(command: ['git', 'fetch', 'upstream']), + const FakeCommand(command: ['git', 'checkout', workingBranch]), + const FakeCommand( + command: ['git', 'status', '--porcelain'], + stdout: 'MM blah', + ), + const FakeCommand(command: ['git', 'add', '--all']), + const FakeCommand(command: [ + 'git', + 'commit', + "--message='add branch $candidateBranch to enabled_branches in .ci.yaml'", + ]), + const FakeCommand( + command: ['git', 'rev-parse', 'HEAD'], + stdout: revision2, + ), + ]); final FakePlatform platform = FakePlatform( environment: { 'HOME': ['path', 'to', 'home'].join(localPathSeparator), @@ -205,6 +224,16 @@ void main() { _initializeCiYamlFile(file); }, ), + const FakeCommand( + command: ['git', 'status', '--porcelain'], + stdout: 'MM .ci.yaml', + ), + const FakeCommand(command: ['git', 'add', '--all']), + const FakeCommand(command: ['git', 'commit', "--message='add branch $candidateBranch to enabled_branches in .ci.yaml'"]), + const FakeCommand( + command: ['git', 'rev-parse', 'HEAD'], + stdout: revision2, + ), const FakeCommand(command: ['git', 'push', 'mirror', 'HEAD:refs/heads/$workingBranch']), ]); final FakePlatform platform = FakePlatform( @@ -322,7 +351,6 @@ void main() { fileSystem.file(stateFile), ); - expect(processManager, hasNoRemainingExpectations); expect(stdio.stdout, contains('Has CI passed for the engine PR and binaries been codesigned? (y/n) ')); expect(finalState.currentPhase, ReleasePhase.CODESIGN_ENGINE_BINARIES); expect(stdio.error.contains('Aborting command.'), true); @@ -360,7 +388,6 @@ void main() { fileSystem.file(stateFile), ); - expect(processManager, hasNoRemainingExpectations); expect(stdio.stdout, contains('Has CI passed for the engine PR and binaries been codesigned? (y/n) ')); expect(finalState.currentPhase, ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS); }); @@ -493,6 +520,20 @@ void main() { _initializeCiYamlFile(file); }, ), + const FakeCommand( + command: ['git', 'status', '--porcelain'], + stdout: 'MM /path/to/.ci.yaml', + ), + const FakeCommand(command: ['git', 'add', '--all']), + const FakeCommand(command: [ + 'git', + 'commit', + "--message='add branch $candidateBranch to enabled_branches in .ci.yaml'", + ]), + const FakeCommand( + command: ['git', 'rev-parse', 'HEAD'], + stdout: revision3, + ), const FakeCommand( command: ['git', 'status', '--porcelain'], stdout: 'MM /path/to/engine.version', @@ -569,6 +610,20 @@ void main() { ), const FakeCommand(command: ['git', 'fetch', 'upstream']), const FakeCommand(command: ['git', 'checkout', workingBranch]), + const FakeCommand( + command: ['git', 'status', '--porcelain'], + stdout: 'MM path/to/.ci.yaml', + ), + const FakeCommand(command: ['git', 'add', '--all']), + const FakeCommand(command: [ + 'git', + 'commit', + "--message='add branch $candidateBranch to enabled_branches in .ci.yaml'", + ]), + const FakeCommand( + command: ['git', 'rev-parse', 'HEAD'], + stdout: revision3, + ), const FakeCommand( command: ['git', 'status', '--porcelain'], stdout: 'MM path/to/engine.version', @@ -638,6 +693,20 @@ void main() { stdout: 'MM path/to/.ci.yaml', ), const FakeCommand(command: ['git', 'add', '--all']), + const FakeCommand(command: [ + 'git', + 'commit', + "--message='add branch $candidateBranch to enabled_branches in .ci.yaml'", + ]), + const FakeCommand( + command: ['git', 'rev-parse', 'HEAD'], + stdout: revision3, + ), + const FakeCommand( + command: ['git', 'status', '--porcelain'], + stdout: 'MM path/to/engine.version', + ), + const FakeCommand(command: ['git', 'add', '--all']), const FakeCommand(command: [ 'git', 'commit', @@ -893,8 +962,6 @@ void main() { }); test('updates currentPhase if user responds yes', () async { - stdio.stdin.add('y'); - // for kSynchronizeDevWithBeta stdio.stdin.add('y'); final FakeProcessManager processManager = FakeProcessManager.list([ const FakeCommand( @@ -910,10 +977,6 @@ void main() { const FakeCommand( command: ['git', 'push', FrameworkRepository.defaultUpstream, '$revision1:$releaseChannel'], ), - // for kSynchronizeDevWithBeta - const FakeCommand( - command: ['git', 'push', FrameworkRepository.defaultUpstream, '$revision1:dev'], - ), ]); writeStateToFile( fileSystem.file(stateFile), @@ -991,27 +1054,6 @@ void main() { }); group('prompt', () { - test('can be overridden for different frontend implementations', () async { - final FileSystem fileSystem = MemoryFileSystem.test(); - final Stdio stdio = _UnimplementedStdio.instance; - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory('/'), - platform: FakePlatform(), - processManager: FakeProcessManager.empty(), - stdio: stdio, - ); - final _TestNextContext context = _TestNextContext( - checkouts: checkouts, - stateFile: fileSystem.file('/statefile.json'), - ); - - final bool response = await context.prompt( - 'A prompt that will immediately be agreed to', - ); - expect(response, true); - }); - test('throws if user inputs character that is not "y" or "n"', () { final FileSystem fileSystem = MemoryFileSystem.test(); final TestStdio stdio = TestStdio( @@ -1033,142 +1075,11 @@ void main() { ); expect( - () => context.prompt('Asking a question?'), + () => context.prompt('Asking a question?', stdio), throwsExceptionWith('Unknown user input (expected "y" or "n")'), ); }); }); - - group('.pushWorkingBranch()', () { - late MemoryFileSystem fileSystem; - late TestStdio stdio; - late Platform platform; - - setUp(() { - stdio = TestStdio(); - fileSystem = MemoryFileSystem.test(); - platform = FakePlatform(); - }); - - test('catches GitException if the push was rejected and instead throws a helpful ConductorException', () async { - const String gitPushErrorMessage = ''' - To github.com:user/engine.git - - ! [rejected] HEAD -> cherrypicks-flutter-2.8-candidate.3 (non-fast-forward) - error: failed to push some refs to 'github.com:user/engine.git' - hint: Updates were rejected because the tip of your current branch is behind - hint: its remote counterpart. Integrate the remote changes (e.g. - hint: 'git pull ...') before pushing again. - hint: See the 'Note about fast-forwards' in 'git push --help' for details. -'''; - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory)..createSync(recursive: true), - platform: platform, - processManager: FakeProcessManager.empty(), - stdio: stdio, - ); - final Repository testRepository = _TestRepository.fromCheckouts(checkouts); - final pb.Repository testPbRepository = pb.Repository(); - (checkouts.processManager as FakeProcessManager).addCommands([ - FakeCommand( - command: ['git', 'clone', '--origin', 'upstream', '--', testRepository.upstreamRemote.url, '/flutter/dev/conductor/flutter_conductor_checkouts/test-repo/test-repo'], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision1, - ), - FakeCommand( - command: const ['git', 'push', '', 'HEAD:refs/heads/'], - exception: GitException(gitPushErrorMessage, ['git', 'push', '--force', '', 'HEAD:refs/heads/']), - ) - ]); - final NextContext nextContext = NextContext( - autoAccept: false, - checkouts: checkouts, - force: false, - stateFile: fileSystem.file(stateFile), - ); - - expect( - () => nextContext.pushWorkingBranch(testRepository, testPbRepository), - throwsA(isA().having( - (ConductorException exception) => exception.message, - 'has correct message', - contains('Re-run this command with --force to overwrite the remote branch'), - )), - ); - }); - }); -} - -/// A [Stdio] that will throw an exception if any of its methods are called. -class _UnimplementedStdio implements Stdio { - const _UnimplementedStdio(); - - static const _UnimplementedStdio _instance = _UnimplementedStdio(); - static _UnimplementedStdio get instance => _instance; - - Never _throw() => throw Exception('Unimplemented!'); - - @override - List get logs => _throw(); - - @override - void printError(String message) => _throw(); - - @override - void printWarning(String message) => _throw(); - - @override - void printStatus(String message) => _throw(); - - @override - void printTrace(String message) => _throw(); - - @override - void write(String message) => _throw(); - - @override - String readLineSync() => _throw(); -} - -class _TestRepository extends Repository { - _TestRepository.fromCheckouts(Checkouts checkouts, [String name = 'test-repo']) : super( - fileSystem: checkouts.fileSystem, - parentDirectory: checkouts.directory.childDirectory(name), - platform: checkouts.platform, - processManager: checkouts.processManager, - name: name, - requiredLocalBranches: [], - stdio: checkouts.stdio, - upstreamRemote: const Remote(name: RemoteName.upstream, url: 'git@github.com:upstream/repo.git'), - ); - - @override - Future<_TestRepository> cloneRepository(String? cloneName) async { - throw Exception('Unimplemented!'); - } -} - -class _TestNextContext extends NextContext { - const _TestNextContext({ - bool autoAccept = false, - bool force = false, - required File stateFile, - required Checkouts checkouts, - }) : super( - autoAccept: autoAccept, - force: force, - checkouts: checkouts, - stateFile: stateFile, - ); - - @override - Future prompt(String message) { - // always say yes - return Future.value(true); - } } void _initializeCiYamlFile( diff --git a/dev/conductor/core/test/repository_test.dart b/dev/conductor/core/test/repository_test.dart index 5fe2f18c24459..32a7429a67c4d 100644 --- a/dev/conductor/core/test/repository_test.dart +++ b/dev/conductor/core/test/repository_test.dart @@ -13,27 +13,24 @@ void main() { group('repository', () { late FakePlatform platform; const String rootDir = '/'; - late MemoryFileSystem fileSystem; - late FakeProcessManager processManager; - late TestStdio stdio; setUp(() { final String pathSeparator = const LocalPlatform().pathSeparator; - fileSystem = MemoryFileSystem.test(); platform = FakePlatform( environment: { 'HOME': ['path', 'to', 'home'].join(pathSeparator), }, pathSeparator: pathSeparator, ); - processManager = FakeProcessManager.empty(); - stdio = TestStdio(); }); test('canCherryPick returns true if git cherry-pick returns 0', () async { const String commit = 'abc123'; - processManager.addCommands([ + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = + FakeProcessManager.list([ FakeCommand(command: [ 'git', 'clone', @@ -44,11 +41,6 @@ void main() { fileSystem.path .join(rootDir, 'flutter_conductor_checkouts', 'framework'), ]), - const FakeCommand(command: [ - 'git', - 'checkout', - FrameworkRepository.defaultBranch, - ]), const FakeCommand(command: [ 'git', 'rev-parse', @@ -86,7 +78,10 @@ void main() { test('canCherryPick returns false if git cherry-pick returns non-zero', () async { const String commit = 'abc123'; - processManager.addCommands([ + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = + FakeProcessManager.list([ FakeCommand(command: [ 'git', 'clone', @@ -97,11 +92,6 @@ void main() { fileSystem.path .join(rootDir, 'flutter_conductor_checkouts', 'framework'), ]), - const FakeCommand(command: [ - 'git', - 'checkout', - FrameworkRepository.defaultBranch, - ]), const FakeCommand(command: [ 'git', 'rev-parse', @@ -143,7 +133,10 @@ void main() { test('cherryPick() applies the commit', () async { const String commit = 'abc123'; - processManager.addCommands([ + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = + FakeProcessManager.list([ FakeCommand(command: [ 'git', 'clone', @@ -154,11 +147,6 @@ void main() { fileSystem.path .join(rootDir, 'flutter_conductor_checkouts', 'framework'), ]), - const FakeCommand(command: [ - 'git', - 'checkout', - FrameworkRepository.defaultBranch, - ]), const FakeCommand(command: [ 'git', 'rev-parse', @@ -190,6 +178,9 @@ void main() { test('updateDartRevision() updates the DEPS file', () async { const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef'; const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.empty(); final Checkouts checkouts = Checkouts( fileSystem: fileSystem, @@ -209,6 +200,9 @@ void main() { test('updateDartRevision() throws exception on malformed DEPS file', () { const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.empty(); final Checkouts checkouts = Checkouts( fileSystem: fileSystem, @@ -233,7 +227,9 @@ vars = { const String commit1 = 'abc123'; const String commit2 = 'def456'; const String message = 'This is a commit message.'; - processManager.addCommands([ + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.list([ FakeCommand(command: [ 'git', 'clone', @@ -247,7 +243,7 @@ vars = { const FakeCommand(command: [ 'git', 'checkout', - EngineRepository.defaultBranch, + 'upstream/master', ]), const FakeCommand(command: [ 'git', @@ -286,11 +282,13 @@ vars = { ); }); - test('commit() passes correct commit message', () async { + test('commit() passes correct commit message', () { const String commit1 = 'abc123'; const String commit2 = 'def456'; const String message = 'This is a commit message.'; - processManager.addCommands([ + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.list([ FakeCommand(command: [ 'git', 'clone', @@ -304,7 +302,7 @@ vars = { const FakeCommand(command: [ 'git', 'checkout', - EngineRepository.defaultBranch, + 'upstream/master', ]), const FakeCommand(command: [ 'git', @@ -336,15 +334,16 @@ vars = { ); final EngineRepository repo = EngineRepository(checkouts); - await repo.commit(message); - expect(processManager.hasRemainingExpectations, false); + repo.commit(message); }); test('updateEngineRevision() returns false if newCommit is the same as version file', () async { const String commit1 = 'abc123'; const String commit2 = 'def456'; + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); final File engineVersionFile = fileSystem.file('/engine.version')..writeAsStringSync(commit2); - processManager.addCommands([ + final FakeProcessManager processManager = FakeProcessManager.list([ FakeCommand(command: [ 'git', 'clone', @@ -376,6 +375,7 @@ vars = { }); test('CiYaml(file) will throw if file does not exist', () { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); final File file = fileSystem.file('/non/existent/file.txt'); expect( @@ -384,43 +384,40 @@ vars = { ); }); - test('framework repo set as localUpstream ensures requiredLocalBranches exist locally', () async { - const String commit = 'deadbeef'; - const String candidateBranch = 'flutter-1.2-candidate.3'; - bool createdCandidateBranch = false; - processManager.addCommands([ - FakeCommand(command: [ + test('ciYaml.enableBranch() will prepend the given branch to the yaml list of enabled_branches', () async { + const String commit1 = 'abc123'; + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final File ciYaml = fileSystem.file('/flutter_conductor_checkouts/framework/.ci.yaml'); + final ProcessManager processManager = FakeProcessManager.list([ + FakeCommand( + command: [ 'git', 'clone', '--origin', 'upstream', '--', FrameworkRepository.defaultUpstream, - fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'framework'), - ]), - FakeCommand( - command: const ['git', 'checkout', candidateBranch, '--'], - onRun: () => createdCandidateBranch = true, - ), - const FakeCommand( - command: ['git', 'checkout', 'stable', '--'], - ), - const FakeCommand( - command: ['git', 'checkout', 'beta', '--'], - ), - const FakeCommand( - command: ['git', 'checkout', 'dev', '--'], - ), - const FakeCommand( - command: ['git', 'checkout', FrameworkRepository.defaultBranch, '--'], - ), - const FakeCommand( - command: ['git', 'checkout', FrameworkRepository.defaultBranch], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: commit, - ), + fileSystem.path + .join(rootDir, 'flutter_conductor_checkouts', 'framework'), + ], + onRun: () { + ciYaml.createSync(recursive: true); + ciYaml.writeAsStringSync(''' +# Friendly note + +enabled_branches: + - master + - dev + - beta + - stable +'''); + }), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit1), ]); final Checkouts checkouts = Checkouts( fileSystem: fileSystem, @@ -430,43 +427,65 @@ vars = { stdio: stdio, ); - final Repository repo = FrameworkRepository( - checkouts, - additionalRequiredLocalBranches: [candidateBranch], - localUpstream: true, + final FrameworkRepository framework = FrameworkRepository(checkouts); + expect( + (await framework.ciYaml).enabledBranches, + ['master', 'dev', 'beta', 'stable'], ); - // call this so that repo.lazilyInitialize() is called. - await repo.checkoutDirectory; - expect(processManager.hasRemainingExpectations, false); - expect(createdCandidateBranch, true); + (await framework.ciYaml).enableBranch('foo'); + expect( + (await framework.ciYaml).enabledBranches, + ['foo', 'master', 'dev', 'beta', 'stable'], + ); + + expect( + (await framework.ciYaml).stringContents, + ''' +# Friendly note + +enabled_branches: + - foo + - master + - dev + - beta + - stable +''' + ); }); - test('engine repo set as localUpstream ensures requiredLocalBranches exist locally', () async { - const String commit = 'deadbeef'; - const String candidateBranch = 'flutter-1.2-candidate.3'; - bool createdCandidateBranch = false; - processManager.addCommands([ - FakeCommand(command: [ + test('ciYaml.enableBranch() will throw if the input branch is already present in the yaml file', () { + const String commit1 = 'abc123'; + final TestStdio stdio = TestStdio(); + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final File ciYaml = fileSystem.file('/flutter_conductor_checkouts/framework/.ci.yaml'); + final ProcessManager processManager = FakeProcessManager.list([ + FakeCommand( + command: [ 'git', 'clone', '--origin', 'upstream', '--', - EngineRepository.defaultUpstream, - fileSystem.path.join(rootDir, 'flutter_conductor_checkouts', 'engine'), - ]), - FakeCommand( - command: const ['git', 'checkout', candidateBranch, '--'], - onRun: () => createdCandidateBranch = true, - ), - const FakeCommand( - command: ['git', 'checkout', EngineRepository.defaultBranch], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: commit, - ), + FrameworkRepository.defaultUpstream, + fileSystem.path + .join(rootDir, 'flutter_conductor_checkouts', 'framework'), + ], + onRun: () { + ciYaml.createSync(recursive: true); + ciYaml.writeAsStringSync(''' +enabled_branches: + - master + - dev + - beta + - stable +'''); + }), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit1), ]); final Checkouts checkouts = Checkouts( fileSystem: fileSystem, @@ -476,16 +495,11 @@ vars = { stdio: stdio, ); - final Repository repo = EngineRepository( - checkouts, - additionalRequiredLocalBranches: [candidateBranch], - localUpstream: true, + final FrameworkRepository framework = FrameworkRepository(checkouts); + expect( + () async => (await framework.ciYaml).enableBranch('master'), + throwsExceptionWith('.ci.yaml already contains the branch master'), ); - // call this so that repo.lazilyInitialize() is called. - await repo.checkoutDirectory; - - expect(processManager.hasRemainingExpectations, false); - expect(createdCandidateBranch, true); }); }); } diff --git a/dev/conductor/core/test/roll_dev_test.dart b/dev/conductor/core/test/roll_dev_test.dart new file mode 100644 index 0000000000000..cc2b18640eef0 --- /dev/null +++ b/dev/conductor/core/test/roll_dev_test.dart @@ -0,0 +1,708 @@ +// 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 'package:conductor_core/src/repository.dart'; +import 'package:conductor_core/src/roll_dev.dart'; +import 'package:file/memory.dart'; +import 'package:platform/platform.dart'; + +import './common.dart'; + +const String _kUpstreamRemote = 'git@github.com:flutter/flutter.git'; + +void main() { + group('rollDev()', () { + const String usage = 'usage info...'; + const String level = 'm'; + const String commit = 'abcde012345'; + const String remote = 'origin'; + const String lastVersion = '1.2.0-0.0.pre'; + const String nextVersion = '1.2.0-2.0.pre'; + const String candidateBranch = 'flutter-1.2-candidate.2'; + const String checkoutsParentDirectory = '/path/to/directory/'; + late FakeArgResults fakeArgResults; + late MemoryFileSystem fileSystem; + late TestStdio stdio; + late FrameworkRepository repo; + late Checkouts checkouts; + late FakePlatform platform; + late FakeProcessManager processManager; + + setUp(() { + stdio = TestStdio(); + fileSystem = MemoryFileSystem.test(); + platform = FakePlatform(); + processManager = FakeProcessManager.list([]); + checkouts = Checkouts( + fileSystem: fileSystem, + parentDirectory: fileSystem.directory(checkoutsParentDirectory), + platform: platform, + processManager: processManager, + stdio: stdio, + ); + repo = FrameworkRepository(checkouts); + }); + + test('throws Exception if level not provided', () { + fakeArgResults = FakeArgResults( + level: null, + candidateBranch: candidateBranch, + remote: remote, + ); + expect( + () async => rollDev( + argResults: fakeArgResults, + repository: repo, + stdio: stdio, + usage: usage, + ), + throwsExceptionWith(usage), + ); + }); + + test('throws exception if git checkout not clean', () { + processManager.addCommands([ + const FakeCommand(command: [ + 'git', + 'clone', + '--origin', + 'upstream', + '--', + _kUpstreamRemote, + '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'remote', + 'get-url', + remote, + ], stdout: _kUpstreamRemote), + const FakeCommand(command: [ + 'git', + 'status', + '--porcelain', + ], stdout: ' M dev/conductor/bin/conductor.dart'), + ]); + fakeArgResults = FakeArgResults( + level: level, + candidateBranch: candidateBranch, + remote: remote, + ); + expect( + () async => rollDev( + argResults: fakeArgResults, + repository: repo, + stdio: stdio, + usage: usage, + ), + throwsExceptionWith('Your git repository is not clean.'), + ); + }); + + test('does not reset or tag if --just-print is specified', () async { + processManager.addCommands([ + const FakeCommand(command: [ + 'git', + 'clone', + '--origin', + 'upstream', + '--', + _kUpstreamRemote, + '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'remote', + 'get-url', + remote, + ], stdout: _kUpstreamRemote), + const FakeCommand(command: [ + 'git', + 'status', + '--porcelain', + ]), + const FakeCommand(command: [ + 'git', + 'fetch', + remote, + '--tags', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + candidateBranch, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'describe', + '--match', + '*.*.*', + '--exact-match', + '--tags', + 'refs/remotes/$remote/dev', + ], stdout: lastVersion), + const FakeCommand(command: [ + 'git', + 'rev-parse', + lastVersion, + ], stdout: 'zxy321'), + ]); + + fakeArgResults = FakeArgResults( + level: level, + candidateBranch: candidateBranch, + remote: remote, + justPrint: true, + ); + expect( + await rollDev( + usage: usage, + argResults: fakeArgResults, + repository: repo, + stdio: stdio, + ), + false, + ); + expect(stdio.logs.join().contains(nextVersion), true); + }); + + test("exits with exception if --skip-tagging is provided but commit isn't already tagged", () { + processManager.addCommands([ + const FakeCommand(command: [ + 'git', + 'clone', + '--origin', + 'upstream', + '--', + _kUpstreamRemote, + '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'remote', + 'get-url', + remote, + ], stdout: _kUpstreamRemote), + const FakeCommand(command: [ + 'git', + 'status', + '--porcelain', + ]), + const FakeCommand(command: [ + 'git', + 'fetch', + remote, + '--tags', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + candidateBranch, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'describe', + '--match', + '*.*.*', + '--exact-match', + '--tags', + 'refs/remotes/$remote/dev', + ], stdout: lastVersion), + const FakeCommand(command: [ + 'git', + 'rev-parse', + lastVersion, + ], stdout: 'zxy321'), + const FakeCommand(command: [ + 'git', + 'describe', + '--exact-match', + '--tags', + commit, + ], exitCode: 1), + ]); + + const String exceptionMessage = + 'The $kSkipTagging flag is only supported ' + 'for tagged commits.'; + + fakeArgResults = FakeArgResults( + level: level, + candidateBranch: candidateBranch, + remote: remote, + skipTagging: true, + ); + expect( + () async => rollDev( + usage: usage, + argResults: fakeArgResults, + repository: repo, + stdio: stdio, + ), + throwsExceptionWith(exceptionMessage), + ); + }); + + test('throws exception if desired commit is already tip of dev branch', () { + processManager.addCommands([ + const FakeCommand(command: [ + 'git', + 'clone', + '--origin', + 'upstream', + '--', + _kUpstreamRemote, + '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'remote', + 'get-url', + remote, + ], stdout: _kUpstreamRemote), + const FakeCommand(command: [ + 'git', + 'status', + '--porcelain', + ]), + const FakeCommand(command: [ + 'git', + 'fetch', + remote, + '--tags', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + candidateBranch, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'describe', + '--match', + '*.*.*', + '--exact-match', + '--tags', + 'refs/remotes/$remote/dev', + ], stdout: lastVersion), + // [commit] is already [lastVersion] + const FakeCommand(command: [ + 'git', + 'rev-parse', + lastVersion, + ], stdout: commit), + ]); + fakeArgResults = FakeArgResults( + level: level, + candidateBranch: candidateBranch, + remote: remote, + justPrint: true, + ); + expect( + () async => rollDev( + usage: usage, + argResults: fakeArgResults, + repository: repo, + stdio: stdio, + ), + throwsExceptionWith( + 'Commit $commit is already on the dev branch as $lastVersion', + ), + ); + }); + + test( + 'does not tag if last release is not direct ancestor of desired ' + 'commit and --force not supplied', () { + processManager.addCommands([ + const FakeCommand(command: [ + 'git', + 'clone', + '--origin', + 'upstream', + '--', + _kUpstreamRemote, + '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'remote', + 'get-url', + remote, + ], stdout: _kUpstreamRemote), + const FakeCommand(command: [ + 'git', + 'status', + '--porcelain', + ]), + const FakeCommand(command: [ + 'git', + 'fetch', + remote, + '--tags', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + candidateBranch, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'describe', + '--match', + '*.*.*', + '--exact-match', + '--tags', + 'refs/remotes/$remote/dev', + ], stdout: lastVersion), + const FakeCommand(command: [ + 'git', + 'rev-parse', + lastVersion, + ], stdout: 'zxy321'), + const FakeCommand(command: [ + 'git', + 'merge-base', + '--is-ancestor', + lastVersion, + commit, + ], exitCode: 1), + ]); + + fakeArgResults = FakeArgResults( + level: level, + candidateBranch: candidateBranch, + remote: remote, + ); + const String errorMessage = 'The previous dev tag $lastVersion is not a ' + 'direct ancestor of $commit.'; + expect( + () async => rollDev( + argResults: fakeArgResults, + repository: repo, + stdio: stdio, + usage: usage, + ), + throwsExceptionWith(errorMessage), + ); + }); + + test('does not tag but updates branch if --skip-tagging provided', () async { + processManager.addCommands([ + const FakeCommand(command: [ + 'git', + 'clone', + '--origin', + 'upstream', + '--', + _kUpstreamRemote, + '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'remote', + 'get-url', + remote, + ], stdout: _kUpstreamRemote), + const FakeCommand(command: [ + 'git', + 'status', + '--porcelain', + ]), + const FakeCommand(command: [ + 'git', + 'fetch', + remote, + '--tags', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + candidateBranch, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'describe', + '--match', + '*.*.*', + '--exact-match', + '--tags', + 'refs/remotes/$remote/dev', + ], stdout: lastVersion), + const FakeCommand(command: [ + 'git', + 'rev-parse', + lastVersion, + ], stdout: 'zxy321'), + const FakeCommand(command: [ + 'git', + 'describe', + '--exact-match', + '--tags', + commit, + ]), + const FakeCommand(command: [ + 'git', + 'merge-base', + '--is-ancestor', + lastVersion, + commit, + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + commit, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'push', + remote, + '$commit:dev', + ]), + ]); + fakeArgResults = FakeArgResults( + level: level, + candidateBranch: candidateBranch, + remote: remote, + skipTagging: true, + ); + expect( + await rollDev( + usage: usage, + argResults: fakeArgResults, + repository: repo, + stdio: stdio, + ), + true, + ); + }); + + test('successfully tags and publishes release', () async { + processManager.addCommands([ + const FakeCommand(command: [ + 'git', + 'clone', + '--origin', + 'upstream', + '--', + _kUpstreamRemote, + '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'remote', + 'get-url', + remote, + ], stdout: _kUpstreamRemote), + const FakeCommand(command: [ + 'git', + 'status', + '--porcelain', + ]), + const FakeCommand(command: [ + 'git', + 'fetch', + remote, + '--tags', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + candidateBranch, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'describe', + '--match', + '*.*.*', + '--exact-match', + '--tags', + 'refs/remotes/$remote/dev', + ], stdout: lastVersion), + const FakeCommand(command: [ + 'git', + 'rev-parse', + lastVersion, + ], stdout: 'zxy321'), + const FakeCommand(command: [ + 'git', + 'merge-base', + '--is-ancestor', + lastVersion, + commit, + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + commit, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'tag', + nextVersion, + commit, + ]), + const FakeCommand(command: [ + 'git', + 'push', + remote, + nextVersion, + ]), + const FakeCommand(command: [ + 'git', + 'push', + remote, + '$commit:dev', + ]), + ]); + fakeArgResults = FakeArgResults( + level: level, + candidateBranch: candidateBranch, + remote: remote, + ); + expect( + await rollDev( + usage: usage, + argResults: fakeArgResults, + repository: repo, + stdio: stdio, + ), + true, + ); + }); + + test('successfully publishes release with --force', () async { + processManager.addCommands([ + const FakeCommand(command: [ + 'git', + 'clone', + '--origin', + 'upstream', + '--', + _kUpstreamRemote, + '${checkoutsParentDirectory}flutter_conductor_checkouts/framework', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + 'HEAD', + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'remote', + 'get-url', + remote, + ], stdout: _kUpstreamRemote), + const FakeCommand(command: [ + 'git', + 'status', + '--porcelain', + ]), + const FakeCommand(command: [ + 'git', + 'fetch', + remote, + '--tags', + ]), + const FakeCommand(command: [ + 'git', + 'rev-parse', + candidateBranch, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'describe', + '--match', + '*.*.*', + '--exact-match', + '--tags', + 'refs/remotes/$remote/dev', + ], stdout: lastVersion), + const FakeCommand(command: [ + 'git', + 'rev-parse', + lastVersion, + ], stdout: 'zxy321'), + const FakeCommand(command: [ + 'git', + 'rev-parse', + commit, + ], stdout: commit), + const FakeCommand(command: [ + 'git', + 'tag', + nextVersion, + commit, + ]), + const FakeCommand(command: [ + 'git', + 'push', + remote, + nextVersion, + ]), + const FakeCommand(command: [ + 'git', + 'push', + '--force', + remote, + '$commit:dev', + ]), + ]); + + fakeArgResults = FakeArgResults( + level: level, + candidateBranch: candidateBranch, + remote: remote, + force: true, + ); + expect( + await rollDev( + argResults: fakeArgResults, + repository: repo, + stdio: stdio, + usage: usage, + ), + true, + ); + expect(processManager.hasRemainingExpectations, false); + }); + }, onPlatform: { + 'windows': const Skip('Flutter Conductor only supported on macos/linux'), + }); +} diff --git a/dev/conductor/core/test/start_test.dart b/dev/conductor/core/test/start_test.dart index 88857c8170213..efbee1ff76d98 100644 --- a/dev/conductor/core/test/start_test.dart +++ b/dev/conductor/core/test/start_test.dart @@ -5,7 +5,6 @@ import 'dart:convert' show jsonDecode; import 'package:args/command_runner.dart'; -import 'package:conductor_core/src/globals.dart'; import 'package:conductor_core/src/proto/conductor_state.pb.dart' as pb; import 'package:conductor_core/src/proto/conductor_state.pbenum.dart' show ReleasePhase; import 'package:conductor_core/src/repository.dart'; @@ -123,81 +122,22 @@ void main() { ); }); - test('does not fail if version wrong but --force provided', () async { + test('creates state file if provided correct inputs', () async { const String revision2 = 'def789'; const String revision3 = '123abc'; const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef'; const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; const String previousVersion = '1.2.0-1.0.pre'; - // This is what this release will be - const String nextVersion = '1.2.0-1.1.pre'; - const String incrementLevel = 'n'; + const String nextVersion = '1.2.0-3.0.pre'; + const String incrementLevel = 'm'; - final Directory engine = fileSystem - .directory(checkoutsParentDirectory) + final Directory engine = fileSystem.directory(checkoutsParentDirectory) .childDirectory('flutter_conductor_checkouts') .childDirectory('engine'); final File depsFile = engine.childFile('DEPS'); final List engineCommands = [ - FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - EngineRepository.defaultUpstream, - engine.path, - ], - onRun: () { - // Create the DEPS file which the tool will update - engine.createSync(recursive: true); - depsFile.writeAsStringSync(generateMockDeps(previousDartRevision)); - }), - const FakeCommand( - command: ['git', 'remote', 'add', 'mirror', engineMirror], - ), - const FakeCommand( - command: ['git', 'fetch', 'mirror'], - ), - const FakeCommand( - command: ['git', 'checkout', 'upstream/$candidateBranch'], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision2, - ), - const FakeCommand( - command: [ - 'git', - 'checkout', - '-b', - 'cherrypicks-$candidateBranch', - ], - ), - const FakeCommand( - command: ['git', 'status', '--porcelain'], - stdout: 'MM path/to/DEPS', - ), - const FakeCommand( - command: ['git', 'add', '--all'], - ), - const FakeCommand( - command: ['git', 'commit', "--message='Update Dart SDK to $nextDartRevision'"], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision2, - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision2, - ), - ]; - - final List frameworkCommands = [ FakeCommand( command: [ 'git', @@ -205,143 +145,15 @@ void main() { '--origin', 'upstream', '--', - FrameworkRepository.defaultUpstream, - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - ), - ], - ), - const FakeCommand( - command: ['git', 'remote', 'add', 'mirror', frameworkMirror], - ), - const FakeCommand( - command: ['git', 'fetch', 'mirror'], - ), - const FakeCommand( - command: ['git', 'checkout', 'upstream/$candidateBranch'], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision3, - ), - const FakeCommand( - command: [ - 'git', - 'checkout', - '-b', - 'cherrypicks-$candidateBranch', - ], - ), - const FakeCommand( - command: [ - 'git', - 'describe', - '--match', - '*.*.*', - '--tags', - 'refs/remotes/upstream/$candidateBranch', + EngineRepository.defaultUpstream, + engine.path, ], - stdout: '$previousVersion-42-gabc123', + onRun: () { + // Create the DEPS file which the tool will update + engine.createSync(recursive: true); + depsFile.writeAsStringSync(generateMockDeps(previousDartRevision)); + } ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision3, - ), - ]; - - final CommandRunner runner = createRunner( - commands: [ - ...engineCommands, - ...frameworkCommands, - ], - ); - - final String stateFilePath = fileSystem.path.join( - platform.environment['HOME']!, - kStateFileName, - ); - - await runner.run([ - 'start', - '--$kFrameworkMirrorOption', - frameworkMirror, - '--$kEngineMirrorOption', - engineMirror, - '--$kCandidateOption', - candidateBranch, - '--$kReleaseOption', - releaseChannel, - '--$kStateOption', - stateFilePath, - '--$kDartRevisionOption', - nextDartRevision, - '--$kIncrementOption', - incrementLevel, - '--$kForceFlag', - ]); - - final File stateFile = fileSystem.file(stateFilePath); - - final pb.ConductorState state = pb.ConductorState(); - state.mergeFromProto3Json( - jsonDecode(stateFile.readAsStringSync()), - ); - - expect(processManager.hasRemainingExpectations, false); - expect(state.isInitialized(), true); - expect(state.releaseChannel, releaseChannel); - expect(state.releaseVersion, nextVersion); - expect(state.engine.candidateBranch, candidateBranch); - expect(state.engine.startingGitHead, revision2); - expect(state.engine.dartRevision, nextDartRevision); - expect(state.engine.upstream.url, 'git@github.com:flutter/engine.git'); - expect(state.framework.candidateBranch, candidateBranch); - expect(state.framework.startingGitHead, revision3); - expect(state.framework.upstream.url, 'git@github.com:flutter/flutter.git'); - expect(state.currentPhase, ReleasePhase.APPLY_ENGINE_CHERRYPICKS); - expect(state.conductorVersion, conductorVersion); - expect(state.incrementLevel, incrementLevel); - }); - - test('creates state file if provided correct inputs', () async { - stdio.stdin.add('y'); // accept prompt from ensureBranchPointTagged() - const String revision2 = 'def789'; - const String revision3 = '123abc'; - const String branchPointRevision = 'deadbeef'; - const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef'; - const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; - const String previousVersion = '1.2.0-1.0.pre'; - // This is a git tag applied to the branch point, not an actual release - const String branchPointTag = '1.2.0-3.0.pre'; - // This is what this release will be - const String nextVersion = '1.2.0-3.1.pre'; - const String incrementLevel = 'm'; - - final Directory engine = fileSystem - .directory(checkoutsParentDirectory) - .childDirectory('flutter_conductor_checkouts') - .childDirectory('engine'); - - final File depsFile = engine.childFile('DEPS'); - - final List engineCommands = [ - FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - EngineRepository.defaultUpstream, - engine.path, - ], - onRun: () { - // Create the DEPS file which the tool will update - engine.createSync(recursive: true); - depsFile.writeAsStringSync(generateMockDeps(previousDartRevision)); - }), const FakeCommand( command: ['git', 'remote', 'add', 'mirror', engineMirror], ), @@ -431,16 +243,6 @@ void main() { ], stdout: '$previousVersion-42-gabc123', ), - const FakeCommand( - command: ['git', 'merge-base', candidateBranch, 'master'], - stdout: branchPointRevision, - ), - const FakeCommand( - command: ['git', 'tag', branchPointTag, branchPointRevision], - ), - const FakeCommand( - command: ['git', 'push', FrameworkRepository.defaultUpstream, branchPointTag], - ), const FakeCommand( command: ['git', 'rev-parse', 'HEAD'], stdout: revision3, @@ -498,9 +300,6 @@ void main() { expect(state.currentPhase, ReleasePhase.APPLY_ENGINE_CHERRYPICKS); expect(state.conductorVersion, conductorVersion); expect(state.incrementLevel, incrementLevel); - expect(stdio.stdout, contains('Applying the tag $branchPointTag at the branch point $branchPointRevision')); - expect(stdio.stdout, contains('The actual release will be version $nextVersion')); - expect(branchPointTag != nextVersion, true); }); test('can convert from dev style version to stable version', () async { @@ -512,8 +311,7 @@ void main() { const String nextVersion = '1.2.0'; const String incrementLevel = 'z'; - final Directory engine = fileSystem - .directory(checkoutsParentDirectory) + final Directory engine = fileSystem.directory(checkoutsParentDirectory) .childDirectory('flutter_conductor_checkouts') .childDirectory('engine'); @@ -521,20 +319,21 @@ void main() { final List engineCommands = [ FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - EngineRepository.defaultUpstream, - engine.path, - ], - onRun: () { - // Create the DEPS file which the tool will update - engine.createSync(recursive: true); - depsFile.writeAsStringSync(generateMockDeps(previousDartRevision)); - }), + command: [ + 'git', + 'clone', + '--origin', + 'upstream', + '--', + EngineRepository.defaultUpstream, + engine.path, + ], + onRun: () { + // Create the DEPS file which the tool will update + engine.createSync(recursive: true); + depsFile.writeAsStringSync(generateMockDeps(previousDartRevision)); + } + ), const FakeCommand( command: ['git', 'remote', 'add', 'mirror', engineMirror], ), @@ -680,202 +479,6 @@ void main() { expect(state.conductorVersion, conductorVersion); expect(state.incrementLevel, incrementLevel); }); - - test('StartContext gets engine and framework checkout directories after run', () async { - stdio.stdin.add('y'); - const String revision2 = 'def789'; - const String revision3 = '123abc'; - const String branchPointRevision = 'deadbeef'; - const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef'; - const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; - const String previousVersion = '1.2.0-1.0.pre'; - // This is a git tag applied to the branch point, not an actual release - const String branchPointTag = '1.2.0-3.0.pre'; - // This is what this release will be - const String incrementLevel = 'm'; - - final Directory engine = fileSystem - .directory(checkoutsParentDirectory) - .childDirectory('flutter_conductor_checkouts') - .childDirectory('engine'); - - final Directory framework = fileSystem - .directory(checkoutsParentDirectory) - .childDirectory('flutter_conductor_checkouts') - .childDirectory('framework'); - - final File depsFile = engine.childFile('DEPS'); - - final List engineCommands = [ - FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - EngineRepository.defaultUpstream, - engine.path, - ], - onRun: () { - // Create the DEPS file which the tool will update - engine.createSync(recursive: true); - depsFile.writeAsStringSync(generateMockDeps(previousDartRevision)); - }), - const FakeCommand( - command: ['git', 'remote', 'add', 'mirror', engineMirror], - ), - const FakeCommand( - command: ['git', 'fetch', 'mirror'], - ), - const FakeCommand( - command: ['git', 'checkout', 'upstream/$candidateBranch'], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision2, - ), - const FakeCommand( - command: [ - 'git', - 'checkout', - '-b', - 'cherrypicks-$candidateBranch', - ], - ), - const FakeCommand( - command: ['git', 'status', '--porcelain'], - stdout: 'MM path/to/DEPS', - ), - const FakeCommand( - command: ['git', 'add', '--all'], - ), - const FakeCommand( - command: ['git', 'commit', "--message='Update Dart SDK to $nextDartRevision'"], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision2, - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision2, - ), - ]; - - final List frameworkCommands = [ - FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - FrameworkRepository.defaultUpstream, - framework.path, - ], - ), - const FakeCommand( - command: ['git', 'remote', 'add', 'mirror', frameworkMirror], - ), - const FakeCommand( - command: ['git', 'fetch', 'mirror'], - ), - const FakeCommand( - command: ['git', 'checkout', 'upstream/$candidateBranch'], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision3, - ), - const FakeCommand( - command: [ - 'git', - 'checkout', - '-b', - 'cherrypicks-$candidateBranch', - ], - ), - const FakeCommand( - command: [ - 'git', - 'describe', - '--match', - '*.*.*', - '--tags', - 'refs/remotes/upstream/$candidateBranch', - ], - stdout: '$previousVersion-42-gabc123', - ), - const FakeCommand( - command: ['git', 'merge-base', candidateBranch, 'master'], - stdout: branchPointRevision, - ), - const FakeCommand( - command: ['git', 'tag', branchPointTag, branchPointRevision], - ), - const FakeCommand( - command: ['git', 'push', FrameworkRepository.defaultUpstream, branchPointTag], - ), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: revision3, - ), - ]; - - final String operatingSystem = const LocalPlatform().operatingSystem; - final Map environment = { - 'HOME': '/path/to/user/home', - }; - final Directory homeDir = fileSystem.directory( - environment['HOME'], - ); - // Tool assumes this exists - homeDir.createSync(recursive: true); - platform = FakePlatform( - environment: environment, - operatingSystem: operatingSystem, - ); - - final String stateFilePath = fileSystem.path.join( - platform.environment['HOME']!, - kStateFileName, - ); - final File stateFile = fileSystem.file(stateFilePath); - - processManager = FakeProcessManager.list([ - ...engineCommands, - ...frameworkCommands, - ]); - checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - - final StartContext startContext = StartContext( - candidateBranch: candidateBranch, - checkouts: checkouts, - dartRevision: nextDartRevision, - engineCherrypickRevisions: [], - engineMirror: engineMirror, - engineUpstream: EngineRepository.defaultUpstream, - frameworkCherrypickRevisions: [], - frameworkMirror: frameworkMirror, - frameworkUpstream: FrameworkRepository.defaultUpstream, - releaseChannel: releaseChannel, - incrementLetter: incrementLevel, - processManager: processManager, - conductorVersion: conductorVersion, - stateFile: stateFile); - - await startContext.run(); - - expect((await startContext.engine.checkoutDirectory).path, equals(engine.path)); - expect((await startContext.framework.checkoutDirectory).path, equals(framework.path)); - }); }, onPlatform: { 'windows': const Skip('Flutter Conductor only supported on macos/linux'), }); diff --git a/dev/conductor/core/test/version_test.dart b/dev/conductor/core/test/version_test.dart index 6eae350af172b..7bfa52922178c 100644 --- a/dev/conductor/core/test/version_test.dart +++ b/dev/conductor/core/test/version_test.dart @@ -7,24 +7,6 @@ import 'package:conductor_core/src/version.dart'; import './common.dart'; void main() { - group('Version.fromString()', () { - test('parses commits past a tagged stable', () { - const String versionString = '2.8.0-1-g2ef5ad67fe'; - final Version version; - try { - version = Version.fromString(versionString); - } on Exception catch (exception) { - fail('Failed parsing "$versionString" with:\n$exception'); - } - expect(version.x, 2); - expect(version.y, 8); - expect(version.z, 0); - expect(version.m, isNull); - expect(version.n, isNull); - expect(version.commits, 1); - expect(version.type, VersionType.gitDescribe); - }); - }); group('Version.increment()', () { test('throws exception on nonsensical `level`', () { final List levels = ['f', '0', 'xyz']; diff --git a/dev/customer_testing/ci.bat b/dev/customer_testing/ci.bat index d8669892d2560..d6feb0f761f4c 100644 --- a/dev/customer_testing/ci.bat +++ b/dev/customer_testing/ci.bat @@ -16,4 +16,4 @@ CD ..\customer_testing CMD /S /C "IF EXIST "..\..\bin\cache\pkg\tests\" RMDIR /S /Q ..\..\bin\cache\pkg\tests" git clone https://github.com/flutter/tests.git ..\..\bin\cache\pkg\tests FOR /F "usebackq tokens=*" %%a IN (`dart --enable-asserts ..\tools\bin\find_commit.dart ..\..\bin\cache\pkg\tests`) DO git -C ..\..\bin\cache\pkg\tests checkout %%a -dart --enable-asserts run_tests.dart --verbose --skip-on-fetch-failure --skip-template ..\..\bin\cache\pkg\tests\registry\*.test +dart --enable-asserts run_tests.dart --skip-on-fetch-failure --skip-template ..\..\bin\cache\pkg\tests\registry\*.test diff --git a/dev/customer_testing/ci.sh b/dev/customer_testing/ci.sh index 495b21c6fd83b..17f04b9978e62 100755 --- a/dev/customer_testing/ci.sh +++ b/dev/customer_testing/ci.sh @@ -34,4 +34,4 @@ git clone https://github.com/flutter/tests.git ../../bin/cache/pkg/tests git -C ../../bin/cache/pkg/tests checkout `dart --enable-asserts ../tools/bin/find_commit.dart ../../bin/cache/pkg/tests` # Finally, run the tests. -dart --enable-asserts run_tests.dart --verbose --skip-on-fetch-failure --skip-template ../../bin/cache/pkg/tests/registry/*.test +dart --enable-asserts run_tests.dart --skip-on-fetch-failure --skip-template ../../bin/cache/pkg/tests/registry/*.test diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index df860c2a3b9ca..7a38044aa6ff1 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -6,7 +6,7 @@ environment: dependencies: args: 2.3.0 - path: 1.8.1 + path: 1.8.0 glob: 2.0.2 meta: 1.7.0 @@ -19,10 +19,10 @@ dependencies: term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -32,12 +32,13 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,13 +49,13 @@ dev_dependencies: source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 80de +# PUBSPEC CHECKSUM: efa5 diff --git a/dev/devicelab/README.md b/dev/devicelab/README.md index d6e75d7d3cf4d..cf744479e2b55 100644 --- a/dev/devicelab/README.md +++ b/dev/devicelab/README.md @@ -206,14 +206,27 @@ There are several PRs needed to add a DeviceLab task to CI. _TASK_- the name of your test that also matches the name of the file in `bin/tasks` without the `.dart` extension. -1. Add target to - [.ci.yaml](https://github.com/flutter/flutter/blob/master/.ci.yaml) - - Mirror an existing one that has the recipe `devicelab_drone` - -If your test needs to run on multiple operating systems, create a separate -target for each operating system. +1. Add prod builder to [flutter/infra devicelab_config.star](https://github.com/flutter/infra/blob/master/config/devicelab_config.star) + - Example PR: https://github.com/flutter/infra/pull/401/files + - This will need to soak for 15 minutes after merged to propagate (should show up in [LUCI console](https://ci.chromium.org/p/flutter/g/devicelab/console)) + - There are various lists for the different testbeds a test can run on +2. Add task to [flutter/flutter prod_builders.json](https://github.com/flutter/flutter/blob/master/dev/prod_builders.json) + - Example PR: https://github.com/flutter/flutter/pull/79913/files + - Set `flaky: true` for validation before blocking tree +3. After 10 green runs, update [flutter/flutter prod_builders.json](https://github.com/flutter/flutter/blob/master/dev/prod_builders.json) to `flaky:false` + +If your test needs to run on multiple operating systems, create a separate test +for each operating system. ## Adding tests to presubmit -Flutter's DeviceLab has a limited capacity in presubmit. File an infra ticket -to investigate feasibility of adding a test to presubmit. +Flutter's DeviceLab does not currently have capacity to run tests against physical devices in presubmit. + +Note that DeviceLab tests should generally require a tethered device. If you are adding host-only tests, considering adding your test to `packages/flutter_tools/test/integration.shard`. Example: https://github.com/flutter/flutter/pull/73577/files" + +1. Add try builder to [flutter/infra devicelab_config.star](https://github.com/flutter/infra/blob/master/config/devicelab_config.star) + - Example PR: https://github.com/flutter/infra/pull/401/files + - This will need to soak for 15 minutes after merged to propagate + - There are various lists for the different testbeds a test can run on +2. Add task to [flutter/flutter try_builders.json](https://github.com/flutter/flutter/blob/master/dev/try_builders.json) + - Example PR: https://github.com/flutter/flutter/pull/79913/files diff --git a/dev/devicelab/bin/run.dart b/dev/devicelab/bin/run.dart index d4589bda37c30..515b3a185adc9 100644 --- a/dev/devicelab/bin/run.dart +++ b/dev/devicelab/bin/run.dart @@ -13,108 +13,102 @@ import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/utils.dart'; import 'package:path/path.dart' as path; -/// Runs tasks. -/// -/// The tasks are chosen depending on the command-line options. -Future main(List rawArgs) async { - // This is populated by a callback in the ArgParser. - final List taskNames = []; - final ArgParser argParser = createArgParser(taskNames); +late ArgResults args; - ArgResults args; - try { - args = argParser.parse(rawArgs); // populates taskNames as a side-effect - } on FormatException catch (error) { - stderr.writeln('${error.message}\n'); - stderr.writeln('Usage:\n'); - stderr.writeln(argParser.usage); - exit(1); - } +List _taskNames = []; + +/// The device-id to run test on. +String? deviceId; + +/// The git branch being tested on. +String? gitBranch; - /// Suppresses standard output, prints only standard error output. - final bool silent = (args['silent'] as bool?) ?? false; +/// The build of the local engine to use. +/// +/// Required for A/B test mode. +String? localEngine; - /// The build of the local engine to use. - /// - /// Required for A/B test mode. - final String? localEngine = args['local-engine'] as String?; +/// The path to the engine "src/" directory. +String? localEngineSrcPath; - /// The path to the engine "src/" directory. - final String? localEngineSrcPath = args['local-engine-src-path'] as String?; +/// Name of the LUCI builder this test is currently running on. +/// +/// This is only passed on CI runs for Cocoon to be able to uniquely identify +/// this test run. +String? luciBuilder; - /// The device-id to run test on. - final String? deviceId = args['device-id'] as String?; +/// Whether to exit on first test failure. +bool exitOnFirstTestFailure = false; - /// Whether to exit on first test failure. - final bool exitOnFirstTestFailure = (args['exit'] as bool?) ?? false; +/// Path to write test results to. +String? resultsPath; - /// Whether to tell tasks to clean up after themselves. - final bool terminateStrayDartProcesses = (args['terminate-stray-dart-processes'] as bool?) ?? false; +/// File containing a service account token. +/// +/// If passed, the test run results will be uploaded to Flutter infrastructure. +String? serviceAccountTokenFile; - /// The git branch being tested on. - final String? gitBranch = args['git-branch'] as String?; +/// Suppresses standard output, prints only standard error output. +bool silent = false; - /// Name of the LUCI builder this test is currently running on. - /// - /// This is only passed on CI runs for Cocoon to be able to uniquely identify - /// this test run. - final String? luciBuilder = args['luci-builder'] as String?; +/// Runs tasks. +/// +/// The tasks are chosen depending on the command-line options +/// (see [_argParser]). +Future main(List rawArgs) async { + try { + args = _argParser.parse(rawArgs); + } on FormatException catch (error) { + stderr.writeln('${error.message}\n'); + stderr.writeln('Usage:\n'); + stderr.writeln(_argParser.usage); + exitCode = 1; + return; + } - /// Path to write test results to. - final String? resultsPath = args['results-file'] as String?; + deviceId = args['device-id'] as String?; + exitOnFirstTestFailure = (args['exit'] as bool?) ?? false; + gitBranch = args['git-branch'] as String?; + localEngine = args['local-engine'] as String?; + localEngineSrcPath = args['local-engine-src-path'] as String?; + luciBuilder = args['luci-builder'] as String?; + resultsPath = args['results-file'] as String?; + serviceAccountTokenFile = args['service-account-token-file'] as String?; + silent = (args['silent'] as bool?) ?? false; if (!args.wasParsed('task')) { if (args.wasParsed('stage') || args.wasParsed('all')) { addTasks( tasks: loadTaskManifest().tasks, args: args, - taskNames: taskNames, + taskNames: _taskNames, ); } } if (args.wasParsed('list')) { - for (int i = 0; i < taskNames.length; i++) { - print('${(i + 1).toString().padLeft(3)} - ${taskNames[i]}'); + for (int i = 0; i < _taskNames.length; i++) { + print('${(i + 1).toString().padLeft(3)} - ${_taskNames[i]}'); } - exit(0); + exitCode = 0; + return; } - if (taskNames.isEmpty) { + if (_taskNames.isEmpty) { stderr.writeln('Failed to find tasks to run based on supplied options.'); - exit(1); + exitCode = 1; + return; } if (args.wasParsed('ab')) { - final int runsPerTest = int.parse(args['ab'] as String); - final String resultsFile = args['ab-result-file'] as String? ?? 'ABresults#.json'; - if (taskNames.length > 1) { - stderr.writeln('When running in A/B test mode exactly one task must be passed but got ${taskNames.join(', ')}.\n'); - stderr.writeln(argParser.usage); - exit(1); - } - if (localEngine == null) { - stderr.writeln('When running in A/B test mode --local-engine is required.\n'); - stderr.writeln(argParser.usage); - exit(1); - } - await _runABTest( - runsPerTest: runsPerTest, - silent: silent, - localEngine: localEngine, - localEngineSrcPath: localEngineSrcPath, - deviceId: deviceId, - resultsFile: resultsFile, - taskName: taskNames.single, - ); + await _runABTest(); } else { - await runTasks(taskNames, + await runTasks(_taskNames, silent: silent, localEngine: localEngine, localEngineSrcPath: localEngineSrcPath, deviceId: deviceId, exitOnFirstTestFailure: exitOnFirstTestFailure, - terminateStrayDartProcesses: terminateStrayDartProcesses, gitBranch: gitBranch, luciBuilder: luciBuilder, resultsPath: resultsPath, @@ -122,18 +116,26 @@ Future main(List rawArgs) async { } } -Future _runABTest({ - required int runsPerTest, - required bool silent, - required String localEngine, - required String? localEngineSrcPath, - required String? deviceId, - required String resultsFile, - required String taskName, -}) async { +Future _runABTest() async { + final int runsPerTest = int.parse(args['ab'] as String); + + if (_taskNames.length > 1) { + stderr.writeln('When running in A/B test mode exactly one task must be passed but got ${_taskNames.join(', ')}.\n'); + stderr.writeln(_argParser.usage); + exit(1); + } + + if (!args.wasParsed('local-engine')) { + stderr.writeln('When running in A/B test mode --local-engine is required.\n'); + stderr.writeln(_argParser.usage); + exit(1); + } + + final String taskName = _taskNames.single; + print('$taskName A/B test. Will run $runsPerTest times.'); - final ABTest abTest = ABTest(localEngine, taskName); + final ABTest abTest = ABTest(localEngine!, taskName); for (int i = 1; i <= runsPerTest; i++) { section('Run #$i'); @@ -180,7 +182,7 @@ Future _runABTest({ } abTest.finalize(); - final File jsonFile = _uniqueFile(resultsFile); + final File jsonFile = _uniqueFile(args['ab-result-file'] as String? ?? 'ABresults#.json'); jsonFile.writeAsStringSync(const JsonEncoder.withIndent(' ').convert(abTest.jsonMap)); if (silent != true) { @@ -232,152 +234,142 @@ void addTasks({ } } -ArgParser createArgParser(List taskNames) { - return ArgParser() - ..addMultiOption( - 'task', - abbr: 't', - help: 'Either:\n' - ' - the name of a task defined in manifest.yaml.\n' - ' Example: complex_layout__start_up.\n' - ' - the path to a Dart file corresponding to a task,\n' - ' which resides in bin/tasks.\n' - ' Example: bin/tasks/complex_layout__start_up.dart.\n' - '\n' - 'This option may be repeated to specify multiple tasks.', - callback: (List value) { - for (final String nameOrPath in value) { - final List fragments = path.split(nameOrPath); - final bool isDartFile = fragments.last.endsWith('.dart'); - - if (fragments.length == 1 && !isDartFile) { - // Not a path - taskNames.add(nameOrPath); - } else if (!isDartFile || !path.equals(path.dirname(nameOrPath), path.join('bin', 'tasks'))) { - // Unsupported executable location - throw FormatException('Invalid value for option -t (--task): $nameOrPath'); - } else { - taskNames.add(path.withoutExtension(fragments.last)); - } - } - }, - ) - ..addOption( - 'device-id', - abbr: 'd', - help: 'Target device id (prefixes are allowed, names are not supported).\n' - 'The option will be ignored if the test target does not run on a\n' - 'mobile device. This still respects the device operating system\n' - 'settings in the test case, and will results in error if no device\n' - 'with given ID/ID prefix is found.', - ) - ..addOption( - 'ab', - help: 'Runs an A/B test comparing the default engine with the local\n' - 'engine build for one task. This option does not support running\n' - 'multiple tasks. The value is the number of times to run the task.\n' - 'The task is expected to be a benchmark that reports score keys.\n' - 'The A/B test collects the metrics collected by the test and\n' - 'produces a report containing averages, noise, and the speed-up\n' - 'between the two engines. --local-engine is required when running\n' - 'an A/B test.', - callback: (String? value) { - if (value != null && int.tryParse(value) == null) { - throw ArgParserException('Option --ab must be a number, but was "$value".'); - } - }, - ) - ..addOption( - 'ab-result-file', - help: 'The filename in which to place the json encoded results of an A/B test.\n' - 'The filename may contain a single # character to be replaced by a sequence\n' - 'number if the name already exists.', - ) - ..addFlag( - 'all', - abbr: 'a', - help: 'Runs all tasks defined in manifest.yaml in alphabetical order.', - ) - ..addOption( - 'continue-from', - abbr: 'c', - help: 'With --all or --stage, continue from the given test.', - ) - ..addFlag( - 'exit', - defaultsTo: true, - help: 'Exit on the first test failure. Currently flakes are intentionally (though ' - 'incorrectly) not considered to be failures.', - ) - ..addOption( - 'git-branch', - help: '[Flutter infrastructure] Git branch of the current commit. LUCI\n' - 'checkouts run in detached HEAD state, so the branch must be passed.', - ) - ..addOption( - 'local-engine', - help: 'Name of a build output within the engine out directory, if you\n' - 'are building Flutter locally. Use this to select a specific\n' - 'version of the engine if you have built multiple engine targets.\n' - 'This path is relative to --local-engine-src-path/out. This option\n' - 'is required when running an A/B test (see the --ab option).', - ) - ..addFlag( - 'list', - abbr: 'l', - help: "Don't actually run the tasks, but list out the tasks that would\n" - 'have been run, in the order they would have run.', - ) - ..addOption( - 'local-engine-src-path', - help: 'Path to your engine src directory, if you are building Flutter\n' - 'locally. Defaults to \$FLUTTER_ENGINE if set, or tries to guess at\n' - 'the location based on the value of the --flutter-root option.', - ) - ..addOption('luci-builder', help: '[Flutter infrastructure] Name of the LUCI builder being run on.') - ..addFlag( - 'match-host-platform', - defaultsTo: true, - help: 'Only run tests that match the host platform (e.g. do not run a\n' - 'test with a `required_agent_capabilities` value of "mac/android"\n' - 'on a windows host). Each test publishes its ' - '`required_agent_capabilities`\nin the `manifest.yaml` file.', - ) - ..addOption( - 'results-file', - help: '[Flutter infrastructure] File path for test results. If passed with\n' - 'task, will write test results to the file.' - ) - ..addOption( - 'service-account-token-file', - help: '[Flutter infrastructure] Authentication for uploading results.', - ) - ..addOption( - 'stage', - abbr: 's', - help: 'Name of the stage. Runs all tasks for that stage. The tasks and\n' - 'their stages are read from manifest.yaml.', - ) - ..addFlag( - 'silent', - help: 'Reduce verbosity slightly.', - ) - ..addFlag( - 'terminate-stray-dart-processes', - defaultsTo: true, - help: 'Whether to send a SIGKILL signal to any Dart processes that are still ' - 'running when a task is completed. If any Dart processes are terminated ' - 'in this way, the test is considered to have failed.', - ) - ..addMultiOption( - 'test', - hide: true, - callback: (List value) { - if (value.isNotEmpty) { - throw const FormatException( - 'Invalid option --test. Did you mean --task (-t)?', - ); +/// Command-line options for the `run.dart` command. +final ArgParser _argParser = ArgParser() + ..addMultiOption( + 'task', + abbr: 't', + help: 'Either:\n' + ' - the name of a task defined in manifest.yaml.\n' + ' Example: complex_layout__start_up.\n' + ' - the path to a Dart file corresponding to a task,\n' + ' which resides in bin/tasks.\n' + ' Example: bin/tasks/complex_layout__start_up.dart.\n' + '\n' + 'This option may be repeated to specify multiple tasks.', + callback: (List value) { + for (final String nameOrPath in value) { + final List fragments = path.split(nameOrPath); + final bool isDartFile = fragments.last.endsWith('.dart'); + + if (fragments.length == 1 && !isDartFile) { + // Not a path + _taskNames.add(nameOrPath); + } else if (!isDartFile || !path.equals(path.dirname(nameOrPath), path.join('bin', 'tasks'))) { + // Unsupported executable location + throw FormatException('Invalid value for option -t (--task): $nameOrPath'); + } else { + _taskNames.add(path.withoutExtension(fragments.last)); } - }, - ); -} + } + }, + ) + ..addOption( + 'device-id', + abbr: 'd', + help: 'Target device id (prefixes are allowed, names are not supported).\n' + 'The option will be ignored if the test target does not run on a\n' + 'mobile device. This still respects the device operating system\n' + 'settings in the test case, and will results in error if no device\n' + 'with given ID/ID prefix is found.', + ) + ..addOption( + 'ab', + help: 'Runs an A/B test comparing the default engine with the local\n' + 'engine build for one task. This option does not support running\n' + 'multiple tasks. The value is the number of times to run the task.\n' + 'The task is expected to be a benchmark that reports score keys.\n' + 'The A/B test collects the metrics collected by the test and\n' + 'produces a report containing averages, noise, and the speed-up\n' + 'between the two engines. --local-engine is required when running\n' + 'an A/B test.', + callback: (String? value) { + if (value != null && int.tryParse(value) == null) { + throw ArgParserException('Option --ab must be a number, but was "$value".'); + } + }, + ) + ..addOption( + 'ab-result-file', + help: 'The filename in which to place the json encoded results of an A/B test.\n' + 'The filename may contain a single # character to be replaced by a sequence\n' + 'number if the name already exists.', + ) + ..addFlag( + 'all', + abbr: 'a', + help: 'Runs all tasks defined in manifest.yaml in alphabetical order.', + ) + ..addOption( + 'continue-from', + abbr: 'c', + help: 'With --all or --stage, continue from the given test.', + ) + ..addFlag( + 'exit', + defaultsTo: true, + help: 'Exit on the first test failure.', + ) + ..addOption( + 'git-branch', + help: '[Flutter infrastructure] Git branch of the current commit. LUCI\n' + 'checkouts run in detached HEAD state, so the branch must be passed.', + ) + ..addOption( + 'local-engine', + help: 'Name of a build output within the engine out directory, if you\n' + 'are building Flutter locally. Use this to select a specific\n' + 'version of the engine if you have built multiple engine targets.\n' + 'This path is relative to --local-engine-src-path/out. This option\n' + 'is required when running an A/B test (see the --ab option).', + ) + ..addFlag( + 'list', + abbr: 'l', + help: "Don't actually run the tasks, but list out the tasks that would\n" + 'have been run, in the order they would have run.', + ) + ..addOption( + 'local-engine-src-path', + help: 'Path to your engine src directory, if you are building Flutter\n' + 'locally. Defaults to \$FLUTTER_ENGINE if set, or tries to guess at\n' + 'the location based on the value of the --flutter-root option.', + ) + ..addOption('luci-builder', help: '[Flutter infrastructure] Name of the LUCI builder being run on.') + ..addFlag( + 'match-host-platform', + defaultsTo: true, + help: 'Only run tests that match the host platform (e.g. do not run a\n' + 'test with a `required_agent_capabilities` value of "mac/android"\n' + 'on a windows host). Each test publishes its ' + '`required_agent_capabilities`\nin the `manifest.yaml` file.', + ) + ..addOption( + 'results-file', + help: '[Flutter infrastructure] File path for test results. If passed with\n' + 'task, will write test results to the file.' + ) + ..addOption( + 'service-account-token-file', + help: '[Flutter infrastructure] Authentication for uploading results.', + ) + ..addOption( + 'stage', + abbr: 's', + help: 'Name of the stage. Runs all tasks for that stage. The tasks and\n' + 'their stages are read from manifest.yaml.', + ) + ..addFlag( + 'silent', + ) + ..addMultiOption( + 'test', + hide: true, + callback: (List value) { + if (value.isNotEmpty) { + throw const FormatException( + 'Invalid option --test. Did you mean --task (-t)?', + ); + } + }, + ); diff --git a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart index 3deac25666824..63b59ab28c44a 100644 --- a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart +++ b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart @@ -66,7 +66,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals String content = pubspec.readAsStringSync(); content = content.replaceFirst( '\ndependencies:\n', - '\ndependencies:\n package_info: 2.0.2\n connectivity: 3.0.6\n', + '\ndependencies:\n device_info: 0.4.1\n package_info: 0.4.0+9\n connectivity: 3.0.3\n', ); pubspec.writeAsStringSync(content, flush: true); await inDirectory(projectDir, () async { @@ -263,10 +263,10 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals final String pluginFrameworkPath = path.join( outputPath, mode, - 'connectivity.xcframework', + 'device_info.xcframework', 'ios-arm64_armv7', - 'connectivity.framework', - 'connectivity', + 'device_info.framework', + 'device_info', ); await _checkBitcode(pluginFrameworkPath, mode); if (!await _linksOnFlutter(pluginFrameworkPath)) { @@ -288,41 +288,41 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals checkFileExists(path.join( outputPath, mode, - 'connectivity.xcframework', + 'device_info.xcframework', 'ios-arm64_armv7', - 'connectivity.framework', + 'device_info.framework', 'Headers', - 'FLTConnectivityPlugin.h', + 'DeviceInfoPlugin.h', )); if (mode != 'Debug') { checkDirectoryExists(path.join( outputPath, mode, - 'connectivity.xcframework', + 'device_info.xcframework', 'ios-arm64_armv7', 'dSYMs', - 'connectivity.framework.dSYM', + 'device_info.framework.dSYM', )); } final String simulatorFrameworkPath = path.join( outputPath, mode, - 'connectivity.xcframework', + 'device_info.xcframework', 'ios-arm64_x86_64-simulator', - 'connectivity.framework', - 'connectivity', + 'device_info.framework', + 'device_info', ); final String simulatorFrameworkHeaderPath = path.join( outputPath, mode, - 'connectivity.xcframework', + 'device_info.xcframework', 'ios-arm64_x86_64-simulator', - 'connectivity.framework', + 'device_info.framework', 'Headers', - 'FLTConnectivityPlugin.h', + 'DeviceInfoPlugin.h', ); checkFileExists(simulatorFrameworkPath); @@ -332,7 +332,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals checkDirectoryExists(path.join( outputPath, 'Release', - 'connectivity.xcframework', + 'device_info.xcframework', 'ios-arm64_armv7', 'BCSymbolMaps', )); @@ -415,6 +415,12 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals 'Unexpected FlutterPluginRegistrant.xcframework.'); } + checkDirectoryExists(path.join( + cocoapodsOutputPath, + mode, + 'device_info.xcframework', + )); + checkDirectoryExists(path.join( cocoapodsOutputPath, mode, diff --git a/dev/devicelab/bin/tasks/flavors_test.dart b/dev/devicelab/bin/tasks/flavors_test.dart index 7e50969cd30b6..b8fbade6610b6 100644 --- a/dev/devicelab/bin/tasks/flavors_test.dart +++ b/dev/devicelab/bin/tasks/flavors_test.dart @@ -4,15 +4,9 @@ import 'package:flutter_devicelab/framework/devices.dart'; import 'package:flutter_devicelab/framework/framework.dart'; -import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/tasks/integration_tests.dart'; Future main() async { deviceOperatingSystem = DeviceOperatingSystem.android; - await task(() async { - await createFlavorsTest().call(); - await createIntegrationTestFlavorsTest().call(); - - return TaskResult.success(null); - }); + await task(createFlavorsTest()); } diff --git a/dev/devicelab/bin/tasks/flavors_test_ios.dart b/dev/devicelab/bin/tasks/flavors_test_ios.dart index c508c7fa889ae..3fa97b2cf7b0b 100644 --- a/dev/devicelab/bin/tasks/flavors_test_ios.dart +++ b/dev/devicelab/bin/tasks/flavors_test_ios.dart @@ -4,15 +4,9 @@ import 'package:flutter_devicelab/framework/devices.dart'; import 'package:flutter_devicelab/framework/framework.dart'; -import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/tasks/integration_tests.dart'; Future main() async { deviceOperatingSystem = DeviceOperatingSystem.ios; - await task(() async { - await createFlavorsTest().call(); - await createIntegrationTestFlavorsTest().call(); - - return TaskResult.success(null); - }); + await task(createFlavorsTest()); } diff --git a/dev/devicelab/bin/tasks/flavors_test_win.dart b/dev/devicelab/bin/tasks/flavors_test_win.dart index 7e50969cd30b6..b8fbade6610b6 100644 --- a/dev/devicelab/bin/tasks/flavors_test_win.dart +++ b/dev/devicelab/bin/tasks/flavors_test_win.dart @@ -4,15 +4,9 @@ import 'package:flutter_devicelab/framework/devices.dart'; import 'package:flutter_devicelab/framework/framework.dart'; -import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/tasks/integration_tests.dart'; Future main() async { deviceOperatingSystem = DeviceOperatingSystem.android; - await task(() async { - await createFlavorsTest().call(); - await createIntegrationTestFlavorsTest().call(); - - return TaskResult.success(null); - }); + await task(createFlavorsTest()); } diff --git a/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart b/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart index b2be48db88515..a410eb2c47150 100644 --- a/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart +++ b/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:convert'; import 'dart:io'; +import 'package:flutter_devicelab/common.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/ios.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; @@ -14,6 +16,8 @@ Future main() async { await task(() async { section('Copy test Flutter App with watchOS Companion'); + String? watchDeviceID; + String? phoneDeviceID; final Directory tempDir = Directory.systemTemp .createTempSync('flutter_ios_app_with_extensions_test.'); final Directory projectDir = @@ -28,23 +32,11 @@ Future main() async { section('Create release build'); - // This only builds the iOS app, not the companion watchOS app. The watchOS app - // has been removed as a build dependency and is not embedded in the app to avoid - // requiring the watchOS being available in CI. - // Instead, validate the tool detects that there is a watch companion, and omits - // the "-sdk iphoneos" option, which fails to build the watchOS app. - // See https://github.com/flutter/flutter/pull/94190. await inDirectory(projectDir, () async { - final String buildOutput = await evalFlutter( + await flutter( 'build', options: ['ios', '--no-codesign', '--release', '--verbose'], ); - if (!buildOutput.contains('Watch companion app found')) { - throw TaskResult.failure('Did not detect watch companion'); - } - if (buildOutput.contains('-sdk iphoneos -destination')) { - throw TaskResult.failure('-sdk must be omitted for app with watch companion'); - } }); final String appBundle = Directory(path.join( @@ -72,17 +64,228 @@ Future main() async { await _checkFlutterFrameworkArchs(appFrameworkPath); await _checkFlutterFrameworkArchs(flutterFrameworkPath); + // Check the watch extension framework added in the Podfile + // is in place with the expected watch archs. + final String watchExtensionFrameworkPath = path.join( + appBundle, + 'Watch', + 'watch.app', + 'PlugIns', + 'watch Extension.appex', + 'Frameworks', + 'EFQRCode.framework', + 'EFQRCode', + ); + unawaited(_checkWatchExtensionFrameworkArchs(watchExtensionFrameworkPath)); + + section('Clean build'); + + await inDirectory(projectDir, () async { + await flutter('clean'); + }); + + section('Create debug build'); + + await inDirectory(projectDir, () async { + await flutter( + 'build', + options: ['ios', '--debug', '--no-codesign', '--verbose'], + ); + }); + + checkDirectoryExists(appBundle); + await _checkFlutterFrameworkArchs(appFrameworkPath); + await _checkFlutterFrameworkArchs(flutterFrameworkPath); + unawaited(_checkWatchExtensionFrameworkArchs(watchExtensionFrameworkPath)); + section('Clean build'); await inDirectory(projectDir, () async { await flutter('clean'); }); + section('Run app on simulator device'); + + // Xcode 11.4 simctl create makes the runtime argument optional, and defaults to latest. + // TODO(jmagman): Remove runtime parsing when devicelab upgrades to Xcode 11.4 https://github.com/flutter/flutter/issues/54889 + final String availableRuntimes = await eval( + 'xcrun', + [ + 'simctl', + 'list', + 'runtimes', + ], + workingDirectory: flutterDirectory.path, + ); + + // Example simctl list: + // == Runtimes == + // iOS 10.3 (10.3.1 - 14E8301) - com.apple.CoreSimulator.SimRuntime.iOS-10-3 + // iOS 13.4 (13.4 - 17E255) - com.apple.CoreSimulator.SimRuntime.iOS-13-4 + // tvOS 13.4 (13.4 - 17L255) - com.apple.CoreSimulator.SimRuntime.tvOS-13-4 + // watchOS 6.2 (6.2 - 17T256) - com.apple.CoreSimulator.SimRuntime.watchOS-6-2 + String? iOSSimRuntime; + String? watchSimRuntime; + + final RegExp iOSRuntimePattern = RegExp(r'iOS .*\) - (.*)'); + final RegExp watchOSRuntimePattern = RegExp(r'watchOS .*\) - (.*)'); + + for (final String runtime in LineSplitter.split(availableRuntimes)) { + // These seem to be in order, so allow matching multiple lines so it grabs + // the last (hopefully latest) one. + final RegExpMatch? iOSRuntimeMatch = iOSRuntimePattern.firstMatch(runtime); + if (iOSRuntimeMatch != null) { + iOSSimRuntime = iOSRuntimeMatch.group(1)!.trim(); + continue; + } + final RegExpMatch? watchOSRuntimeMatch = watchOSRuntimePattern.firstMatch(runtime); + if (watchOSRuntimeMatch != null) { + watchSimRuntime = watchOSRuntimeMatch.group(1)!.trim(); + } + } + if (iOSSimRuntime == null || watchSimRuntime == null) { + String message; + if (iOSSimRuntime != null) { + message = 'Found "$iOSSimRuntime", but no watchOS simulator runtime found.'; + } else if (watchSimRuntime != null) { + message = 'Found "$watchSimRuntime", but no iOS simulator runtime found.'; + } else { + message = 'watchOS and iOS simulator runtimes not found.'; + } + return TaskResult.failure('$message Available runtimes:\n$availableRuntimes'); + } + + // Create iOS simulator. + phoneDeviceID = await eval( + 'xcrun', + [ + 'simctl', + 'create', + 'TestFlutteriPhoneWithWatch', + 'com.apple.CoreSimulator.SimDeviceType.iPhone-11', + iOSSimRuntime, + ], + workingDirectory: flutterDirectory.path, + ); + + // Create watchOS simulator. + watchDeviceID = await eval( + 'xcrun', + [ + 'simctl', + 'create', + 'TestFlutterWatch', + 'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-44mm', + watchSimRuntime, + ], + workingDirectory: flutterDirectory.path, + ); + + // Pair watch with phone. + await eval( + 'xcrun', + ['simctl', 'pair', watchDeviceID, phoneDeviceID], + workingDirectory: flutterDirectory.path, + ); + + // Boot simulator devices. + await eval( + 'xcrun', + ['simctl', 'bootstatus', phoneDeviceID, '-b'], + workingDirectory: flutterDirectory.path, + ); + await eval( + 'xcrun', + ['simctl', 'bootstatus', watchDeviceID, '-b'], + workingDirectory: flutterDirectory.path, + ); + + // Start app on simulated device. + final Process process = await startProcess( + path.join(flutterDirectory.path, 'bin', 'flutter'), + ['run', '-d', phoneDeviceID], + workingDirectory: projectDir.path); + + process.stdout + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen((String line) { + print('stdout: $line'); + // Wait for app startup to complete and quit immediately afterwards. + if (line.startsWith('An Observatory debugger')) { + process.stdin.write('q'); + } + }); + process.stderr + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen((String line) { + print('stderr: $line'); + }); + + final int exitCode = await process.exitCode; + + if (exitCode != 0) { + return TaskResult.failure( + 'Failed to start flutter iOS app with WatchOS companion on simulated device.'); + } + + final String simulatorAppBundle = Directory(path.join( + projectDir.path, + 'build', + 'ios', + 'iphonesimulator', + 'Runner.app', + )).path; + + checkDirectoryExists(simulatorAppBundle); + checkFileExists(path.join( + simulatorAppBundle, + 'Frameworks', + 'App.framework', + 'App', + )); + checkFileExists(path.join( + simulatorAppBundle, + 'Frameworks', + 'Flutter.framework', + 'Flutter', + )); + return TaskResult.success(null); } catch (e) { return TaskResult.failure(e.toString()); } finally { rmTree(tempDir); + // Delete simulator devices + if (watchDeviceID != null && watchDeviceID != '') { + await eval( + 'xcrun', + ['simctl', 'shutdown', watchDeviceID], + canFail: true, + workingDirectory: flutterDirectory.path, + ); + await eval( + 'xcrun', + ['simctl', 'delete', watchDeviceID], + canFail: true, + workingDirectory: flutterDirectory.path, + ); + } + if (phoneDeviceID != null && phoneDeviceID != '') { + await eval( + 'xcrun', + ['simctl', 'shutdown', phoneDeviceID], + canFail: true, + workingDirectory: flutterDirectory.path, + ); + await eval( + 'xcrun', + ['simctl', 'delete', phoneDeviceID], + canFail: true, + workingDirectory: flutterDirectory.path, + ); + } } }); } @@ -99,3 +302,15 @@ Future _checkFlutterFrameworkArchs(String frameworkPath) async { throw TaskResult.failure('$frameworkPath x86_64 architecture unexpectedly present'); } } + +Future _checkWatchExtensionFrameworkArchs(String frameworkPath) async { + checkFileExists(frameworkPath); + final String archs = await fileType(frameworkPath); + if (!archs.contains('armv7k')) { + throw TaskResult.failure('$frameworkPath armv7k architecture missing'); + } + + if (!archs.contains('arm64_32')) { + throw TaskResult.failure('$frameworkPath arm64_32 architecture missing'); + } +} diff --git a/dev/devicelab/bin/tasks/module_custom_host_app_name_test.dart b/dev/devicelab/bin/tasks/module_custom_host_app_name_test.dart index 7f19d887e079a..006744beb8104 100644 --- a/dev/devicelab/bin/tasks/module_custom_host_app_name_test.dart +++ b/dev/devicelab/bin/tasks/module_custom_host_app_name_test.dart @@ -72,7 +72,7 @@ Future main() async { content = await pubspec.readAsString(); content = content.replaceFirst( '${platformLineSep}dependencies:$platformLineSep', - '${platformLineSep}dependencies:$platformLineSep device_info: 2.0.3$platformLineSep package_info: 2.0.2$platformLineSep', + '${platformLineSep}dependencies:$platformLineSep device_info: 0.4.1$platformLineSep package_info: 0.4.0+9$platformLineSep', ); await pubspec.writeAsString(content, flush: true); await inDirectory(projectDir, () async { diff --git a/dev/devicelab/bin/tasks/module_test.dart b/dev/devicelab/bin/tasks/module_test.dart index 413f2abe81f71..a9fbb58f17fc8 100644 --- a/dev/devicelab/bin/tasks/module_test.dart +++ b/dev/devicelab/bin/tasks/module_test.dart @@ -75,7 +75,7 @@ Future main() async { content = await pubspec.readAsString(); content = content.replaceFirst( '${platformLineSep}dependencies:$platformLineSep', - '${platformLineSep}dependencies:$platformLineSep device_info: 2.0.3$platformLineSep package_info: 2.0.2$platformLineSep', + '${platformLineSep}dependencies:$platformLineSep device_info: 0.4.1$platformLineSep package_info: 0.4.0+9$platformLineSep', ); await pubspec.writeAsString(content, flush: true); await inDirectory(projectDir, () async { diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index 81f69bf7bc5fd..afd5201e12cc7 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -18,9 +18,7 @@ import 'package:path/path.dart' as path; /// adding Flutter to an existing iOS app. Future main() async { await task(() async { - // this variable cannot be `late`, as we reference it in the `finally` block - // which may execute before this field has been initialized - String? simulatorDeviceId; + late String simulatorDeviceId; section('Create Flutter module project'); final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.'); @@ -152,28 +150,14 @@ Future main() async { await flutter('clean'); }); - // Make a fake Dart-only plugin, since there are no existing examples. - section('Create local plugin'); - - const String dartPluginName = 'dartplugin'; - await _createFakeDartPlugin(dartPluginName, tempDir); - section('Add plugins'); final File pubspec = File(path.join(projectDir.path, 'pubspec.yaml')); String content = await pubspec.readAsString(); content = content.replaceFirst( '\ndependencies:\n', - // One dynamic framework, one static framework, one Dart-only, - // and one that does not support iOS. - ''' -dependencies: - device_info: 2.0.3 - google_sign_in: 4.5.1 - android_alarm_manager: 0.4.5+11 - $dartPluginName: - path: ../$dartPluginName -''', + // One dynamic framework, one static framework, and one that does not support iOS. + '\ndependencies:\n device_info: 0.4.2+4\n google_sign_in: 4.5.1\n android_alarm_manager: 0.4.5+11\n', ); await pubspec.writeAsString(content, flush: true); await inDirectory(projectDir, () async { @@ -205,8 +189,7 @@ dependencies: || !podfileLockOutput.contains(':path: Flutter/FlutterPluginRegistrant') || !podfileLockOutput.contains(':path: ".symlinks/plugins/device_info/ios"') || !podfileLockOutput.contains(':path: ".symlinks/plugins/google_sign_in/ios"') - || podfileLockOutput.contains('android_alarm_manager') - || podfileLockOutput.contains(dartPluginName)) { + || podfileLockOutput.contains('android_alarm_manager')) { print(podfileLockOutput); return TaskResult.failure('Building ephemeral host app Podfile.lock does not contain expected pods'); } @@ -220,9 +203,6 @@ dependencies: // Android-only, no embedded framework. checkDirectoryNotExists(path.join(ephemeralIOSHostApp.path, 'Frameworks', 'android_alarm_manager.framework')); - // Dart-only, no embedded framework. - checkDirectoryNotExists(path.join(ephemeralIOSHostApp.path, 'Frameworks', '$dartPluginName.framework')); - section('Clean and pub get module'); await inDirectory(projectDir, () async { @@ -261,8 +241,7 @@ dependencies: || !hostPodfileLockOutput.contains(':path: "../hello/.ios/Flutter/FlutterPluginRegistrant"') || !hostPodfileLockOutput.contains(':path: "../hello/.ios/.symlinks/plugins/device_info/ios"') || !hostPodfileLockOutput.contains(':path: "../hello/.ios/.symlinks/plugins/google_sign_in/ios"') - || hostPodfileLockOutput.contains('android_alarm_manager') - || hostPodfileLockOutput.contains(dartPluginName)) { + || hostPodfileLockOutput.contains('android_alarm_manager')) { print(hostPodfileLockOutput); throw TaskResult.failure('Building host app Podfile.lock does not contain expected pods'); } @@ -520,46 +499,3 @@ Future _isAppAotBuild(Directory app) async { return symbolTable.contains('kDartIsolateSnapshotInstructions'); } - -Future _createFakeDartPlugin(String name, Directory parent) async { - // Start from a standard plugin template. - await inDirectory(parent, () async { - await flutter( - 'create', - options: [ - '--org', - 'io.flutter.devicelab', - '--template=plugin', - '--platforms=ios', - name, - ], - ); - }); - - final String pluginDir = path.join(parent.path, name); - - // Convert the metadata to Dart-only. - final String dartPluginClass = 'DartClassFor$name'; - final File pubspec = File(path.join(pluginDir, 'pubspec.yaml')); - String content = await pubspec.readAsString(); - content = content.replaceAll( - RegExp(r' pluginClass: .*?\n'), - ' dartPluginClass: $dartPluginClass\n', - ); - await pubspec.writeAsString(content, flush: true); - - // Add the Dart registration hook that the build will generate a call to. - final File dartCode = File(path.join(pluginDir, 'lib', '$name.dart')); - content = await dartCode.readAsString(); - content = ''' -$content - -class $dartPluginClass { - static void registerWith() {} -} -'''; - await dartCode.writeAsString(content, flush: true); - - // Remove the native plugin code. - await Directory(path.join(pluginDir, 'ios')).delete(recursive: true); -} diff --git a/dev/devicelab/bin/tasks/native_ui_tests_ios.dart b/dev/devicelab/bin/tasks/native_ui_tests_ios.dart index 68bc76f3eff24..a671ad616f54d 100644 --- a/dev/devicelab/bin/tasks/native_ui_tests_ios.dart +++ b/dev/devicelab/bin/tasks/native_ui_tests_ios.dart @@ -36,11 +36,7 @@ Future main() async { section('Run platform unit tests'); final Device device = await devices.workingDevice; - if (!await runXcodeTests( - platformDirectory: path.join(projectDirectory, 'ios'), - destination: 'id=${device.deviceId}', - testName: 'native_ui_tests_ios', - )) { + if (!await runXcodeTests(path.join(projectDirectory, 'ios'), 'id=${device.deviceId}', 'native_ui_tests_ios')) { return TaskResult.failure('Platform unit tests failed'); } diff --git a/dev/devicelab/bin/tasks/native_ui_tests_macos.dart b/dev/devicelab/bin/tasks/native_ui_tests_macos.dart index 1b358432f793e..f0051d1f47b19 100644 --- a/dev/devicelab/bin/tasks/native_ui_tests_macos.dart +++ b/dev/devicelab/bin/tasks/native_ui_tests_macos.dart @@ -27,12 +27,7 @@ Future main() async { section('Run platform unit tests'); - if (!await runXcodeTests( - platformDirectory: path.join(projectDirectory, 'macos'), - destination: 'platform=macOS', - testName: 'native_ui_tests_macos', - skipCodesign: true, - )) { + if (!await runXcodeTests(path.join(projectDirectory, 'macos'), 'platform=macOS', 'native_ui_tests_macos')) { return TaskResult.failure('Platform unit tests failed'); } diff --git a/dev/devicelab/bin/tasks/opacity_peephole_col_of_rows_perf__e2e_summary.dart b/dev/devicelab/bin/tasks/opacity_peephole_col_of_rows_perf__e2e_summary.dart deleted file mode 100644 index a600541c01cfd..0000000000000 --- a/dev/devicelab/bin/tasks/opacity_peephole_col_of_rows_perf__e2e_summary.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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:async'; - -import 'package:flutter_devicelab/framework/devices.dart'; -import 'package:flutter_devicelab/framework/framework.dart'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; - -Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createOpacityPeepholeColOfRowsPerfE2ETest()); -} diff --git a/dev/devicelab/bin/tasks/opacity_peephole_fade_transition_text_perf__e2e_summary.dart b/dev/devicelab/bin/tasks/opacity_peephole_fade_transition_text_perf__e2e_summary.dart deleted file mode 100644 index d6287f0a49bae..0000000000000 --- a/dev/devicelab/bin/tasks/opacity_peephole_fade_transition_text_perf__e2e_summary.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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:async'; - -import 'package:flutter_devicelab/framework/devices.dart'; -import 'package:flutter_devicelab/framework/framework.dart'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; - -Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createOpacityPeepholeFadeTransitionTextPerfE2ETest()); -} diff --git a/dev/devicelab/bin/tasks/opacity_peephole_grid_of_opacity_perf__e2e_summary.dart b/dev/devicelab/bin/tasks/opacity_peephole_grid_of_opacity_perf__e2e_summary.dart deleted file mode 100644 index eff6485a78c70..0000000000000 --- a/dev/devicelab/bin/tasks/opacity_peephole_grid_of_opacity_perf__e2e_summary.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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:async'; - -import 'package:flutter_devicelab/framework/devices.dart'; -import 'package:flutter_devicelab/framework/framework.dart'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; - -Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createOpacityPeepholeGridOfOpacityPerfE2ETest()); -} diff --git a/dev/devicelab/bin/tasks/opacity_peephole_one_rect_perf__e2e_summary.dart b/dev/devicelab/bin/tasks/opacity_peephole_one_rect_perf__e2e_summary.dart deleted file mode 100644 index ffe72266a0acc..0000000000000 --- a/dev/devicelab/bin/tasks/opacity_peephole_one_rect_perf__e2e_summary.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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:async'; - -import 'package:flutter_devicelab/framework/devices.dart'; -import 'package:flutter_devicelab/framework/framework.dart'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; - -Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createOpacityPeepholeOneRectPerfE2ETest()); -} diff --git a/dev/devicelab/bin/tasks/opacity_peephole_opacity_of_grid_perf__e2e_summary.dart b/dev/devicelab/bin/tasks/opacity_peephole_opacity_of_grid_perf__e2e_summary.dart deleted file mode 100644 index 9efed8ac334b9..0000000000000 --- a/dev/devicelab/bin/tasks/opacity_peephole_opacity_of_grid_perf__e2e_summary.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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:async'; - -import 'package:flutter_devicelab/framework/devices.dart'; -import 'package:flutter_devicelab/framework/framework.dart'; -import 'package:flutter_devicelab/tasks/perf_tests.dart'; - -Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createOpacityPeepholeOpacityOfGridPerfE2ETest()); -} diff --git a/dev/devicelab/bin/tasks/plugin_test.dart b/dev/devicelab/bin/tasks/plugin_test.dart index 9b556cded7000..d7b5e536f5c91 100644 --- a/dev/devicelab/bin/tasks/plugin_test.dart +++ b/dev/devicelab/bin/tasks/plugin_test.dart @@ -16,7 +16,5 @@ Future main() async { {'ENABLE_ANDROID_EMBEDDING_V2': 'true'}), PluginTest('apk', ['-a', 'kotlin', '--platforms=android'], pluginCreateEnvironment: {'ENABLE_ANDROID_EMBEDDING_V2': 'true'}), - // Test that Dart-only plugins are supported. - PluginTest('apk', ['--platforms=android'], dartOnlyPlugin: true), ])); } diff --git a/dev/devicelab/bin/tasks/plugin_test_ios.dart b/dev/devicelab/bin/tasks/plugin_test_ios.dart index 408cf1b87be82..bff25a21202a4 100644 --- a/dev/devicelab/bin/tasks/plugin_test_ios.dart +++ b/dev/devicelab/bin/tasks/plugin_test_ios.dart @@ -10,8 +10,5 @@ Future main() async { PluginTest('ios', ['-i', 'objc', '--platforms=ios']), PluginTest('ios', ['-i', 'swift', '--platforms=ios']), PluginTest('macos', ['--platforms=macos']), - // Test that Dart-only plugins are supported. - PluginTest('ios', ['--platforms=ios'], dartOnlyPlugin: true), - PluginTest('macos', ['--platforms=macos'], dartOnlyPlugin: true), ])); } diff --git a/dev/devicelab/bin/tasks/run_release_test.dart b/dev/devicelab/bin/tasks/run_release_test.dart index 2b2130bc23954..cd1050ae196ef 100644 --- a/dev/devicelab/bin/tasks/run_release_test.dart +++ b/dev/devicelab/bin/tasks/run_release_test.dart @@ -76,8 +76,6 @@ void main() { run.stderr .transform(utf8.decoder) .transform(const LineSplitter()) - // TODO(egarciad): Remove once https://github.com/flutter/flutter/issues/95131 is fixed. - .skipWhile((String line) => line.contains('Mapping new ns')) .listen((String line) { print('run:stderr: $line'); stderr.add(line); diff --git a/dev/devicelab/bin/tasks/hot_mode_dev_cycle_ios__benchmark.dart b/dev/devicelab/bin/tasks/smoke_catalina_hot_mode_dev_cycle_ios__benchmark.dart similarity index 100% rename from dev/devicelab/bin/tasks/hot_mode_dev_cycle_ios__benchmark.dart rename to dev/devicelab/bin/tasks/smoke_catalina_hot_mode_dev_cycle_ios__benchmark.dart diff --git a/dev/devicelab/bin/tasks/flutter_gallery_mac__start_up.dart b/dev/devicelab/bin/tasks/smoke_catalina_start_up.dart similarity index 100% rename from dev/devicelab/bin/tasks/flutter_gallery_mac__start_up.dart rename to dev/devicelab/bin/tasks/smoke_catalina_start_up.dart diff --git a/dev/devicelab/lib/command/test.dart b/dev/devicelab/lib/command/test.dart index 437b80d94c486..62c947bab7df8 100644 --- a/dev/devicelab/lib/command/test.dart +++ b/dev/devicelab/lib/command/test.dart @@ -49,7 +49,6 @@ class TestCommand extends Command { 'task, will write test results to the file.'); argParser.addFlag( 'silent', - help: 'Suppresses standard output and only print standard error output.', ); } diff --git a/dev/devicelab/lib/framework/devices.dart b/dev/devicelab/lib/framework/devices.dart index 4fa0cbe44787b..3428fb475e1cf 100644 --- a/dev/devicelab/lib/framework/devices.dart +++ b/dev/devicelab/lib/framework/devices.dart @@ -124,9 +124,6 @@ abstract class Device { /// Send the device to sleep mode. Future sendToSleep(); - /// Emulates pressing the home button. - Future home(); - /// Emulates pressing the power button, toggling the device's on/off state. Future togglePower(); @@ -473,12 +470,6 @@ class AndroidDevice extends Device { await togglePower(); } - /// Sends `KEYCODE_HOME` (3), which causes the device to go to the home screen. - @override - Future home() async { - await shellExec('input', const ['keyevent', '3']); - } - /// Sends `KEYCODE_POWER` (26), which causes the device to toggle its mode /// between awake and asleep. @override @@ -904,9 +895,6 @@ class IosDevice extends Device { @override Future sendToSleep() async {} - @override - Future home() async {} - @override Future togglePower() async {} @@ -957,9 +945,6 @@ class FuchsiaDevice extends Device { @override Future sendToSleep() async {} - @override - Future home() async {} - @override Future togglePower() async {} @@ -1026,9 +1011,6 @@ class FakeDevice extends Device { @override Future sendToSleep() async {} - @override - Future home() async {} - @override Future togglePower() async {} diff --git a/dev/devicelab/lib/framework/framework.dart b/dev/devicelab/lib/framework/framework.dart index a81f035c2b8cb..a304102b7afff 100644 --- a/dev/devicelab/lib/framework/framework.dart +++ b/dev/devicelab/lib/framework/framework.dart @@ -10,7 +10,6 @@ import 'dart:isolate'; import 'package:logging/logging.dart'; import 'package:path/path.dart' as path; -import 'package:process/process.dart'; import 'package:stack_trace/stack_trace.dart'; import 'devices.dart'; @@ -42,15 +41,11 @@ bool _isTaskRegistered = false; /// /// It is OK for a [task] to perform many things. However, only one task can be /// registered per Dart VM. -/// -/// If no `processManager` is provided, a default [LocalProcessManager] is created -/// for the task. -Future task(TaskFunction task, { ProcessManager? processManager }) async { +Future task(TaskFunction task) async { if (_isTaskRegistered) throw StateError('A task is already registered'); - _isTaskRegistered = true; - processManager ??= const LocalProcessManager(); + _isTaskRegistered = true; // TODO(ianh): allow overriding logging. Logger.root.level = Level.ALL; @@ -58,27 +53,23 @@ Future task(TaskFunction task, { ProcessManager? processManager }) a print('${rec.level.name}: ${rec.time}: ${rec.message}'); }); - final _TaskRunner runner = _TaskRunner(task, processManager); + final _TaskRunner runner = _TaskRunner(task); runner.keepVmAliveUntilTaskRunRequested(); return runner.whenDone; } class _TaskRunner { - _TaskRunner(this.task, this.processManager) { + _TaskRunner(this.task) { registerExtension('ext.cocoonRunTask', (String method, Map parameters) async { final Duration? taskTimeout = parameters.containsKey('timeoutInMinutes') ? Duration(minutes: int.parse(parameters['timeoutInMinutes']!)) : null; - final bool runFlutterConfig = parameters['runFlutterConfig'] != 'false'; // used by tests to avoid changing the configuration + // This is only expected to be passed in unit test runs so they do not + // kill the Dart process that is running them and waste time running config. + final bool runFlutterConfig = parameters['runFlutterConfig'] != 'false'; final bool runProcessCleanup = parameters['runProcessCleanup'] != 'false'; - final String? localEngine = parameters['localEngine']; - final TaskResult result = await run( - taskTimeout, - runProcessCleanup: runProcessCleanup, - runFlutterConfig: runFlutterConfig, - localEngine: localEngine, - ); + final TaskResult result = await run(taskTimeout, runProcessCleanup: runProcessCleanup, runFlutterConfig: runFlutterConfig); return ServiceExtensionResponse.result(json.encode(result.toJson())); }); registerExtension('ext.cocoonRunnerReady', @@ -88,7 +79,6 @@ class _TaskRunner { } final TaskFunction task; - final ProcessManager processManager; Future _getWorkingDeviceIfAvailable() async { try { @@ -113,7 +103,6 @@ class _TaskRunner { Future run(Duration? taskTimeout, { bool runFlutterConfig = true, bool runProcessCleanup = true, - required String? localEngine, }) async { try { _taskStarted = true; @@ -124,19 +113,20 @@ class _TaskRunner { section('Checking running Dart$exe processes'); beforeRunningDartInstances = await getRunningProcesses( processName: 'dart$exe', - processManager: processManager, - ); - final Set allProcesses = await getRunningProcesses(processManager: processManager); + ).toSet(); + final Set allProcesses = await getRunningProcesses().toSet(); beforeRunningDartInstances.forEach(print); for (final RunningProcessInfo info in allProcesses) { if (info.commandLine.contains('iproxy')) { print('[LEAK]: ${info.commandLine} ${info.creationDate} ${info.pid} '); } } + } else { + section('Skipping check running Dart$exe processes'); } if (runFlutterConfig) { - print('Enabling configs for macOS, Linux, Windows, and Web...'); + print('enabling configs for macOS, Linux, Windows, and Web...'); final int configResult = await exec(path.join(flutterDirectory.path, 'bin', 'flutter'), [ 'config', '-v', @@ -144,18 +134,16 @@ class _TaskRunner { '--enable-windows-desktop', '--enable-linux-desktop', '--enable-web', - if (localEngine != null) ...['--local-engine', localEngine], + if (localEngine != null) ...['--local-engine', localEngine!], ], canFail: true); if (configResult != 0) { print('Failed to enable configuration, tasks may not run.'); } + } else { + print('Skipping enabling configs for macOS, Linux, Windows, and Web'); } final Device? device = await _getWorkingDeviceIfAvailable(); - - // Some tests assume the phone is in home - await device?.home(); - late TaskResult result; IOSink? sink; try { @@ -177,24 +165,26 @@ class _TaskRunner { } if (runProcessCleanup) { - section('Terminating lingering Dart$exe processes after task...'); - final Set afterRunningDartInstances = await getRunningProcesses( + section('Checking running Dart$exe processes after task...'); + final List afterRunningDartInstances = await getRunningProcesses( processName: 'dart$exe', - processManager: processManager, - ); + ).toList(); for (final RunningProcessInfo info in afterRunningDartInstances) { if (!beforeRunningDartInstances.contains(info)) { print('$info was leaked by this test.'); if (result is TaskResultCheckProcesses) { result = TaskResult.failure('This test leaked dart processes'); } - if (await info.terminate(processManager: processManager)) { - print('Killed process id ${info.pid}.'); - } else { + final bool killed = await killProcess(info.pid); + if (!killed) { print('Failed to kill process ${info.pid}.'); + } else { + print('Killed process id ${info.pid}.'); } } } + } else { + print('Skipping check running Dart$exe processes after task'); } _completer.complete(result); return result; diff --git a/dev/devicelab/lib/framework/ios.dart b/dev/devicelab/lib/framework/ios.dart index e0691fcfa3f24..a746310cbee51 100644 --- a/dev/devicelab/lib/framework/ios.dart +++ b/dev/devicelab/lib/framework/ios.dart @@ -116,14 +116,14 @@ Future testWithNewIOSSimulator( } /// Shuts down and deletes simulator with deviceId. -Future removeIOSimulator(String? deviceId) async { +Future removeIOSimulator(String deviceId) async { if (deviceId != null && deviceId != '') { await eval( 'xcrun', [ 'simctl', 'shutdown', - deviceId, + deviceId ], canFail: true, workingDirectory: flutterDirectory.path, @@ -133,30 +133,20 @@ Future removeIOSimulator(String? deviceId) async { [ 'simctl', 'delete', - deviceId, - ], + deviceId], canFail: true, workingDirectory: flutterDirectory.path, ); } } -Future runXcodeTests({ - required String platformDirectory, - required String destination, - required String testName, - bool skipCodesign = false, -}) async { +Future runXcodeTests(String platformDirectory, String destination, String testName) async { final Map environment = Platform.environment; - String? developmentTeam; - String? codeSignStyle; - String? provisioningProfile; - if (!skipCodesign) { - // If not running on CI, inject the Flutter team code signing properties. - developmentTeam = environment['FLUTTER_XCODE_DEVELOPMENT_TEAM'] ?? 'S8QB4VV633'; - codeSignStyle = environment['FLUTTER_XCODE_CODE_SIGN_STYLE']; - provisioningProfile = environment['FLUTTER_XCODE_PROVISIONING_PROFILE_SPECIFIER']; - } + // If not running on CI, inject the Flutter team code signing properties. + final String developmentTeam = environment['FLUTTER_XCODE_DEVELOPMENT_TEAM'] ?? 'S8QB4VV633'; + final String? codeSignStyle = environment['FLUTTER_XCODE_CODE_SIGN_STYLE']; + final String? provisioningProfile = environment['FLUTTER_XCODE_PROVISIONING_PROFILE_SPECIFIER']; + final String resultBundleTemp = Directory.systemTemp.createTempSync('flutter_xcresult.').path; final String resultBundlePath = path.join(resultBundleTemp, 'result'); final int testResultExit = await exec( @@ -174,8 +164,7 @@ Future runXcodeTests({ resultBundlePath, 'test', 'COMPILER_INDEX_STORE_ENABLE=NO', - if (developmentTeam != null) - 'DEVELOPMENT_TEAM=$developmentTeam', + 'DEVELOPMENT_TEAM=$developmentTeam', if (codeSignStyle != null) 'CODE_SIGN_STYLE=$codeSignStyle', if (provisioningProfile != null) diff --git a/dev/devicelab/lib/framework/metrics_center.dart b/dev/devicelab/lib/framework/metrics_center.dart index 6aa1c754edc2c..6a587749eca96 100644 --- a/dev/devicelab/lib/framework/metrics_center.dart +++ b/dev/devicelab/lib/framework/metrics_center.dart @@ -63,13 +63,14 @@ List parse(Map resultsJson, Map b resultsJson['ResultData'] as Map? ?? const {}; final String gitBranch = (resultsJson['CommitBranch'] as String).trim(); final String gitSha = (resultsJson['CommitSha'] as String).trim(); + final String builderName = (resultsJson['BuilderName'] as String).trim(); final List metricPoints = []; for (final String scoreKey in scoreKeys) { Map tags = { kGithubRepoKey: kFlutterFrameworkRepo, kGitRevisionKey: gitSha, 'branch': gitBranch, - kNameKey: taskName, + kNameKey: builderName, kSubResultKey: scoreKey, }; // Append additional benchmark tags, which will surface in Skia Perf dashboards. @@ -81,6 +82,18 @@ List parse(Map resultsJson, Map b tags, ), ); + + // Add an extra entry under test name. This way we have duplicate metrics + // under both builder name and test name. Once we have enough data and update + // existing alerts to point to test name, we can deprecate builder name ones. + // https://github.com/flutter/flutter/issues/74522#issuecomment-942575581 + tags[kNameKey] = taskName; + metricPoints.add( + MetricPoint( + (resultData[scoreKey] as num).toDouble(), + tags, + ), + ); } return metricPoints; } diff --git a/dev/devicelab/lib/framework/runner.dart b/dev/devicelab/lib/framework/runner.dart index 56aa7814ad2df..de7cf5dac56de 100644 --- a/dev/devicelab/lib/framework/runner.dart +++ b/dev/devicelab/lib/framework/runner.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:convert'; +// import 'dart:core' as core; import 'dart:io'; import 'package:meta/meta.dart'; @@ -28,10 +29,6 @@ import 'utils.dart'; Future runTasks( List taskNames, { bool exitOnFirstTestFailure = false, - // terminateStrayDartProcesses defaults to false so that tests don't have to specify it. - // It is set based on the --terminate-stray-dart-processes command line argument in - // normal execution, and that flag defaults to true. - bool terminateStrayDartProcesses = false, bool silent = false, String? deviceId, String? gitBranch, @@ -53,7 +50,6 @@ Future runTasks( deviceId: deviceId, localEngine: localEngine, localEngineSrcPath: localEngineSrcPath, - terminateStrayDartProcesses: terminateStrayDartProcesses, silent: silent, taskArgs: taskArgs, resultsPath: resultsPath, @@ -62,17 +58,15 @@ Future runTasks( isolateParams: isolateParams, ); + section('Flaky status for "$taskName"'); if (!result.succeeded) { - retry += 1; + retry++; } else { - section('Flaky status for "$taskName"'); if (retry > 0) { - print('Total ${retry+1} executions: $retry failures and 1 false positive.'); + print('Total ${retry+1} executions: $retry failures and 1 success'); print('flaky: true'); - // TODO(ianh): stop ignoring this failure. We should set exitCode=1, and quit - // if exitOnFirstTestFailure is true. } else { - print('Test passed on first attempt.'); + print('Total ${retry+1} executions: 1 success'); print('flaky: false'); } break; @@ -80,8 +74,7 @@ Future runTasks( } if (!result.succeeded) { - section('Flaky status for "$taskName"'); - print('Consistently failed across all $retry executions.'); + print('Total $retry executions: 0 success'); print('flaky: false'); exitCode = 1; if (exitOnFirstTestFailure) { @@ -99,7 +92,6 @@ Future rerunTask( String? deviceId, String? localEngine, String? localEngineSrcPath, - bool terminateStrayDartProcesses = false, bool silent = false, List? taskArgs, String? resultsPath, @@ -113,7 +105,6 @@ Future rerunTask( deviceId: deviceId, localEngine: localEngine, localEngineSrcPath: localEngineSrcPath, - terminateStrayDartProcesses: terminateStrayDartProcesses, silent: silent, taskArgs: taskArgs, isolateParams: isolateParams, @@ -147,12 +138,11 @@ Future rerunTask( /// [taskArgs] are passed to the task executable for additional configuration. Future runTask( String taskName, { - bool terminateStrayDartProcesses = false, bool silent = false, String? localEngine, String? localEngineSrcPath, String? deviceId, - List? taskArgs, + List ?taskArgs, @visibleForTesting Map? isolateParams, }) async { final String taskExecutable = 'bin/tasks/$taskName.dart'; @@ -208,26 +198,17 @@ Future runTask( try { final ConnectionResult result = await _connectToRunnerIsolate(await uri.future); - print('[$taskName] Connected to VM server.'); - isolateParams = isolateParams == null ? {} : Map.of(isolateParams); - isolateParams['runProcessCleanup'] = terminateStrayDartProcesses.toString(); final Map taskResultJson = (await result.vmService.callServiceExtension( 'ext.cocoonRunTask', args: isolateParams, isolateId: result.isolate.id, )).json!; final TaskResult taskResult = TaskResult.fromJson(taskResultJson); - final int exitCode = await runner.exitCode; - print('[$taskName] Process terminated with exit code $exitCode.'); + await runner.exitCode; return taskResult; - } catch (error, stack) { - print('[$taskName] Task runner system failed with exception!\n$error\n$stack'); - rethrow; } finally { - if (!runnerFinished) { - print('[$taskName] Terminating process...'); + if (!runnerFinished) runner.kill(ProcessSignal.sigkill); - } await stdoutSub.cancel(); await stderrSub.cancel(); } diff --git a/dev/devicelab/lib/framework/running_processes.dart b/dev/devicelab/lib/framework/running_processes.dart index 96b6e591e67ca..07a5e52739b11 100644 --- a/dev/devicelab/lib/framework/running_processes.dart +++ b/dev/devicelab/lib/framework/running_processes.dart @@ -9,12 +9,12 @@ import 'package:process/process.dart'; @immutable class RunningProcessInfo { - const RunningProcessInfo(this.pid, this.commandLine, this.creationDate) + const RunningProcessInfo(this.pid, this.creationDate, this.commandLine) : assert(pid != null), assert(commandLine != null); - final int pid; final String commandLine; + final String pid; final DateTime creationDate; @override @@ -25,54 +25,57 @@ class RunningProcessInfo { && other.creationDate == creationDate; } - Future terminate({required ProcessManager processManager}) async { - // This returns true when the signal is sent, not when the process goes away. - // See also https://github.com/dart-lang/sdk/issues/40759 (killPid should wait for process to be terminated). - if (Platform.isWindows) { - // TODO(ianh): Move Windows to killPid once we can. - // - killPid on Windows has not-useful return code: https://github.com/dart-lang/sdk/issues/47675 - final ProcessResult result = await processManager.run([ - 'taskkill.exe', - '/pid', - '$pid', - '/f', - ]); - return result.exitCode == 0; - } - return processManager.killPid(pid, ProcessSignal.sigkill); - } - @override int get hashCode => Object.hash(pid, commandLine, creationDate); @override String toString() { - return 'RunningProcesses(pid: $pid, commandLine: $commandLine, creationDate: $creationDate)'; + return 'RunningProcesses{pid: $pid, commandLine: $commandLine, creationDate: $creationDate}'; + } +} + +Future killProcess(String pid, {ProcessManager? processManager}) async { + assert(pid != null, 'Must specify a pid to kill'); + processManager ??= const LocalProcessManager(); + ProcessResult result; + if (Platform.isWindows) { + result = await processManager.run([ + 'taskkill.exe', + '/pid', + pid, + '/f', + ]); + } else { + result = await processManager.run([ + 'kill', + '-9', + pid, + ]); } + return result.exitCode == 0; } -Future> getRunningProcesses({ +Stream getRunningProcesses({ String? processName, - required ProcessManager processManager, + ProcessManager? processManager, }) { + processManager ??= const LocalProcessManager(); if (Platform.isWindows) { - return windowsRunningProcesses(processName, processManager); + return windowsRunningProcesses(processName); } return posixRunningProcesses(processName, processManager); } @visibleForTesting -Future> windowsRunningProcesses( - String? processName, - ProcessManager processManager, -) async { - // PowerShell script to get the command line arguments and create time of a process. +Stream windowsRunningProcesses(String? processName) async* { + // PowerShell script to get the command line arguments and create time of + // a process. // See: https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process final String script = processName != null ? '"Get-CimInstance Win32_Process -Filter \\"name=\'$processName\'\\" | Select-Object ProcessId,CreationDate,CommandLine | Format-Table -AutoSize | Out-String -Width 4096"' : '"Get-CimInstance Win32_Process | Select-Object ProcessId,CreationDate,CommandLine | Format-Table -AutoSize | Out-String -Width 4096"'; - // TODO(ianh): Unfortunately, there doesn't seem to be a good way to get - // ProcessManager to run this. + // Unfortunately, there doesn't seem to be a good way to get ProcessManager to + // run this. final ProcessResult result = await Process.run( 'powershell -command $script', [], @@ -81,9 +84,11 @@ Future> windowsRunningProcesses( print('Could not list processes!'); print(result.stderr); print(result.stdout); - return {}; + return; + } + for (final RunningProcessInfo info in processPowershellOutput(result.stdout as String)) { + yield info; } - return processPowershellOutput(result.stdout as String).toSet(); } /// Parses the output of the PowerShell script from [windowsRunningProcesses]. @@ -144,22 +149,22 @@ Iterable processPowershellOutput(String output) sync* { time = '${hours + 12}${time.substring(2)}'; } - final int pid = int.parse(line.substring(0, processIdHeaderSize).trim()); + final String pid = line.substring(0, processIdHeaderSize).trim(); final DateTime creationDate = DateTime.parse('$year-$month-${day}T$time'); final String commandLine = line.substring(commandLineHeaderStart).trim(); - yield RunningProcessInfo(pid, commandLine, creationDate); + yield RunningProcessInfo(pid, creationDate, commandLine); } } @visibleForTesting -Future> posixRunningProcesses( +Stream posixRunningProcesses( String? processName, ProcessManager processManager, -) async { +) async* { // Cirrus is missing this in Linux for some reason. if (!processManager.canRun('ps')) { - print('Cannot list processes on this system: "ps" not available.'); - return {}; + print('Cannot list processes on this system: `ps` not available.'); + return; } final ProcessResult result = await processManager.run([ 'ps', @@ -170,9 +175,11 @@ Future> posixRunningProcesses( print('Could not list processes!'); print(result.stderr); print(result.stdout); - return {}; + return; + } + for (final RunningProcessInfo info in processPsOutput(result.stdout as String, processName)) { + yield info; } - return processPsOutput(result.stdout as String, processName).toSet(); } /// Parses the output of the command in [posixRunningProcesses]. @@ -233,8 +240,8 @@ Iterable processPsOutput( final DateTime creationDate = DateTime.parse('$year-$month-${day}T$time'); line = line.substring(24).trim(); final int nextSpace = line.indexOf(' '); - final int pid = int.parse(line.substring(0, nextSpace)); + final String pid = line.substring(0, nextSpace); final String commandLine = line.substring(nextSpace + 1); - yield RunningProcessInfo(pid, commandLine, creationDate); + yield RunningProcessInfo(pid, creationDate, commandLine); } } diff --git a/dev/devicelab/lib/framework/utils.dart b/dev/devicelab/lib/framework/utils.dart index b1ef7150a0256..f5d960ba6583e 100644 --- a/dev/devicelab/lib/framework/utils.dart +++ b/dev/devicelab/lib/framework/utils.dart @@ -20,18 +20,14 @@ import 'task_result.dart'; String cwd = Directory.current.path; /// The local engine to use for [flutter] and [evalFlutter], if any. -/// -/// This is set as an environment variable when running the task, see runTask in runner.dart. -String? get localEngineFromEnv { +String? get localEngine { const bool isDefined = bool.hasEnvironment('localEngine'); return isDefined ? const String.fromEnvironment('localEngine') : null; } /// The local engine source path to use if a local engine is used for [flutter] /// and [evalFlutter]. -/// -/// This is set as an environment variable when running the task, see runTask in runner.dart. -String? get localEngineSrcPathFromEnv { +String? get localEngineSrcPath { const bool isDefined = bool.hasEnvironment('localEngineSrcPath'); return isDefined ? const String.fromEnvironment('localEngineSrcPath') : null; } @@ -49,9 +45,9 @@ class ProcessInfo { @override String toString() { return ''' - command: $command - started: $startTime - pid : ${process.pid} + command : $command + started : $startTime + pid : ${process.pid} ''' .trim(); } @@ -279,7 +275,7 @@ Future startProcess( final Map newEnvironment = Map.from(environment ?? {}); newEnvironment['BOT'] = isBot ? 'true' : 'false'; newEnvironment['LANG'] = 'en_US.UTF-8'; - print('Executing "$command" in "$finalWorkingDirectory" with environment $newEnvironment'); + print('\nExecuting: $command in $finalWorkingDirectory with environment $newEnvironment'); final Process process = await _processManager.start( [executable, ...?arguments], environment: newEnvironment, @@ -289,6 +285,7 @@ Future startProcess( _runningProcesses.add(processInfo); unawaited(process.exitCode.then((int exitCode) { + print('"$executable" exit code: $exitCode'); _runningProcesses.remove(processInfo); })); @@ -306,7 +303,7 @@ Future forceQuitRunningProcesses() async { for (final ProcessInfo p in _runningProcesses) { print('Force-quitting process:\n$p'); if (!p.process.kill()) { - print('Failed to force quit process.'); + print('Failed to force quit process'); } } _runningProcesses.clear(); @@ -352,7 +349,7 @@ Future _execute( stderr: stderr, printStdout: printStdout, printStderr: printStderr, - ); + ); final int exitCode = await process.exitCode; if (exitCode != 0 && !canFail) @@ -376,23 +373,23 @@ Future forwardStandardStreams( final Completer stdoutDone = Completer(); final Completer stderrDone = Completer(); process.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen((String line) { - if (printStdout) { - print('stdout: $line'); - } - output?.writeln(line); - }, onDone: () { stdoutDone.complete(); }); + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen((String line) { + if (printStdout) { + print('stdout: $line'); + } + output?.writeln(line); + }, onDone: () { stdoutDone.complete(); }); process.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen((String line) { - if (printStderr) { - print('stderr: $line'); - } - stderr?.writeln(line); - }, onDone: () { stderrDone.complete(); }); + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen((String line) { + if (printStderr) { + print('stderr: $line'); + } + stderr?.writeln(line); + }, onDone: () { stderrDone.complete(); }); return Future.wait(>[ stdoutDone.future, @@ -439,8 +436,6 @@ List flutterCommandArgs(String command, List options) { 'run', 'screenshot', }; - final String? localEngine = localEngineFromEnv; - final String? localEngineSrcPath = localEngineSrcPathFromEnv; return [ command, if (deviceOperatingSystem == DeviceOperatingSystem.ios && supportedDeviceTimeoutCommands.contains(command)) @@ -453,8 +448,8 @@ List flutterCommandArgs(String command, List options) { '--screenshot', hostAgent.dumpDirectory!.path, ], - if (localEngine != null) ...['--local-engine', localEngine], - if (localEngineSrcPath != null) ...['--local-engine-src-path', localEngineSrcPath], + if (localEngine != null) ...['--local-engine', localEngine!], + if (localEngineSrcPath != null) ...['--local-engine-src-path', localEngineSrcPath!], ...options, ]; } diff --git a/dev/devicelab/lib/tasks/integration_tests.dart b/dev/devicelab/lib/tasks/integration_tests.dart index af4dc5573bda9..570f6f5e1592c 100644 --- a/dev/devicelab/lib/tasks/integration_tests.dart +++ b/dev/devicelab/lib/tasks/integration_tests.dart @@ -29,14 +29,6 @@ TaskFunction createFlavorsTest() { ); } -TaskFunction createIntegrationTestFlavorsTest() { - return IntegrationTest( - '${flutterDirectory.path}/dev/integration_tests/flavors', - 'integration_test/integration_test.dart', - extraOptions: ['--flavor', 'paid'], - ); -} - TaskFunction createExternalUiIntegrationTest() { return DriverTest( '${flutterDirectory.path}/dev/integration_tests/external_ui', @@ -174,16 +166,10 @@ class DriverTest { } class IntegrationTest { - IntegrationTest( - this.testDirectory, - this.testTarget, { - this.extraOptions = const [], - } - ); + IntegrationTest(this.testDirectory, this.testTarget); final String testDirectory; final String testTarget; - final List extraOptions; Future call() { return inDirectory(testDirectory, () async { @@ -197,7 +183,6 @@ class IntegrationTest { '-d', deviceId, testTarget, - ...extraOptions, ]; await flutter('test', options: options); diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 306464e562bcb..9ff5fe2e38c47 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -484,41 +484,6 @@ TaskFunction createFramePolicyIntegrationTest() { }; } -TaskFunction createOpacityPeepholeOneRectPerfE2ETest() { - return PerfTest.e2e( - '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', - 'test/opacity_peephole_one_rect_perf_e2e.dart', - ).run; -} - -TaskFunction createOpacityPeepholeColOfRowsPerfE2ETest() { - return PerfTest.e2e( - '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', - 'test/opacity_peephole_col_of_rows_perf_e2e.dart', - ).run; -} - -TaskFunction createOpacityPeepholeOpacityOfGridPerfE2ETest() { - return PerfTest.e2e( - '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', - 'test/opacity_peephole_opacity_of_grid_perf_e2e.dart', - ).run; -} - -TaskFunction createOpacityPeepholeGridOfOpacityPerfE2ETest() { - return PerfTest.e2e( - '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', - 'test/opacity_peephole_grid_of_opacity_perf_e2e.dart', - ).run; -} - -TaskFunction createOpacityPeepholeFadeTransitionTextPerfE2ETest() { - return PerfTest.e2e( - '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', - 'test/opacity_peephole_fade_transition_text_perf_e2e.dart', - ).run; -} - Map _average(List> results, int iterations) { final Map tally = {}; for (final Map item in results) { @@ -847,14 +812,12 @@ class PerfTest { final Device device = await devices.workingDevice; await device.unlock(); final String deviceId = device.deviceId; - final String? localEngine = localEngineFromEnv; - final String? localEngineSrcPath = localEngineSrcPathFromEnv; await flutter('drive', options: [ if (localEngine != null) - ...['--local-engine', localEngine], + ...['--local-engine', localEngine!], if (localEngineSrcPath != null) - ...['--local-engine-src-path', localEngineSrcPath], + ...['--local-engine-src-path', localEngineSrcPath!], '--no-dds', '--no-android-gradle-daemon', '-v', @@ -1030,16 +993,15 @@ class PerfTestWithSkSL extends PerfTest { if (File(_vmserviceFileName).existsSync()) { File(_vmserviceFileName).deleteSync(); } - final String? localEngine = localEngineFromEnv; - final String? localEngineSrcPath = localEngineSrcPathFromEnv; + _runProcess = await startProcess( _flutterPath, [ 'run', if (localEngine != null) - ...['--local-engine', localEngine], + ...['--local-engine', localEngine!], if (localEngineSrcPath != null) - ...['--local-engine-src-path', localEngineSrcPath], + ...['--local-engine-src-path', localEngineSrcPath!], '--no-dds', if (deviceOperatingSystem == DeviceOperatingSystem.ios) ...[ diff --git a/dev/devicelab/lib/tasks/plugin_tests.dart b/dev/devicelab/lib/tasks/plugin_tests.dart index 4de88a284a4bd..05fc5510dd703 100644 --- a/dev/devicelab/lib/tasks/plugin_tests.dart +++ b/dev/devicelab/lib/tasks/plugin_tests.dart @@ -26,19 +26,12 @@ TaskFunction combine(List tasks) { /// Defines task that creates new Flutter project, adds a local and remote /// plugin, and then builds the specified [buildTarget]. class PluginTest { - PluginTest( - this.buildTarget, - this.options, { - this.pluginCreateEnvironment, - this.appCreateEnvironment, - this.dartOnlyPlugin = false, - }); + PluginTest(this.buildTarget, this.options, { this.pluginCreateEnvironment, this.appCreateEnvironment }); final String buildTarget; final List options; final Map? pluginCreateEnvironment; final Map? appCreateEnvironment; - final bool dartOnlyPlugin; Future call() async { final Directory tempDir = @@ -48,9 +41,6 @@ class PluginTest { final _FlutterProject plugin = await _FlutterProject.create( tempDir, options, buildTarget, name: 'plugintest', template: 'plugin', environment: pluginCreateEnvironment); - if (dartOnlyPlugin) { - await plugin.convertDefaultPluginToDartPlugin(); - } section('Test plugin'); await plugin.test(); section('Create Flutter app'); @@ -62,7 +52,7 @@ class PluginTest { pluginPath: path.join('..', 'plugintest')); await app.addPlugin('path_provider'); section('Build app'); - await app.build(buildTarget, validateNativeBuildProject: !dartOnlyPlugin); + await app.build(buildTarget); section('Test app'); await app.test(); } finally { @@ -86,10 +76,8 @@ class _FlutterProject { String get rootPath => path.join(parent.path, name); - File get pubspecFile => File(path.join(rootPath, 'pubspec.yaml')); - Future addPlugin(String plugin, {String? pluginPath}) async { - final File pubspec = pubspecFile; + final File pubspec = File(path.join(rootPath, 'pubspec.yaml')); String content = await pubspec.readAsString(); final String dependency = pluginPath != null ? '$plugin:\n path: $pluginPath' : '$plugin:'; @@ -100,47 +88,6 @@ class _FlutterProject { await pubspec.writeAsString(content, flush: true); } - /// Converts a plugin created from the standard template to a Dart-only - /// plugin. - Future convertDefaultPluginToDartPlugin() async { - final String dartPluginClass = 'DartClassFor$name'; - // Convert the metadata. - final File pubspec = pubspecFile; - String content = await pubspec.readAsString(); - content = content.replaceAll( - RegExp(r' pluginClass: .*?\n'), - ' dartPluginClass: $dartPluginClass\n', - ); - await pubspec.writeAsString(content, flush: true); - - // Add the Dart registration hook that the build will generate a call to. - final File dartCode = File(path.join(rootPath, 'lib', '$name.dart')); - content = await dartCode.readAsString(); - content = ''' -$content - -class $dartPluginClass { - static void registerWith() {} -} -'''; - await dartCode.writeAsString(content, flush: true); - - // Remove any native plugin code. - const List platforms = [ - 'android', - 'ios', - 'linux', - 'macos', - 'windows', - ]; - for (final String platform in platforms) { - final Directory platformDir = Directory(path.join(rootPath, platform)); - if (platformDir.existsSync()) { - await platformDir.delete(recursive: true); - } - } - } - Future test() async { await inDirectory(Directory(rootPath), () async { await flutter('test'); @@ -200,7 +147,7 @@ class $dartPluginClass { podspec.writeAsStringSync(podspecContent, flush: true); } - Future build(String target, {bool validateNativeBuildProject = true}) async { + Future build(String target) async { await inDirectory(Directory(rootPath), () async { final String buildOutput = await evalFlutter('build', options: [ target, @@ -220,31 +167,29 @@ class $dartPluginClass { throw TaskResult.failure('Minimum plugin version warning present'); } - if (validateNativeBuildProject) { - final File podsProject = File(path.join(rootPath, target, 'Pods', 'Pods.xcodeproj', 'project.pbxproj')); - if (!podsProject.existsSync()) { - throw TaskResult.failure('Xcode Pods project file missing at ${podsProject.path}'); - } + final File podsProject = File(path.join(rootPath, target, 'Pods', 'Pods.xcodeproj', 'project.pbxproj')); + if (!podsProject.existsSync()) { + throw TaskResult.failure('Xcode Pods project file missing at ${podsProject.path}'); + } - final String podsProjectContent = podsProject.readAsStringSync(); - if (target == 'ios') { - // Plugins with versions lower than the app version should not have IPHONEOS_DEPLOYMENT_TARGET set. - // The plugintest plugin target should not have IPHONEOS_DEPLOYMENT_TARGET set since it has been lowered - // in _reduceDarwinPluginMinimumVersion to 7, which is below the target version of 9. - if (podsProjectContent.contains('IPHONEOS_DEPLOYMENT_TARGET = 7')) { - throw TaskResult.failure('Plugin build setting IPHONEOS_DEPLOYMENT_TARGET not removed'); - } - if (!podsProjectContent.contains(r'"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386";')) { - throw TaskResult.failure(r'EXCLUDED_ARCHS is not "$(inherited) i386"'); - } + final String podsProjectContent = podsProject.readAsStringSync(); + if (target == 'ios') { + // Plugins with versions lower than the app version should not have IPHONEOS_DEPLOYMENT_TARGET set. + // The plugintest plugin target should not have IPHONEOS_DEPLOYMENT_TARGET set since it has been lowered + // in _reduceDarwinPluginMinimumVersion to 7, which is below the target version of 9. + if (podsProjectContent.contains('IPHONEOS_DEPLOYMENT_TARGET = 7')) { + throw TaskResult.failure('Plugin build setting IPHONEOS_DEPLOYMENT_TARGET not removed'); } - - // Same for macOS deployment target, but 10.8. - // The plugintest target should not have MACOSX_DEPLOYMENT_TARGET set. - if (target == 'macos' && podsProjectContent.contains('MACOSX_DEPLOYMENT_TARGET = 10.8')) { - throw TaskResult.failure('Plugin build setting MACOSX_DEPLOYMENT_TARGET not removed'); + if (!podsProjectContent.contains(r'"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386";')) { + throw TaskResult.failure(r'EXCLUDED_ARCHS is not "$(inherited) i386"'); } } + + // Same for macOS deployment target, but 10.8. + // The plugintest target should not have MACOSX_DEPLOYMENT_TARGET set. + if (target == 'macos' && podsProjectContent.contains('MACOSX_DEPLOYMENT_TARGET = 10.8')) { + throw TaskResult.failure('Plugin build setting MACOSX_DEPLOYMENT_TARGET not removed'); + } } }); } diff --git a/dev/devicelab/lib/versions/gallery.dart b/dev/devicelab/lib/versions/gallery.dart index f8236c159b5a1..71b786f2aa1d1 100644 --- a/dev/devicelab/lib/versions/gallery.dart +++ b/dev/devicelab/lib/versions/gallery.dart @@ -3,4 +3,4 @@ // found in the LICENSE file. /// The pinned version of flutter gallery, used for devicelab tests. -const String galleryVersion = '9eb785cb997ff56c46e933c1c591f0a6f31454f6'; +const String galleryVersion = '40b00d316fbf911788c50599a53213dc291b0627'; diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 1797eb83461e6..c2313a91c7f23 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -6,21 +6,21 @@ environment: sdk: ">=2.12.0-0 <3.0.0" dependencies: - archive: 3.1.8 + archive: 3.1.6 args: 2.3.0 file: 6.1.2 http: 0.13.4 logging: 1.0.2 meta: 1.7.0 - metrics_center: 1.0.3 - path: 1.8.1 - platform: 3.1.0 + metrics_center: 1.0.1 + path: 1.8.0 + platform: 3.0.2 process: 4.2.4 - pubspec_parse: 1.2.0 + pubspec_parse: 1.1.0 shelf: 1.1.4 shelf_static: 1.1.0 stack_trace: 1.10.0 - vm_service: 7.5.0 + vm_service: 7.3.0 webkit_inspection_protocol: 1.0.0 _discoveryapis_commons: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,11 +31,11 @@ dependencies: convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" equatable: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + gcloud: 0.8.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - googleapis_auth: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + googleapis_auth: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - json_annotation: 4.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + json_annotation: 4.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -46,10 +46,10 @@ dependencies: yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,18 +57,19 @@ dev_dependencies: glob: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4c85 +# PUBSPEC CHECKSUM: d345 diff --git a/dev/devicelab/test/metrics_center_test.dart b/dev/devicelab/test/metrics_center_test.dart index a7dfff782d82b..54928c215866a 100644 --- a/dev/devicelab/test/metrics_center_test.dart +++ b/dev/devicelab/test/metrics_center_test.dart @@ -38,9 +38,11 @@ void main() { }; final List metricPoints = parse(results, {}, 'test'); - expect(metricPoints.length, 1); + expect(metricPoints.length, 2); expect(metricPoints[0].value, equals(0.4550425531914895)); - expect(metricPoints[0].tags[kNameKey], 'test'); + expect(metricPoints[0].tags[kNameKey], 'Linux test'); + expect(metricPoints[1].value, equals(0.4550425531914895)); + expect(metricPoints[1].tags[kNameKey], 'test'); }); test('without additional benchmark tags', () { @@ -60,7 +62,7 @@ void main() { final List metricPoints = parse(results, {}, 'task abc'); expect(metricPoints[0].value, equals(0.4550425531914895)); - expect(metricPoints[1].value, equals(0.473)); + expect(metricPoints[2].value, equals(0.473)); }); test('with additional benchmark tags', () { @@ -88,8 +90,8 @@ void main() { expect(metricPoints[0].value, equals(0.4550425531914895)); expect(metricPoints[0].tags.keys.contains('arch'), isTrue); - expect(metricPoints[1].value, equals(0.473)); - expect(metricPoints[1].tags.keys.contains('device_type'), isTrue); + expect(metricPoints[2].value, equals(0.473)); + expect(metricPoints[2].tags.keys.contains('device_type'), isTrue); }); test('succeeds - null ResultData', () { diff --git a/dev/devicelab/test/run_test.dart b/dev/devicelab/test/run_test.dart index a5332dd53c7ad..61ff3ea8991e2 100644 --- a/dev/devicelab/test/run_test.dart +++ b/dev/devicelab/test/run_test.dart @@ -4,7 +4,6 @@ import 'dart:io'; -import 'package:flutter_devicelab/framework/utils.dart' show rm; import 'package:path/path.dart' as path; import 'package:process/process.dart'; @@ -21,7 +20,6 @@ void main() { final ProcessResult scriptProcess = processManager.runSync([ dart, 'bin/run.dart', - '--no-terminate-stray-dart-processes', ...otherArgs, for (final String testName in testNames) ...['-t', testName], ]); @@ -89,14 +87,9 @@ void main() { test('runs A/B test', () async { - final Directory tempDirectory = Directory.systemTemp.createTempSync('flutter_devicelab_ab_test.'); - final File abResultsFile = File(path.join(tempDirectory.path, 'test_results.json')); - - expect(abResultsFile.existsSync(), isFalse); - final ProcessResult result = await runScript( ['smoke_test_success'], - ['--ab=2', '--local-engine=host_debug_unopt', '--ab-result-file', abResultsFile.path], + ['--ab=2', '--local-engine=host_debug_unopt'], ); expect(result.exitCode, 0); @@ -144,9 +137,6 @@ void main() { 'metric2\t123.00 (0.00%)\t123.00 (0.00%)\t1.00x\t\n', ), ); - - expect(abResultsFile.existsSync(), isTrue); - rm(tempDirectory, recursive: true); }); test('fails to upload results to Cocoon if flags given', () async { diff --git a/dev/devicelab/test/runner_test.dart b/dev/devicelab/test/runner_test.dart index baee698e06327..661a961035b38 100644 --- a/dev/devicelab/test/runner_test.dart +++ b/dev/devicelab/test/runner_test.dart @@ -11,6 +11,7 @@ import 'common.dart'; void main() { final Map isolateParams = { 'runFlutterConfig': 'false', + 'runProcessCleanup': 'false', 'timeoutInMinutes': '1', }; List printLog; @@ -26,7 +27,7 @@ void main() { logs: printLog, ); expect(printLog.length, 2); - expect(printLog[0], 'Test passed on first attempt.'); + expect(printLog[0], 'Total 1 executions: 1 success'); expect(printLog[1], 'flaky: false'); }); @@ -39,7 +40,7 @@ void main() { logs: printLog, ); expect(printLog.length, 2); - expect(printLog[0], 'Consistently failed across all 3 executions.'); + expect(printLog[0], 'Total 3 executions: 0 success'); expect(printLog[1], 'flaky: false'); }); }); diff --git a/dev/devicelab/test/running_processes_test.dart b/dev/devicelab/test/running_processes_test.dart index 100b3dd9cf126..76f3df029e64a 100644 --- a/dev/devicelab/test/running_processes_test.dart +++ b/dev/devicelab/test/running_processes_test.dart @@ -2,13 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - import 'package:flutter_devicelab/framework/running_processes.dart'; -import 'package:process/process.dart'; - import 'common.dart'; void main() { @@ -30,19 +24,19 @@ ProcessId CreationDate CommandLine results, equals([ RunningProcessInfo( - 6552, - r'"C:\tools\dart-sdk\bin\dart.exe" .\bin\agent.dart ci', + '6552', DateTime(2019, 7, 3, 17, 0, 27), + r'"C:\tools\dart-sdk\bin\dart.exe" .\bin\agent.dart ci', ), RunningProcessInfo( - 6553, - r'"C:\tools\dart-sdk1\bin\dart.exe" .\bin\agent.dart ci', + '6553', DateTime(2019, 7, 3, 22, 0, 27), + r'"C:\tools\dart-sdk1\bin\dart.exe" .\bin\agent.dart ci', ), RunningProcessInfo( - 6554, - r'"C:\tools\dart-sdk2\bin\dart.exe" .\bin\agent.dart ci', + '6554', DateTime(2019, 7, 3, 11, 0, 27), + r'"C:\tools\dart-sdk2\bin\dart.exe" .\bin\agent.dart ci', ), ])); }); @@ -61,81 +55,15 @@ Sat Mar 9 20:13:00 2019 49 /usr/sbin/syslogd results, equals([ RunningProcessInfo( - 1, - '/sbin/launchd', + '1', DateTime(2019, 3, 9, 20, 12, 47), + '/sbin/launchd', ), RunningProcessInfo( - 49, - '/usr/sbin/syslogd', + '49', DateTime(2019, 3, 9, 20, 13), + '/usr/sbin/syslogd', ), ])); }); - - test('RunningProcessInfo.terminate', () { - final RunningProcessInfo process = RunningProcessInfo(123, 'test', DateTime(456)); - final FakeProcessManager fakeProcessManager = FakeProcessManager(); - process.terminate(processManager: fakeProcessManager); - if (Platform.isWindows) { - expect(fakeProcessManager.log, ['run([taskkill.exe, /pid, 123, /f], null, null, null, null, null, null)']); - } else { - expect(fakeProcessManager.log, ['killPid(123, SIGKILL)']); - } - }); -} - -class FakeProcessManager implements ProcessManager { - final List log = []; - - @override - bool canRun(Object? a, { String? workingDirectory }) { - log.add('canRun($a, $workingDirectory)'); - return true; - } - - @override - bool killPid(int a, [ProcessSignal? b]) { - log.add('killPid($a, $b)'); - return true; - } - - @override - Future run(List a, { - Map? environment, - bool? includeParentEnvironment, - bool? runInShell, - Encoding? stderrEncoding, - Encoding? stdoutEncoding, - String? workingDirectory, - }) async { - log.add('run($a, $environment, $includeParentEnvironment, $runInShell, $stderrEncoding, $stdoutEncoding, $workingDirectory)'); - return ProcessResult(1, 0, 'stdout', 'stderr'); - } - - @override - ProcessResult runSync(List a, { - Map? environment, - bool? includeParentEnvironment, - bool? runInShell, - Encoding? stderrEncoding, - Encoding? stdoutEncoding, - String? workingDirectory, - }) { - log.add('runSync($a, $environment, $includeParentEnvironment, $runInShell, $stderrEncoding, $stdoutEncoding, $workingDirectory)'); - return ProcessResult(1, 0, 'stdout', 'stderr'); - } - - @override - Future start( - List a, { - Map? environment, - bool? includeParentEnvironment, - ProcessStartMode? mode, - bool? runInShell, - String? workingDirectory, - }) { - log.add('start($a, $environment, $includeParentEnvironment, $mode, $runInShell, $workingDirectory)'); - return Completer().future; - } } diff --git a/dev/devicelab/test/tasks/build_test_task_test.dart b/dev/devicelab/test/tasks/build_test_task_test.dart index 70bb86b5b647c..5cc8b98098931 100644 --- a/dev/devicelab/test/tasks/build_test_task_test.dart +++ b/dev/devicelab/test/tasks/build_test_task_test.dart @@ -12,6 +12,7 @@ import '../common.dart'; void main() { final Map isolateParams = { 'runFlutterConfig': 'false', + 'runProcessCleanup': 'false', 'timeoutInMinutes': '1', }; @@ -65,7 +66,7 @@ void main() { final String capturedPrint = capturedPrintLines.toString(); expect(capturedPrint, contains('with environment {FLUTTER_DEVICELAB_DEVICEID: FAKE_SUCCESS, BOT: true, LANG: en_US.UTF-8}')); - expect(capturedPrint, contains('Process terminated with exit code 0.')); + expect(capturedPrint, contains('exit code: 0')); }); test('throws exception when build and test arg are given', () async { diff --git a/dev/devicelab/test/utils_test.dart b/dev/devicelab/test/utils_test.dart index ca3e12b3b2dc1..06db6a1d1fd63 100644 --- a/dev/devicelab/test/utils_test.dart +++ b/dev/devicelab/test/utils_test.dart @@ -36,8 +36,8 @@ void main() { group('engine environment declarations', () { test('localEngine', () { - expect(localEngineFromEnv, null); - expect(localEngineSrcPathFromEnv, null); + expect(localEngine, null); + expect(localEngineSrcPath, null); }); }); } diff --git a/dev/docs/assets/overrides.css b/dev/docs/assets/overrides.css index ee3d3f9931a0e..dd8324effebaa 100644 --- a/dev/docs/assets/overrides.css +++ b/dev/docs/assets/overrides.css @@ -5,6 +5,7 @@ body { line-height: 1.5; color: #111; background-color: #fdfdfd; + font-weight: 300; -webkit-font-smoothing: auto; } @@ -22,11 +23,23 @@ header.header-fixed nav.navbar-fixed-top { box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.37); } +h1, h2 { + font-weight: 300; +} + +h3, h4, h5, h6 { + font-weight: 400; +} + h1 { font-size: 42px !important; letter-spacing: -1px; } +header h1 { + font-weight: 300; +} + h2 { color: #111; font-size: 24px; @@ -79,6 +92,7 @@ pre.prettyprint { code { background-color: inherit; font-size: 1em; /* browsers default to smaller font for code */ + font-weight: 300; padding-left: 0; /* otherwise we get ragged left margins */ padding-right: 0; } @@ -111,6 +125,11 @@ i.md-36 { vertical-align: bottom; } +/* thinify the inherited names in lists */ +li.inherited a { + font-weight: 100; +} + /* address a style issue with the background of code sections */ code.hljs { background: inherit; diff --git a/dev/docs/google2ed1af765c529f57.html b/dev/docs/google2ed1af765c529f57.html new file mode 100644 index 0000000000000..b3e07102469c2 --- /dev/null +++ b/dev/docs/google2ed1af765c529f57.html @@ -0,0 +1 @@ +google-site-verification: google2ed1af765c529f57.html \ No newline at end of file diff --git a/dev/docs/styles.html b/dev/docs/styles.html index 554a797c35ba4..104b38d1b3886 100644 --- a/dev/docs/styles.html +++ b/dev/docs/styles.html @@ -4,7 +4,7 @@ @import 'https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Sharp|Material+Icons+Round'; - + diff --git a/dev/forbidden_from_release_tests/pubspec.yaml b/dev/forbidden_from_release_tests/pubspec.yaml index ac87f31ca7d8f..0612328e66df8 100644 --- a/dev/forbidden_from_release_tests/pubspec.yaml +++ b/dev/forbidden_from_release_tests/pubspec.yaml @@ -8,12 +8,12 @@ dependencies: args: 2.3.0 file: 6.1.2 package_config: 2.0.2 - path: 1.8.1 + path: 1.8.0 process: 4.2.4 vm_snapshot_analysis: 0.7.0 collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c258 +# PUBSPEC CHECKSUM: a058 diff --git a/dev/integration_tests/abstract_method_smoke_test/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/abstract_method_smoke_test/android/app/src/main/AndroidManifest.xml index 555c2343e01a8..9c6eacb2bcbec 100644 --- a/dev/integration_tests/abstract_method_smoke_test/android/app/src/main/AndroidManifest.xml +++ b/dev/integration_tests/abstract_method_smoke_test/android/app/src/main/AndroidManifest.xml @@ -6,13 +6,13 @@ found in the LICENSE file. --> package="com.example.abstract_method_smoke_test"> - + FlutterApplication and put your custom class here. --> - + FlutterApplication and put your custom class here. --> --> - - + FlutterApplication and put your custom class here. --> + - - diff --git a/dev/integration_tests/android_semantics_testing/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java b/dev/integration_tests/android_semantics_testing/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java index e753f4eda6c33..325569c98e8f8 100644 --- a/dev/integration_tests/android_semantics_testing/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java +++ b/dev/integration_tests/android_semantics_testing/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java @@ -16,16 +16,13 @@ import android.util.DisplayMetrics; import android.view.WindowManager; import android.content.Context; -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity; -import io.flutter.embedding.engine.FlutterEngine; -import io.flutter.embedding.android.FlutterActivity; -import io.flutter.embedding.android.FlutterView; +import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugins.GeneratedPluginRegistrant; +import io.flutter.view.FlutterView; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeProvider; @@ -33,10 +30,10 @@ public class MainActivity extends FlutterActivity { @Override - public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "semantics") - .setMethodCallHandler(new SemanticsTesterMethodHandler()); + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + new MethodChannel(getFlutterView(), "semantics").setMethodCallHandler(new SemanticsTesterMethodHandler()); } class SemanticsTesterMethodHandler implements MethodCallHandler { @@ -44,7 +41,7 @@ class SemanticsTesterMethodHandler implements MethodCallHandler { @Override public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) { - FlutterView flutterView = findViewById(FLUTTER_VIEW_ID); + FlutterView flutterView = getFlutterView(); AccessibilityNodeProvider provider = flutterView.getAccessibilityNodeProvider(); DisplayMetrics displayMetrics = new DisplayMetrics(); WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); diff --git a/dev/integration_tests/android_semantics_testing/android/project-app.lockfile b/dev/integration_tests/android_semantics_testing/android/project-app.lockfile index b5b0b745c3536..0a88943553da0 100644 --- a/dev/integration_tests/android_semantics_testing/android/project-app.lockfile +++ b/dev/integration_tests/android_semantics_testing/android/project-app.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugCompi androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -89,18 +87,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/android_semantics_testing/lib/src/matcher.dart b/dev/integration_tests/android_semantics_testing/lib/src/matcher.dart index 626364b26b644..d3f7f27555df9 100644 --- a/dev/integration_tests/android_semantics_testing/lib/src/matcher.dart +++ b/dev/integration_tests/android_semantics_testing/lib/src/matcher.dart @@ -25,7 +25,6 @@ Matcher hasAndroidSemantics({ Rect rect, Size size, List actions, - List ignoredActions, List children, bool isChecked, bool isCheckable, @@ -45,7 +44,6 @@ Matcher hasAndroidSemantics({ size: size, id: id, actions: actions, - ignoredActions: ignoredActions, isChecked: isChecked, isCheckable: isCheckable, isEditable: isEditable, @@ -65,7 +63,6 @@ class _AndroidSemanticsMatcher extends Matcher { this.className, this.id, this.actions, - this.ignoredActions, this.rect, this.size, this.isChecked, @@ -84,7 +81,6 @@ class _AndroidSemanticsMatcher extends Matcher { final String contentDescription; final int id; final List actions; - final List ignoredActions; final Rect rect; final Size size; final bool isChecked; @@ -152,13 +148,9 @@ class _AndroidSemanticsMatcher extends Matcher { if (!unorderedEquals(actions).matches(itemActions, matchState)) { final List actionsString = actions.map((AndroidSemanticsAction action) => action.toString()).toList()..sort(); final List itemActionsString = itemActions.map((AndroidSemanticsAction action) => action.toString()).toList()..sort(); - final Set unexpected = itemActions.toSet().difference(actions.toSet()); - final Set unexpectedInString = itemActionsString.toSet().difference(actionsString.toSet()); - final Set missingInString = actionsString.toSet().difference(itemActionsString.toSet()); - if (missingInString.isEmpty && ignoredActions != null && unexpected.every(ignoredActions.contains)) { - return true; - } - return _failWithMessage('Expected actions: $actionsString\nActual actions: $itemActionsString\nUnexpected: $unexpectedInString\nMissing: $missingInString', matchState); + final Set unexpected = itemActionsString.toSet().difference(actionsString.toSet()); + final Set missing = actionsString.toSet().difference(itemActionsString.toSet()); + return _failWithMessage('Expected actions: $actionsString\nActual actions: $itemActionsString\nUnexpected: $unexpected\nMissing: $missing', matchState); } } if (isChecked != null && isChecked != item.isChecked) diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 01ca03687cbe9..589b0b8160b7c 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -11,11 +11,11 @@ dependencies: flutter_test: sdk: flutter pub_semver: 2.1.0 - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,15 +34,15 @@ dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,11 +56,11 @@ dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -70,4 +70,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e2ca +# PUBSPEC CHECKSUM: f832 diff --git a/dev/integration_tests/android_semantics_testing/test_driver/main_test.dart b/dev/integration_tests/android_semantics_testing/test_driver/main_test.dart index 4b29e23782ee0..299c593dad863 100644 --- a/dev/integration_tests/android_semantics_testing/test_driver/main_test.dart +++ b/dev/integration_tests/android_semantics_testing/test_driver/main_test.dart @@ -11,14 +11,6 @@ import 'package:path/path.dart' as path; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart' hide isInstanceOf; -// The accessibility focus actions are added when a semantics node receives or -// lose accessibility focus. This test ignores these actions since it is hard to -// predict which node has the accessibility focus after a screen changes. -const List ignoredAccessibilityFocusActions = [ - AndroidSemanticsAction.accessibilityFocus, - AndroidSemanticsAction.clearAccessibilityFocus, -]; - String adbPath() { final String androidHome = io.Platform.environment['ANDROID_HOME'] ?? io.Platform.environment['ANDROID_SDK_ROOT']; if (androidHome == null) { @@ -165,10 +157,10 @@ void main() { isFocused: false, isPassword: false, actions: [ + if (talkbackVersion < fixedTalkback) AndroidSemanticsAction.accessibilityFocus, + if (talkbackVersion >= fixedTalkback) AndroidSemanticsAction.clearAccessibilityFocus, AndroidSemanticsAction.click, ], - // We can't predict the a11y focus when the screen changes. - ignoredActions: ignoredAccessibilityFocusActions ), ); diff --git a/dev/integration_tests/android_views/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/android_views/android/app/src/main/AndroidManifest.xml index b3427f9afe586..8387ccf5801b2 100644 --- a/dev/integration_tests/android_views/android/app/src/main/AndroidManifest.xml +++ b/dev/integration_tests/android_views/android/app/src/main/AndroidManifest.xml @@ -9,7 +9,7 @@ found in the LICENSE file. --> --> - - + FlutterApplication and put your custom class here. --> + - + FlutterApplication and put your custom class here. --> @@ -34,7 +34,7 @@ android { defaultConfig { minSdkVersion 16 - targetSdkVersion 31 + targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 4609552032534..6b195b94c2f4d 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -11,29 +11,28 @@ dependencies: flutter_driver: sdk: flutter - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,11 +47,12 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,8 +65,8 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: e2ca +# PUBSPEC CHECKSUM: f832 diff --git a/dev/integration_tests/deferred_components_test/run_release_test.sh b/dev/integration_tests/deferred_components_test/run_release_test.sh index 2f2c7241f0291..64550148a10b2 100755 --- a/dev/integration_tests/deferred_components_test/run_release_test.sh +++ b/dev/integration_tests/deferred_components_test/run_release_test.sh @@ -32,25 +32,14 @@ java -jar $bundletool_jar_path install-apks --apks=build/app/outputs/bundle/rele $adb_path shell " am start -n io.flutter.integration.deferred_components_test/.MainActivity +sleep 20 exit " -run_start_time_seconds=$(date +%s) -while read LOGLINE -do - if [[ "${LOGLINE}" == *"Running deferred code"* ]]; then - echo "Found ${LOGLINE}" - echo "All tests passed." - pkill -P $$ - exit 0 - fi - # Timeout if expected log not found - current_time=$(date +%s) - if [[ $((current_time - run_start_time_seconds)) -ge 300 ]]; then - echo "Failure: Timed out, deferred component did not load." - pkill -P $$ - exit 1 - fi -done < <($adb_path logcat -T "$script_start_time") - +$adb_path logcat -d -t "$script_start_time" -s "flutter" > build/app/outputs/bundle/release/run_logcat.log +echo "" +if cat build/app/outputs/bundle/release/run_logcat.log | grep -q "Running deferred code"; then + echo "All tests passed." + exit 0 +fi echo "Failure: Deferred component did not load." exit 1 diff --git a/dev/integration_tests/external_ui/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/external_ui/android/app/src/main/AndroidManifest.xml index e47926ea5033c..1639018a5372d 100644 --- a/dev/integration_tests/external_ui/android/app/src/main/AndroidManifest.xml +++ b/dev/integration_tests/external_ui/android/app/src/main/AndroidManifest.xml @@ -8,12 +8,11 @@ found in the LICENSE file. --> @@ -22,10 +21,5 @@ found in the LICENSE file. --> - - diff --git a/dev/integration_tests/external_ui/android/app/src/main/java/io/flutter/externalui/MainActivity.java b/dev/integration_tests/external_ui/android/app/src/main/java/io/flutter/externalui/MainActivity.java index 2188463e4ba66..b6e56e71d9b36 100644 --- a/dev/integration_tests/external_ui/android/app/src/main/java/io/flutter/externalui/MainActivity.java +++ b/dev/integration_tests/external_ui/android/app/src/main/java/io/flutter/externalui/MainActivity.java @@ -11,24 +11,18 @@ import android.os.Bundle; import android.view.Surface; import android.view.SurfaceHolder; -import android.view.View; -import androidx.annotation.NonNull; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicInteger; -import io.flutter.embedding.android.FlutterActivity; -import io.flutter.embedding.android.FlutterSurfaceView; -import io.flutter.embedding.android.FlutterView; -import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.view.TextureRegistry; import io.flutter.view.TextureRegistry.SurfaceTextureEntry; -import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { private Surface surface; @@ -41,9 +35,10 @@ public class MainActivity extends FlutterActivity { private AtomicInteger framesConsumed = new AtomicInteger(0); @Override - public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - final MethodChannel channel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "texture"); + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final MethodChannel channel = new MethodChannel(getFlutterView(), "texture"); channel.setMethodCallHandler(new MethodCallHandler() { @Override public void onMethodCall(MethodCall methodCall, Result result) { @@ -98,14 +93,11 @@ public void run() { } } }); - } - @Override - public void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView) { - flutterSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { + getFlutterView().getHolder().addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { - final SurfaceTextureEntry textureEntry = flutterSurfaceView.getAttachedRenderer().createSurfaceTexture(); + final SurfaceTextureEntry textureEntry = getFlutterView().createSurfaceTexture(); texture = textureEntry.surfaceTexture(); texture.setDefaultBufferSize(300, 200); surface = new Surface(texture); diff --git a/dev/integration_tests/external_ui/android/project-app.lockfile b/dev/integration_tests/external_ui/android/project-app.lockfile index b5b0b745c3536..0a88943553da0 100644 --- a/dev/integration_tests/external_ui/android/project-app.lockfile +++ b/dev/integration_tests/external_ui/android/project-app.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugCompi androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -89,18 +87,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index 1b316bffb2e7d..0d048f5113f11 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -9,11 +9,11 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,15 +30,15 @@ dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,11 +53,11 @@ dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2211 +# PUBSPEC CHECKSUM: fb78 diff --git a/dev/integration_tests/flavors/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/flavors/android/app/src/main/AndroidManifest.xml index 664706aee1380..e1a37c0da7e93 100644 --- a/dev/integration_tests/flavors/android/app/src/main/AndroidManifest.xml +++ b/dev/integration_tests/flavors/android/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ found in the LICENSE file. --> - - diff --git a/dev/integration_tests/flavors/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java b/dev/integration_tests/flavors/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java index 57566001ce998..7e6d4fe711314 100644 --- a/dev/integration_tests/flavors/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java +++ b/dev/integration_tests/flavors/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java @@ -6,22 +6,21 @@ import android.os.Bundle; -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity; -import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { @Override - public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "flavor") - .setMethodCallHandler( - (call, result) -> { - result.success(BuildConfig.FLAVOR); - } - ); + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + new MethodChannel(getFlutterView(), "flavor").setMethodCallHandler(new MethodChannel.MethodCallHandler() { + @Override + public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) { + result.success(BuildConfig.FLAVOR); + } + }); } } diff --git a/dev/integration_tests/flavors/android/project-app.lockfile b/dev/integration_tests/flavors/android/project-app.lockfile index 8ef95cea98dc6..1cd19e5fd33c1 100644 --- a/dev/integration_tests/flavors/android/project-app.lockfile +++ b/dev/integration_tests/flavors/android/project-app.lockfile @@ -26,8 +26,6 @@ androidx.test:runner:1.2.0=freeDebugAndroidTestCompileClasspath,freeDebugCompile androidx.tracing:tracing:1.0.0=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -102,18 +100,11 @@ org.hamcrest:hamcrest-integration:1.3=freeDebugAndroidTestCompileClasspath,freeD org.hamcrest:hamcrest-library:1.3=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=freeDebugAndroidTestCompileClasspath,freeDebugCompileClasspath,freeDebugRuntimeClasspath,freeDebugUnitTestCompileClasspath,freeDebugUnitTestRuntimeClasspath,freeProfileCompileClasspath,freeProfileRuntimeClasspath,freeProfileUnitTestCompileClasspath,freeProfileUnitTestRuntimeClasspath,freeReleaseCompileClasspath,freeReleaseRuntimeClasspath,freeReleaseUnitTestCompileClasspath,freeReleaseUnitTestRuntimeClasspath,lintClassPath,paidDebugAndroidTestCompileClasspath,paidDebugCompileClasspath,paidDebugRuntimeClasspath,paidDebugUnitTestCompileClasspath,paidDebugUnitTestRuntimeClasspath,paidProfileCompileClasspath,paidProfileRuntimeClasspath,paidProfileUnitTestCompileClasspath,paidProfileUnitTestRuntimeClasspath,paidReleaseCompileClasspath,paidReleaseRuntimeClasspath,paidReleaseUnitTestCompileClasspath,paidReleaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/flavors/android/project-integration_test.lockfile b/dev/integration_tests/flavors/android/project-integration_test.lockfile index ca99c9e81b5be..4311264526585 100644 --- a/dev/integration_tests/flavors/android/project-integration_test.lockfile +++ b/dev/integration_tests/flavors/android/project-integration_test.lockfile @@ -26,8 +26,6 @@ androidx.test:runner:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRunt androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -101,18 +99,11 @@ org.hamcrest:hamcrest-integration:1.3=debugAndroidTestCompileClasspath,debugAndr org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/flavors/integration_test/integration_test.dart b/dev/integration_tests/flavors/integration_test/integration_test.dart deleted file mode 100644 index d2cdd10dd4ec9..0000000000000 --- a/dev/integration_tests/flavors/integration_test/integration_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// 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 'package:flavors/main.dart' as app; -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; - -void main() { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - group('Flavor Test', () { - testWidgets('check flavor', (WidgetTester tester) async { - app.runMainApp(); - await tester.pumpAndSettle(); - await tester.pumpAndSettle(); - - expect(find.text('paid'), findsOneWidget); - }); - }); -} diff --git a/dev/integration_tests/flavors/lib/main.dart b/dev/integration_tests/flavors/lib/main.dart index a618efcdfd8d7..352244761419a 100644 --- a/dev/integration_tests/flavors/lib/main.dart +++ b/dev/integration_tests/flavors/lib/main.dart @@ -8,10 +8,6 @@ import 'package:flutter_driver/driver_extension.dart'; void main() { enableFlutterDriverExtension(); - runMainApp(); -} - -void runMainApp() { runApp(const Center(child: Flavor())); } diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 54b8c4d481227..be981a93b30e1 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -11,11 +11,11 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -32,15 +32,15 @@ dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -55,11 +55,11 @@ dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +76,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e2ca +# PUBSPEC CHECKSUM: f832 diff --git a/dev/integration_tests/flutter_gallery/android/app/build.gradle b/dev/integration_tests/flutter_gallery/android/app/build.gradle index da7c676d89a6d..ddb01d033a529 100644 --- a/dev/integration_tests/flutter_gallery/android/app/build.gradle +++ b/dev/integration_tests/flutter_gallery/android/app/build.gradle @@ -54,7 +54,6 @@ android { versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - multiDexEnabled true } buildTypes { diff --git a/dev/integration_tests/flutter_gallery/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/flutter_gallery/android/app/src/main/AndroidManifest.xml index 6a3813aaf4e74..9a6306186c269 100644 --- a/dev/integration_tests/flutter_gallery/android/app/src/main/AndroidManifest.xml +++ b/dev/integration_tests/flutter_gallery/android/app/src/main/AndroidManifest.xml @@ -11,11 +11,10 @@ found in the LICENSE file. --> --> - + diff --git a/dev/integration_tests/flutter_gallery/android/project-app.lockfile b/dev/integration_tests/flutter_gallery/android/project-app.lockfile index 61ced0051972b..7ad00f9427cab 100644 --- a/dev/integration_tests/flutter_gallery/android/project-app.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-app.lockfile @@ -17,8 +17,6 @@ androidx.lifecycle:lifecycle-livedata:2.0.0=debugAndroidTestCompileClasspath,deb androidx.lifecycle:lifecycle-runtime:2.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-viewmodel:2.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.loader:loader:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.multidex:multidex-instrumentation:2.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath -androidx.multidex:multidex:2.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.test.espresso:espresso-core:3.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.test.espresso:espresso-idling-resource:3.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -28,8 +26,6 @@ androidx.test:runner:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRunt androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta04=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta04=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -61,12 +57,12 @@ com.android.tools:sdk-common:27.1.3=lintClassPath com.android.tools:sdklib:27.1.3=lintClassPath com.android:signflinger:4.1.3=lintClassPath com.android:zipflinger:4.1.3=lintClassPath -com.google.android.exoplayer:exoplayer-common:2.14.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-core:2.14.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-dash:2.14.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-extractor:2.14.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-hls:2.14.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-smoothstreaming:2.14.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-common:2.12.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-core:2.12.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-dash:2.12.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-extractor:2.12.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-hls:2.12.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-smoothstreaming:2.12.1=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath com.google.code.findbugs:jsr305:3.0.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.code.gson:gson:2.8.5=lintClassPath com.google.errorprone:error_prone_annotations:2.3.2=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath @@ -110,18 +106,11 @@ org.hamcrest:hamcrest-integration:1.3=debugAndroidTestCompileClasspath,debugAndr org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/flutter_gallery/android/project-connectivity.lockfile b/dev/integration_tests/flutter_gallery/android/project-connectivity.lockfile index 4df1dc6a42f9d..97f7b16a83995 100644 --- a/dev/integration_tests/flutter_gallery/android/project-connectivity.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-connectivity.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugAndro androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -89,18 +87,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/flutter_gallery/android/project-device_info.lockfile b/dev/integration_tests/flutter_gallery/android/project-device_info.lockfile index 4df1dc6a42f9d..97f7b16a83995 100644 --- a/dev/integration_tests/flutter_gallery/android/project-device_info.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-device_info.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugAndro androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -89,18 +87,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile b/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile index 9d48dc0b092dd..4311264526585 100644 --- a/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile @@ -26,8 +26,6 @@ androidx.test:runner:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRunt androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -101,18 +99,11 @@ org.hamcrest:hamcrest-integration:1.3=debugAndroidTestCompileClasspath,debugAndr org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/flutter_gallery/android/project-url_launcher.lockfile b/dev/integration_tests/flutter_gallery/android/project-url_launcher.lockfile index 327d13e36a4ad..e03fa7d782eec 100644 --- a/dev/integration_tests/flutter_gallery/android/project-url_launcher.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-url_launcher.lockfile @@ -23,8 +23,6 @@ androidx.test:monitor:1.2.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeCl androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath backport-util-concurrent:backport-util-concurrent:3.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath classworlds:classworlds:1.1-alpha-2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.almworks.sqlite4java:sqlite4java:0.282=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -130,18 +128,11 @@ org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntim org.hamcrest:hamcrest-library:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.mockito:mockito-core:1.10.19=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.objenesis:objenesis:2.1=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath diff --git a/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile b/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile deleted file mode 100644 index 327d13e36a4ad..0000000000000 --- a/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile +++ /dev/null @@ -1,164 +0,0 @@ -# This is a Gradle generated file for dependency locking. -# Manual edits can break the build and are not advised. -# This file is expected to be part of source control. -androidx.activity:activity:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.annotation:annotation-experimental:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.annotation:annotation:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.arch.core:core-common:2.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.arch.core:core-runtime:2.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.collection:collection:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.core:core:1.6.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.customview:customview:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.fragment:fragment:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-common-java8:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-livedata-core:2.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-livedata:2.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-viewmodel:2.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.loader:loader:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.test:core:1.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.test:monitor:1.2.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -backport-util-concurrent:backport-util-concurrent:3.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -classworlds:classworlds:1.1-alpha-2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.almworks.sqlite4java:sqlite4java:0.282=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.android.tools.analytics-library:protos:27.1.3=lintClassPath -com.android.tools.analytics-library:shared:27.1.3=lintClassPath -com.android.tools.analytics-library:tracker:27.1.3=lintClassPath -com.android.tools.build:aapt2-proto:4.1.0-alpha01-6193524=lintClassPath -com.android.tools.build:aapt2:4.1.3-6503028=_internal_aapt2_binary -com.android.tools.build:apksig:4.1.3=lintClassPath -com.android.tools.build:apkzlib:4.1.3=lintClassPath -com.android.tools.build:builder-model:4.1.3=lintClassPath -com.android.tools.build:builder-test-api:4.1.3=lintClassPath -com.android.tools.build:builder:4.1.3=lintClassPath -com.android.tools.build:gradle-api:4.1.3=lintClassPath -com.android.tools.build:manifest-merger:27.1.3=lintClassPath -com.android.tools.ddms:ddmlib:27.1.3=lintClassPath -com.android.tools.external.com-intellij:intellij-core:27.1.3=lintClassPath -com.android.tools.external.com-intellij:kotlin-compiler:27.1.3=lintClassPath -com.android.tools.external.org-jetbrains:uast:27.1.3=lintClassPath -com.android.tools.layoutlib:layoutlib-api:27.1.3=lintClassPath -com.android.tools.lint:lint-api:27.1.3=lintClassPath -com.android.tools.lint:lint-checks:27.1.3=lintClassPath -com.android.tools.lint:lint-gradle-api:27.1.3=lintClassPath -com.android.tools.lint:lint-gradle:27.1.3=lintClassPath -com.android.tools.lint:lint-model:27.1.3=lintClassPath -com.android.tools.lint:lint:27.1.3=lintClassPath -com.android.tools:annotations:27.1.3=lintClassPath -com.android.tools:common:27.1.3=lintClassPath -com.android.tools:dvlib:27.1.3=lintClassPath -com.android.tools:repository:27.1.3=lintClassPath -com.android.tools:sdk-common:27.1.3=lintClassPath -com.android.tools:sdklib:27.1.3=lintClassPath -com.android:signflinger:4.1.3=lintClassPath -com.android:zipflinger:4.1.3=lintClassPath -com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.auto.service:auto-service:1.0-rc4=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.auto:auto-common:0.8=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.code.findbugs:jsr305:3.0.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.code.gson:gson:2.8.5=lintClassPath -com.google.errorprone:error_prone_annotations:2.2.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.errorprone:error_prone_annotations:2.3.2=lintClassPath -com.google.guava:failureaccess:1.0.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:guava:27.0.1-jre=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:guava:28.1-jre=lintClassPath -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.j2objc:j2objc-annotations:1.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.j2objc:j2objc-annotations:1.3=lintClassPath -com.google.jimfs:jimfs:1.1=lintClassPath -com.google.protobuf:protobuf-java:2.6.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.protobuf:protobuf-java:3.10.0=lintClassPath -com.googlecode.json-simple:json-simple:1.1=lintClassPath -com.ibm.icu:icu4j:53.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.squareup:javawriter:2.5.0=lintClassPath -com.sun.activation:javax.activation:1.2.0=lintClassPath -com.sun.istack:istack-commons-runtime:3.0.7=lintClassPath -com.sun.xml.fastinfoset:FastInfoset:1.2.15=lintClassPath -commons-codec:commons-codec:1.10=lintClassPath -commons-logging:commons-logging:1.2=lintClassPath -it.unimi.dsi:fastutil:7.2.0=lintClassPath -javax.activation:javax.activation-api:1.2.0=lintClassPath -javax.annotation:javax.annotation-api:1.3.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -javax.inject:javax.inject:1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -javax.xml.bind:jaxb-api:2.3.1=lintClassPath -junit:junit:4.12=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -nekohtml:nekohtml:1.9.6.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -nekohtml:xercesMinimal:1.9.6.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -net.sf.jopt-simple:jopt-simple:4.9=lintClassPath -net.sf.kxml:kxml2:2.3.0=lintClassPath -org.apache.ant:ant-launcher:1.8.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.ant:ant:1.8.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.commons:commons-compress:1.12=lintClassPath -org.apache.httpcomponents:httpclient:4.5.6=lintClassPath -org.apache.httpcomponents:httpcore:4.4.10=lintClassPath -org.apache.httpcomponents:httpmime:4.5.6=lintClassPath -org.apache.maven.wagon:wagon-file:1.0-beta-6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven.wagon:wagon-http-lightweight:1.0-beta-6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven.wagon:wagon-http-shared:1.0-beta-6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven.wagon:wagon-provider-api:1.0-beta-6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-ant-tasks:2.1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-artifact-manager:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-artifact:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-error-diagnostics:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-model:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-plugin-registry:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-profile:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-project:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-repository-metadata:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-settings:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.bouncycastle:bcpkix-jdk15on:1.56=lintClassPath -org.bouncycastle:bcprov-jdk15on:1.52=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.bouncycastle:bcprov-jdk15on:1.56=lintClassPath -org.checkerframework:checker-qual:2.5.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.checkerframework:checker-qual:2.8.1=lintClassPath -org.codehaus.groovy:groovy-all:2.4.15=lintClassPath -org.codehaus.mojo:animal-sniffer-annotations:1.17=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.mojo:animal-sniffer-annotations:1.18=lintClassPath -org.codehaus.plexus:plexus-container-default:1.0-alpha-9-stable-1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.plexus:plexus-interpolation:1.11=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.plexus:plexus-utils:1.5.15=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath -org.glassfish.jaxb:txw2:2.3.1=lintClassPath -org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.hamcrest:hamcrest-library:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jvnet.staxex:stax-ex:1.8=lintClassPath -org.mockito:mockito-core:1.10.19=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.objenesis:objenesis:2.1=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath -org.ow2.asm:asm-analysis:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.ow2.asm:asm-commons:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.ow2.asm:asm-tree:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.ow2.asm:asm-util:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.ow2.asm:asm:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:annotations:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:junit:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:pluginapi:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:plugins-maven-dependency-resolver:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:resources:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:robolectric:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:sandbox:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:shadowapi:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:shadows-framework:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:utils-reflector:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:utils:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -empty=androidApis,androidTestUtil,compile,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAnnotationProcessorClasspath,debugUnitTestAnnotationProcessorClasspath,lintChecks,lintPublish,profileAnnotationProcessorClasspath,profileUnitTestAnnotationProcessorClasspath,releaseAnnotationProcessorClasspath,releaseUnitTestAnnotationProcessorClasspath,testCompile diff --git a/dev/integration_tests/flutter_gallery/android/project-video_player.lockfile b/dev/integration_tests/flutter_gallery/android/project-video_player.lockfile index e955008c4805e..0c45723cf0671 100644 --- a/dev/integration_tests/flutter_gallery/android/project-video_player.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-video_player.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugAndro androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -54,12 +52,12 @@ com.android.tools:sdk-common:27.1.3=lintClassPath com.android.tools:sdklib:27.1.3=lintClassPath com.android:signflinger:4.1.3=lintClassPath com.android:zipflinger:4.1.3=lintClassPath -com.google.android.exoplayer:exoplayer-common:2.14.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-core:2.14.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-dash:2.14.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-extractor:2.14.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-hls:2.14.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android.exoplayer:exoplayer-smoothstreaming:2.14.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-common:2.12.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-core:2.12.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-dash:2.12.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-extractor:2.12.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-hls:2.12.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.android.exoplayer:exoplayer-smoothstreaming:2.12.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.code.findbugs:jsr305:3.0.2=lintClassPath com.google.code.gson:gson:2.8.5=lintClassPath com.google.errorprone:error_prone_annotations:2.3.2=lintClassPath @@ -81,9 +79,6 @@ it.unimi.dsi:fastutil:7.2.0=lintClassPath javax.activation:javax.activation-api:1.2.0=lintClassPath javax.inject:javax.inject:1=lintClassPath javax.xml.bind:jaxb-api:2.3.1=lintClassPath -junit:junit:4.12=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -net.bytebuddy:byte-buddy-agent:1.10.20=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -net.bytebuddy:byte-buddy:1.10.20=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.sf.jopt-simple:jopt-simple:4.9=lintClassPath net.sf.kxml:kxml2:2.3.0=lintClassPath org.apache.commons:commons-compress:1.12=lintClassPath @@ -97,25 +92,14 @@ org.codehaus.groovy:groovy-all:2.4.15=lintClassPath org.codehaus.mojo:animal-sniffer-annotations:1.18=lintClassPath org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath -org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath -org.mockito:mockito-core:3.9.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.mockito:mockito-inline:3.9.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.objenesis:objenesis:3.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath org.ow2.asm:asm-tree:7.0=lintClassPath diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart index 8d031674f34c9..cdf0a9da2cd48 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart @@ -10,6 +10,7 @@ import '../../gallery/demo.dart'; class _InputDropdown extends StatelessWidget { const _InputDropdown({ Key? key, + this.child, this.labelText, this.valueText, this.valueStyle, @@ -20,6 +21,7 @@ class _InputDropdown extends StatelessWidget { final String? valueText; final TextStyle? valueStyle; final VoidCallback? onPressed; + final Widget? child; @override Widget build(BuildContext context) { diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart index 8ba3357061b19..90cf627eb832b 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart @@ -112,7 +112,9 @@ TextTheme _buildShrineTextTheme(TextTheme base) { const ColorScheme kShrineColorScheme = ColorScheme( primary: kShrinePink100, + primaryVariant: kShrineBrown900, secondary: kShrinePink50, + secondaryVariant: kShrineBrown900, surface: kShrineSurfaceWhite, background: kShrineBackgroundWhite, error: kShrineErrorRed, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/video_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/video_demo.dart index 33fe67f109c62..0df6ff2183b1b 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/video_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/video_demo.dart @@ -382,12 +382,14 @@ class _VideoDemoState extends State with SingleTickerProviderStateMix super.initState(); Future initController(VideoPlayerController controller, String name) async { + print('> VideoDemo initController "$name" ${isDisposed ? "DISPOSED" : ""}'); controller.setLooping(true); controller.setVolume(0.0); controller.play(); await connectedCompleter.future; await controller.initialize(); if (mounted) { + print('< VideoDemo initController "$name" done ${isDisposed ? "DISPOSED" : ""}'); setState(() { }); } } @@ -401,9 +403,11 @@ class _VideoDemoState extends State with SingleTickerProviderStateMix @override void dispose() { + print('> VideoDemo dispose'); isDisposed = true; butterflyController.dispose(); beeController.dispose(); + print('< VideoDemo dispose'); super.dispose(); } diff --git a/dev/integration_tests/flutter_gallery/macos/Podfile.lock b/dev/integration_tests/flutter_gallery/macos/Podfile.lock index ddad43d5ebaac..81a795ade4d15 100644 --- a/dev/integration_tests/flutter_gallery/macos/Podfile.lock +++ b/dev/integration_tests/flutter_gallery/macos/Podfile.lock @@ -32,4 +32,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: b5c36ba411e4471a03727d0463fa17be341876c1 -COCOAPODS: 1.11.2 +COCOAPODS: 1.10.2 diff --git a/dev/integration_tests/flutter_gallery/macos/Runner/Base.lproj/MainMenu.xib b/dev/integration_tests/flutter_gallery/macos/Runner/Base.lproj/MainMenu.xib index 80e867a4e06b4..537341abf994b 100644 --- a/dev/integration_tests/flutter_gallery/macos/Runner/Base.lproj/MainMenu.xib +++ b/dev/integration_tests/flutter_gallery/macos/Runner/Base.lproj/MainMenu.xib @@ -323,10 +323,6 @@ - - - - diff --git a/dev/integration_tests/flutter_gallery/macos/RunnerTests/RunnerTests.m b/dev/integration_tests/flutter_gallery/macos/RunnerTests/RunnerTests.m index 80dba8485a522..6eaba2fe45613 100644 --- a/dev/integration_tests/flutter_gallery/macos/RunnerTests/RunnerTests.m +++ b/dev/integration_tests/flutter_gallery/macos/RunnerTests/RunnerTests.m @@ -18,16 +18,11 @@ - (void)testMenu { NSMenu *mainMenu = NSApplication.sharedApplication.mainMenu; XCTAssertEqual([mainMenu indexOfItemWithSubmenu:applicationMenu], 0); - // The number of submenu items changes depending on what the OS decides to inject. - // Just check there's at least one per menu item. - XCTAssertGreaterThanOrEqual([mainMenu itemWithTitle:@"Edit"].submenu.numberOfItems, 1); - XCTAssertGreaterThanOrEqual([mainMenu itemWithTitle:@"View"].submenu.numberOfItems, 1); - XCTAssertGreaterThanOrEqual([mainMenu itemWithTitle:@"Window"].submenu.numberOfItems, 1); - - NSMenu *helpMenu = NSApplication.sharedApplication.helpMenu; - XCTAssertNotNil(helpMenu); - // Only the help menu search text box. - XCTAssertEqual(helpMenu.numberOfItems, 0); + XCTAssertEqual([mainMenu itemWithTitle:@"Edit"].submenu.numberOfItems, 19); + XCTAssertEqual([mainMenu itemWithTitle:@"View"].submenu.numberOfItems, 1); + XCTAssertEqual([mainMenu itemWithTitle:@"Window"].submenu.numberOfItems, 6); + + XCTAssertNil(NSApplication.sharedApplication.helpMenu); } @end diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 9c885eff01922..a7f505ac52dd0 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -7,13 +7,13 @@ dependencies: flutter: sdk: flutter collection: 1.15.0 - device_info: 2.0.3 + device_info: 2.0.2 intl: 0.17.0 connectivity: 3.0.6 string_scanner: 1.1.0 - url_launcher: 6.0.18 - cupertino_icons: 1.0.4 - video_player: 2.2.11 + url_launcher: 6.0.12 + cupertino_icons: 1.0.3 + video_player: 2.1.1 scoped_model: git: url: https://github.com/kevmoo/scoped_model.git @@ -24,34 +24,35 @@ dependencies: # and dev/benchmarks/macrobenchmarks/pubspec.yaml flutter_gallery_assets: 1.0.2 + async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" charcode: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" connectivity_for_web: 0.4.0+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" connectivity_macos: 0.2.1+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" connectivity_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - csslib: 0.17.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" device_info_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - html: 0.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_android: 6.0.14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_ios: 6.0.14 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_linux: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_macos: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_platform_interface: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_web: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_platform_interface: 2.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_web: 2.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_windows: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - video_player_platform_interface: 5.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - video_player_web: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + video_player_platform_interface: 4.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + video_player_web: 2.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -60,21 +61,18 @@ dev_dependencies: sdk: flutter flutter_goldens: sdk: flutter - test: 1.20.1 + test: 1.17.12 integration_test: sdk: flutter - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,11 +80,11 @@ dev_dependencies: http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -96,12 +94,9 @@ dev_dependencies: shelf_web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -279,4 +274,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 4f62 +# PUBSPEC CHECKSUM: 8286 diff --git a/dev/integration_tests/flutter_gallery/test/flutter_test_config.dart b/dev/integration_tests/flutter_gallery/test/flutter_test_config.dart index 7f81bd9d4a969..d552235d6903e 100644 --- a/dev/integration_tests/flutter_gallery/test/flutter_test_config.dart +++ b/dev/integration_tests/flutter_gallery/test/flutter_test_config.dart @@ -2,20 +2,4 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; - -import 'package:flutter/rendering.dart'; -import 'package:flutter_goldens/flutter_goldens.dart' as flutter_goldens show testExecutable; -import 'package:flutter_test/flutter_test.dart'; - -Future testExecutable(FutureOr Function() testMain) { - // Enable extra checks since this package exercises a lot of the framework. - debugCheckIntrinsicSizes = true; - - // Make tap() et al fail if the given finder specifies a widget that would not - // receive the event. - WidgetController.hitTestWarningShouldBeFatal = true; - - // Enable golden file testing using Skia Gold. - return flutter_goldens.testExecutable(testMain); -} +export 'package:flutter_goldens/flutter_goldens.dart' show testExecutable; diff --git a/dev/integration_tests/flutter_gallery/test/smoke_test.dart b/dev/integration_tests/flutter_gallery/test/smoke_test.dart index 2de7e2f973a27..ee448eabe8134 100644 --- a/dev/integration_tests/flutter_gallery/test/smoke_test.dart +++ b/dev/integration_tests/flutter_gallery/test/smoke_test.dart @@ -118,7 +118,7 @@ Future smokeOptionsPage(WidgetTester tester) async { // Switch back to system theme setting: first menu button, choose 'System Default' await tester.tap(find.byIcon(Icons.arrow_drop_down).first); await tester.pumpAndSettle(); - await tester.tap(find.text('System Default').at(1), warnIfMissed: false); // https://github.com/flutter/flutter/issues/82908 + await tester.tap(find.text('System Default').at(1)); await tester.pumpAndSettle(); // Switch text direction: first switch diff --git a/dev/integration_tests/gradle_deprecated_settings/android/app/build.gradle b/dev/integration_tests/gradle_deprecated_settings/android/app/build.gradle index 18cf6ccc8dcdc..1b45b600b3b25 100644 --- a/dev/integration_tests/gradle_deprecated_settings/android/app/build.gradle +++ b/dev/integration_tests/gradle_deprecated_settings/android/app/build.gradle @@ -19,7 +19,8 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 31 + // TODO(egarciad): Bump once https://github.com/flutter/flutter/issues/89578 is fixed. + compileSdkVersion 30 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml index 664706aee1380..e1a37c0da7e93 100644 --- a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml +++ b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ found in the LICENSE file. --> - - diff --git a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java index 488c7fb7e6c2d..24f93ca13d830 100644 --- a/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java +++ b/dev/integration_tests/gradle_deprecated_settings/android/app/src/main/java/com/yourcompany/flavors/MainActivity.java @@ -4,6 +4,15 @@ package com.yourcompany.flavors; -import io.flutter.embedding.android.FlutterActivity; +import android.os.Bundle; -public class MainActivity extends FlutterActivity {} +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/dev/integration_tests/gradle_deprecated_settings/android/project-app.lockfile b/dev/integration_tests/gradle_deprecated_settings/android/project-app.lockfile index b5b0b745c3536..0a88943553da0 100644 --- a/dev/integration_tests/gradle_deprecated_settings/android/project-app.lockfile +++ b/dev/integration_tests/gradle_deprecated_settings/android/project-app.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugCompi androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -89,18 +87,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/gradle_deprecated_settings/android/project-camera.lockfile b/dev/integration_tests/gradle_deprecated_settings/android/project-camera.lockfile index e51ff43d0cfea..82e1905ccf2ed 100644 --- a/dev/integration_tests/gradle_deprecated_settings/android/project-camera.lockfile +++ b/dev/integration_tests/gradle_deprecated_settings/android/project-camera.lockfile @@ -23,8 +23,6 @@ androidx.test:monitor:1.3.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeCl androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath backport-util-concurrent:backport-util-concurrent:3.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath classworlds:classworlds:1.1-alpha-2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.almworks.sqlite4java:sqlite4java:0.282=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -132,18 +130,11 @@ org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntim org.hamcrest:hamcrest-library:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.mockito:mockito-core:3.12.4=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.mockito:mockito-inline:3.12.4=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath diff --git a/dev/integration_tests/gradle_deprecated_settings/android/project-flutter_plugin_android_lifecycle.lockfile b/dev/integration_tests/gradle_deprecated_settings/android/project-flutter_plugin_android_lifecycle.lockfile index 405d4e2b310f8..bdd749b870f9d 100644 --- a/dev/integration_tests/gradle_deprecated_settings/android/project-flutter_plugin_android_lifecycle.lockfile +++ b/dev/integration_tests/gradle_deprecated_settings/android/project-flutter_plugin_android_lifecycle.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugAndro androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -91,18 +89,11 @@ org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.mockito:mockito-core:1.10.19=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.objenesis:objenesis:2.1=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index eef8dacf203e0..735554761a8b2 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -7,21 +7,20 @@ environment: dependencies: flutter: sdk: flutter - camera: 0.9.4+5 + camera: 0.9.4+3 - camera_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_platform_interface: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_web: 0.2.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cross_file: 0.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - flutter_plugin_android_lifecycle: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + flutter_plugin_android_lifecycle: 2.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" quiver: 3.0.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_transform: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,4 +30,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0fed +# PUBSPEC CHECKSUM: 5a87 diff --git a/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml index 0e3e9627e493f..afc37761cd458 100644 --- a/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml +++ b/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml @@ -9,7 +9,7 @@ found in the LICENSE file. --> + + - - + + + + - + FlutterApplication and put your custom class here. --> --> - - + FlutterApplication and put your custom class here. --> + - - diff --git a/dev/integration_tests/platform_interaction/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java b/dev/integration_tests/platform_interaction/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java index 145957d5a182b..c8bc0f9f870ca 100644 --- a/dev/integration_tests/platform_interaction/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java +++ b/dev/integration_tests/platform_interaction/android/app/src/main/java/com/yourcompany/platforminteraction/MainActivity.java @@ -6,22 +6,19 @@ import android.os.Bundle; -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity; -import io.flutter.embedding.engine.FlutterEngine; -import io.flutter.plugin.common.BasicMessageChannel; -import io.flutter.plugin.common.StringCodec; +import io.flutter.app.FlutterActivity; +import io.flutter.plugin.common.*; +import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { - BasicMessageChannel channel; - @Override - public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { - channel = - new BasicMessageChannel<>(flutterEngine.getDartExecutor().getBinaryMessenger(), "navigation-test", StringCodec.INSTANCE); + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); } - public void finish() { + BasicMessageChannel channel = + new BasicMessageChannel<>(getFlutterView(), "navigation-test", StringCodec.INSTANCE); channel.send("ping"); } } diff --git a/dev/integration_tests/platform_interaction/android/project-app.lockfile b/dev/integration_tests/platform_interaction/android/project-app.lockfile index b5b0b745c3536..0a88943553da0 100644 --- a/dev/integration_tests/platform_interaction/android/project-app.lockfile +++ b/dev/integration_tests/platform_interaction/android/project-app.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugCompi androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -89,18 +87,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 79a73e9df1b68..d223b4f9169d2 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -9,11 +9,11 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,15 +30,15 @@ dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,11 +53,11 @@ dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2211 +# PUBSPEC CHECKSUM: fb78 diff --git a/dev/integration_tests/release_smoke_test/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/release_smoke_test/android/app/src/main/AndroidManifest.xml index 63a89a01652c6..f93ecc4b9e0d0 100644 --- a/dev/integration_tests/release_smoke_test/android/app/src/main/AndroidManifest.xml +++ b/dev/integration_tests/release_smoke_test/android/app/src/main/AndroidManifest.xml @@ -5,13 +5,13 @@ found in the LICENSE file. --> - + FlutterApplication and put your custom class here. --> --> - - + FlutterApplication and put your custom class here. --> + + package="com.example.manual_tests"> diff --git a/dev/manual_tests/android/app/src/main/AndroidManifest.xml b/dev/manual_tests/android/app/src/main/AndroidManifest.xml index b2dd6fbee2e23..13cb145790659 100644 --- a/dev/manual_tests/android/app/src/main/AndroidManifest.xml +++ b/dev/manual_tests/android/app/src/main/AndroidManifest.xml @@ -3,27 +3,23 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> - + + - - diff --git a/dev/manual_tests/android/app/src/main/kotlin/com/example/manual_tests/MainActivity.kt b/dev/manual_tests/android/app/src/main/kotlin/com/example/manual_tests/MainActivity.kt new file mode 100644 index 0000000000000..f5dae92f65482 --- /dev/null +++ b/dev/manual_tests/android/app/src/main/kotlin/com/example/manual_tests/MainActivity.kt @@ -0,0 +1,12 @@ +package com.example.manual_tests + +import androidx.annotation.NonNull; +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugins.GeneratedPluginRegistrant + +class MainActivity: FlutterActivity() { + override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + GeneratedPluginRegistrant.registerWith(flutterEngine); + } +} diff --git a/dev/manual_tests/android/app/src/main/kotlin/dev/flutter/manual_tests/MainActivity.kt b/dev/manual_tests/android/app/src/main/kotlin/dev/flutter/manual_tests/MainActivity.kt deleted file mode 100644 index f2ca557a8c1e2..0000000000000 --- a/dev/manual_tests/android/app/src/main/kotlin/dev/flutter/manual_tests/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package dev.flutter.manual_tests - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/dev/manual_tests/android/app/src/main/res/drawable-v21/launch_background.xml b/dev/manual_tests/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index 9f19e2f90407e..0000000000000 --- a/dev/manual_tests/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - diff --git a/dev/manual_tests/android/app/src/main/res/drawable/launch_background.xml b/dev/manual_tests/android/app/src/main/res/drawable/launch_background.xml index 3727f9e00a029..bb6811b2ee10d 100644 --- a/dev/manual_tests/android/app/src/main/res/drawable/launch_background.xml +++ b/dev/manual_tests/android/app/src/main/res/drawable/launch_background.xml @@ -1,4 +1,3 @@ - diff --git a/dev/manual_tests/android/app/src/main/res/values-night/styles.xml b/dev/manual_tests/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index ad5918098914a..0000000000000 --- a/dev/manual_tests/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - diff --git a/dev/manual_tests/android/app/src/main/res/values/styles.xml b/dev/manual_tests/android/app/src/main/res/values/styles.xml index 55fd7b57ee682..223593b171838 100644 --- a/dev/manual_tests/android/app/src/main/res/values/styles.xml +++ b/dev/manual_tests/android/app/src/main/res/values/styles.xml @@ -1,22 +1,11 @@ - - - - - diff --git a/dev/manual_tests/android/app/src/profile/AndroidManifest.xml b/dev/manual_tests/android/app/src/profile/AndroidManifest.xml index 2d503e4fcb935..5009c58c3ca8b 100644 --- a/dev/manual_tests/android/app/src/profile/AndroidManifest.xml +++ b/dev/manual_tests/android/app/src/profile/AndroidManifest.xml @@ -3,7 +3,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> + package="com.example.manual_tests"> diff --git a/dev/manual_tests/android/project-app.lockfile b/dev/manual_tests/android/project-app.lockfile index 340de7c6eee6b..7be934c0b9bb9 100644 --- a/dev/manual_tests/android/project-app.lockfile +++ b/dev/manual_tests/android/project-app.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugApiDe androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta04=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta04=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -95,23 +93,18 @@ org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.5.31=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-script-runtime:1.5.31=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugApiDependenciesMetadata,profileApiDependenciesMetadata,releaseApiDependenciesMetadata org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugApiDependenciesMetadata,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,lintClassPath,profileApiDependenciesMetadata,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseApiDependenciesMetadata,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugImplementationDependenciesMetadata,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,lintClassPath,profileCompileClasspath,profileImplementationDependenciesMetadata,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseImplementationDependenciesMetadata,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath org.ow2.asm:asm-tree:7.0=lintClassPath org.ow2.asm:asm-util:7.0=lintClassPath org.ow2.asm:asm:7.0=lintClassPath -empty=androidApis,androidTestApiDependenciesMetadata,androidTestCompileOnlyDependenciesMetadata,androidTestDebugApiDependenciesMetadata,androidTestDebugCompileOnlyDependenciesMetadata,androidTestDebugImplementationDependenciesMetadata,androidTestDebugIntransitiveDependenciesMetadata,androidTestDebugRuntimeOnlyDependenciesMetadata,androidTestImplementationDependenciesMetadata,androidTestIntransitiveDependenciesMetadata,androidTestProfileApiDependenciesMetadata,androidTestProfileCompileOnlyDependenciesMetadata,androidTestProfileImplementationDependenciesMetadata,androidTestProfileIntransitiveDependenciesMetadata,androidTestProfileRuntimeOnlyDependenciesMetadata,androidTestReleaseApiDependenciesMetadata,androidTestReleaseCompileOnlyDependenciesMetadata,androidTestReleaseImplementationDependenciesMetadata,androidTestReleaseIntransitiveDependenciesMetadata,androidTestReleaseRuntimeOnlyDependenciesMetadata,androidTestRuntimeOnlyDependenciesMetadata,androidTestUtil,apiDependenciesMetadata,compile,compileOnlyDependenciesMetadata,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAndroidTestApiDependenciesMetadata,debugAndroidTestCompileOnlyDependenciesMetadata,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestIntransitiveDependenciesMetadata,debugAndroidTestRuntimeClasspath,debugAndroidTestRuntimeOnlyDependenciesMetadata,debugAnnotationProcessorClasspath,debugCompile,debugCompileOnly,debugCompileOnlyDependenciesMetadata,debugIntransitiveDependenciesMetadata,debugReverseMetadataValues,debugRuntimeOnlyDependenciesMetadata,debugUnitTestAnnotationProcessorClasspath,debugUnitTestApiDependenciesMetadata,debugUnitTestCompileOnlyDependenciesMetadata,debugUnitTestImplementationDependenciesMetadata,debugUnitTestIntransitiveDependenciesMetadata,debugUnitTestRuntimeOnlyDependenciesMetadata,debugWearBundling,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathProfile,kotlinCompilerPluginClasspathProfileUnitTest,kotlinCompilerPluginClasspathRelease,kotlinCompilerPluginClasspathReleaseUnitTest,kotlinNativeCompilerPluginClasspath,lintChecks,lintPublish,profileAnnotationProcessorClasspath,profileCompile,profileCompileOnly,profileCompileOnlyDependenciesMetadata,profileIntransitiveDependenciesMetadata,profileReverseMetadataValues,profileRuntimeOnlyDependenciesMetadata,profileUnitTestAnnotationProcessorClasspath,profileUnitTestApiDependenciesMetadata,profileUnitTestCompileOnlyDependenciesMetadata,profileUnitTestImplementationDependenciesMetadata,profileUnitTestIntransitiveDependenciesMetadata,profileUnitTestRuntimeOnlyDependenciesMetadata,profileWearBundling,releaseAnnotationProcessorClasspath,releaseCompile,releaseCompileOnly,releaseCompileOnlyDependenciesMetadata,releaseIntransitiveDependenciesMetadata,releaseReverseMetadataValues,releaseRuntimeOnlyDependenciesMetadata,releaseUnitTestAnnotationProcessorClasspath,releaseUnitTestApiDependenciesMetadata,releaseUnitTestCompileOnlyDependenciesMetadata,releaseUnitTestImplementationDependenciesMetadata,releaseUnitTestIntransitiveDependenciesMetadata,releaseUnitTestRuntimeOnlyDependenciesMetadata,releaseWearBundling,runtimeOnlyDependenciesMetadata,testApiDependenciesMetadata,testCompile,testCompileOnlyDependenciesMetadata,testDebugApiDependenciesMetadata,testDebugCompileOnlyDependenciesMetadata,testDebugImplementationDependenciesMetadata,testDebugIntransitiveDependenciesMetadata,testDebugRuntimeOnlyDependenciesMetadata,testImplementationDependenciesMetadata,testIntransitiveDependenciesMetadata,testProfileApiDependenciesMetadata,testProfileCompileOnlyDependenciesMetadata,testProfileImplementationDependenciesMetadata,testProfileIntransitiveDependenciesMetadata,testProfileRuntimeOnlyDependenciesMetadata,testReleaseApiDependenciesMetadata,testReleaseCompileOnlyDependenciesMetadata,testReleaseImplementationDependenciesMetadata,testReleaseIntransitiveDependenciesMetadata,testReleaseRuntimeOnlyDependenciesMetadata,testRuntimeOnlyDependenciesMetadata +empty=androidApis,androidTestApiDependenciesMetadata,androidTestCompileOnlyDependenciesMetadata,androidTestDebugApiDependenciesMetadata,androidTestDebugCompileOnlyDependenciesMetadata,androidTestDebugImplementationDependenciesMetadata,androidTestDebugIntransitiveDependenciesMetadata,androidTestDebugRuntimeOnlyDependenciesMetadata,androidTestImplementationDependenciesMetadata,androidTestIntransitiveDependenciesMetadata,androidTestProfileApiDependenciesMetadata,androidTestProfileCompileOnlyDependenciesMetadata,androidTestProfileImplementationDependenciesMetadata,androidTestProfileIntransitiveDependenciesMetadata,androidTestProfileRuntimeOnlyDependenciesMetadata,androidTestReleaseApiDependenciesMetadata,androidTestReleaseCompileOnlyDependenciesMetadata,androidTestReleaseImplementationDependenciesMetadata,androidTestReleaseIntransitiveDependenciesMetadata,androidTestReleaseRuntimeOnlyDependenciesMetadata,androidTestRuntimeOnlyDependenciesMetadata,androidTestUtil,apiDependenciesMetadata,compile,compileOnlyDependenciesMetadata,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAndroidTestApiDependenciesMetadata,debugAndroidTestCompile,debugAndroidTestCompileOnlyDependenciesMetadata,debugAndroidTestImplementationDependenciesMetadata,debugAndroidTestIntransitiveDependenciesMetadata,debugAndroidTestRuntime,debugAndroidTestRuntimeClasspath,debugAndroidTestRuntimeOnlyDependenciesMetadata,debugAnnotationProcessorClasspath,debugCompile,debugCompileOnly,debugCompileOnlyDependenciesMetadata,debugIntransitiveDependenciesMetadata,debugReverseMetadataValues,debugRuntime,debugRuntimeOnlyDependenciesMetadata,debugUnitTestAnnotationProcessorClasspath,debugUnitTestApiDependenciesMetadata,debugUnitTestCompile,debugUnitTestCompileOnlyDependenciesMetadata,debugUnitTestImplementationDependenciesMetadata,debugUnitTestIntransitiveDependenciesMetadata,debugUnitTestRuntime,debugUnitTestRuntimeOnlyDependenciesMetadata,debugWearBundling,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathProfile,kotlinCompilerPluginClasspathProfileUnitTest,kotlinCompilerPluginClasspathRelease,kotlinCompilerPluginClasspathReleaseUnitTest,kotlinNativeCompilerPluginClasspath,lintChecks,lintPublish,profileAnnotationProcessorClasspath,profileCompile,profileCompileOnly,profileCompileOnlyDependenciesMetadata,profileIntransitiveDependenciesMetadata,profileReverseMetadataValues,profileRuntime,profileRuntimeOnlyDependenciesMetadata,profileUnitTestAnnotationProcessorClasspath,profileUnitTestApiDependenciesMetadata,profileUnitTestCompile,profileUnitTestCompileOnlyDependenciesMetadata,profileUnitTestImplementationDependenciesMetadata,profileUnitTestIntransitiveDependenciesMetadata,profileUnitTestRuntime,profileUnitTestRuntimeOnlyDependenciesMetadata,profileWearBundling,releaseAnnotationProcessorClasspath,releaseCompile,releaseCompileOnly,releaseCompileOnlyDependenciesMetadata,releaseIntransitiveDependenciesMetadata,releaseReverseMetadataValues,releaseRuntime,releaseRuntimeOnlyDependenciesMetadata,releaseUnitTestAnnotationProcessorClasspath,releaseUnitTestApiDependenciesMetadata,releaseUnitTestCompile,releaseUnitTestCompileOnlyDependenciesMetadata,releaseUnitTestImplementationDependenciesMetadata,releaseUnitTestIntransitiveDependenciesMetadata,releaseUnitTestRuntime,releaseUnitTestRuntimeOnlyDependenciesMetadata,releaseWearBundling,runtimeOnlyDependenciesMetadata,testApiDependenciesMetadata,testCompile,testCompileOnlyDependenciesMetadata,testDebugApiDependenciesMetadata,testDebugCompileOnlyDependenciesMetadata,testDebugImplementationDependenciesMetadata,testDebugIntransitiveDependenciesMetadata,testDebugRuntimeOnlyDependenciesMetadata,testImplementationDependenciesMetadata,testIntransitiveDependenciesMetadata,testProfileApiDependenciesMetadata,testProfileCompileOnlyDependenciesMetadata,testProfileImplementationDependenciesMetadata,testProfileIntransitiveDependenciesMetadata,testProfileRuntimeOnlyDependenciesMetadata,testReleaseApiDependenciesMetadata,testReleaseCompileOnlyDependenciesMetadata,testReleaseImplementationDependenciesMetadata,testReleaseIntransitiveDependenciesMetadata,testReleaseRuntimeOnlyDependenciesMetadata,testRuntimeOnlyDependenciesMetadata diff --git a/dev/manual_tests/ios/.gitignore b/dev/manual_tests/ios/.gitignore deleted file mode 100644 index 7a7f9873ad7dc..0000000000000 --- a/dev/manual_tests/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/dev/manual_tests/ios/Flutter/AppFrameworkInfo.plist b/dev/manual_tests/ios/Flutter/AppFrameworkInfo.plist index 8d4492f977adc..f2872cf474eee 100644 --- a/dev/manual_tests/ios/Flutter/AppFrameworkInfo.plist +++ b/dev/manual_tests/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable App CFBundleIdentifier diff --git a/dev/manual_tests/ios/Runner.xcodeproj/project.pbxproj b/dev/manual_tests/ios/Runner.xcodeproj/project.pbxproj index 438ad2e3e78fc..e53745fdcd1b7 100644 --- a/dev/manual_tests/ios/Runner.xcodeproj/project.pbxproj +++ b/dev/manual_tests/ios/Runner.xcodeproj/project.pbxproj @@ -90,6 +90,7 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -98,6 +99,13 @@ path = Runner; sourceTree = ""; }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -128,7 +136,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1300; - ORGANIZATIONNAME = ""; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; @@ -137,7 +145,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; + compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -290,11 +298,8 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.manualTests; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.manualTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -402,8 +407,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -418,11 +422,8 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.manualTests; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.manualTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -440,11 +441,8 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.manualTests; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.manualTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/dev/manual_tests/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/manual_tests/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d68d..0000000000000 --- a/dev/manual_tests/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/dev/manual_tests/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/dev/manual_tests/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5ea15f..0000000000000 --- a/dev/manual_tests/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/dev/manual_tests/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/dev/manual_tests/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a335208..3db53b6e1fb7f 100644 --- a/dev/manual_tests/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/dev/manual_tests/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -27,6 +27,8 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + - - + + + + - - - - IDEDidComputeMac32BitWarning - - - diff --git a/dev/manual_tests/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/dev/manual_tests/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5ea15f..0000000000000 --- a/dev/manual_tests/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/dev/manual_tests/ios/Runner/Info.plist b/dev/manual_tests/ios/Runner/Info.plist index f2184f0713bf1..80358121b6d97 100644 --- a/dev/manual_tests/ios/Runner/Info.plist +++ b/dev/manual_tests/ios/Runner/Info.plist @@ -4,8 +4,6 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Manual Tests CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -42,6 +40,6 @@ UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance - + diff --git a/dev/manual_tests/linux/.gitignore b/dev/manual_tests/linux/.gitignore deleted file mode 100644 index d3896c98444fb..0000000000000 --- a/dev/manual_tests/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/dev/manual_tests/linux/CMakeLists.txt b/dev/manual_tests/linux/CMakeLists.txt deleted file mode 100644 index 399b80bb8b65b..0000000000000 --- a/dev/manual_tests/linux/CMakeLists.txt +++ /dev/null @@ -1,116 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(runner LANGUAGES CXX) - -set(BINARY_NAME "manual_tests") -set(APPLICATION_ID "dev.flutter.manual_tests") - -cmake_policy(SET CMP0063 NEW) - -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Configure build options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") - -# Flutter library and tool build rules. -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Application build -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) -apply_standard_settings(${BINARY_NAME}) -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) -add_dependencies(${BINARY_NAME} flutter_assemble) -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/dev/manual_tests/linux/flutter/CMakeLists.txt b/dev/manual_tests/linux/flutter/CMakeLists.txt deleted file mode 100644 index 33fd5801e7134..0000000000000 --- a/dev/manual_tests/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,87 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/dev/manual_tests/linux/flutter/generated_plugin_registrant.cc b/dev/manual_tests/linux/flutter/generated_plugin_registrant.cc deleted file mode 100644 index e71a16d23d058..0000000000000 --- a/dev/manual_tests/linux/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,11 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - - -void fl_register_plugins(FlPluginRegistry* registry) { -} diff --git a/dev/manual_tests/linux/flutter/generated_plugin_registrant.h b/dev/manual_tests/linux/flutter/generated_plugin_registrant.h deleted file mode 100644 index e0f0a47bc08f3..0000000000000 --- a/dev/manual_tests/linux/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void fl_register_plugins(FlPluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/dev/manual_tests/linux/flutter/generated_plugins.cmake b/dev/manual_tests/linux/flutter/generated_plugins.cmake deleted file mode 100644 index 51436ae8c982a..0000000000000 --- a/dev/manual_tests/linux/flutter/generated_plugins.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) diff --git a/dev/manual_tests/linux/main.cc b/dev/manual_tests/linux/main.cc deleted file mode 100644 index 281a29e16b599..0000000000000 --- a/dev/manual_tests/linux/main.cc +++ /dev/null @@ -1,10 +0,0 @@ -// 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. - -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/dev/manual_tests/linux/my_application.cc b/dev/manual_tests/linux/my_application.cc deleted file mode 100644 index 9fed00806a3c7..0000000000000 --- a/dev/manual_tests/linux/my_application.cc +++ /dev/null @@ -1,108 +0,0 @@ -// 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. - -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "manual_tests"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "manual_tests"); - } - - gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); -} diff --git a/dev/manual_tests/linux/my_application.h b/dev/manual_tests/linux/my_application.h deleted file mode 100644 index 8c66ec485434d..0000000000000 --- a/dev/manual_tests/linux/my_application.h +++ /dev/null @@ -1,22 +0,0 @@ -// 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. - -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/dev/manual_tests/macos/.gitignore b/dev/manual_tests/macos/.gitignore index 746adbb6b9e14..d2fd3772308cc 100644 --- a/dev/manual_tests/macos/.gitignore +++ b/dev/manual_tests/macos/.gitignore @@ -3,5 +3,4 @@ **/Pods/ # Xcode-related -**/dgph **/xcuserdata/ diff --git a/dev/manual_tests/macos/Runner.xcodeproj/project.pbxproj b/dev/manual_tests/macos/Runner.xcodeproj/project.pbxproj index 1a4b4e8bace73..1bfdc6855539b 100644 --- a/dev/manual_tests/macos/Runner.xcodeproj/project.pbxproj +++ b/dev/manual_tests/macos/Runner.xcodeproj/project.pbxproj @@ -182,8 +182,8 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; - ORGANIZATIONNAME = ""; + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; @@ -268,7 +268,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/dev/manual_tests/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/dev/manual_tests/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index ec0c182ee84d8..ebd53039159fd 100644 --- a/dev/manual_tests/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/dev/manual_tests/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - + + + + - - - - diff --git a/dev/manual_tests/macos/Runner/Configs/AppInfo.xcconfig b/dev/manual_tests/macos/Runner/Configs/AppInfo.xcconfig index 736cdb41d1811..da7e6ed689820 100644 --- a/dev/manual_tests/macos/Runner/Configs/AppInfo.xcconfig +++ b/dev/manual_tests/macos/Runner/Configs/AppInfo.xcconfig @@ -8,7 +8,7 @@ PRODUCT_NAME = manual_tests // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.manualTests +PRODUCT_BUNDLE_IDENTIFIER = com.example.manualTests // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2021 dev.flutter. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2019 com.example. All rights reserved. diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index 87bf4d4453767..f77c730d1c9b5 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -9,7 +9,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -24,15 +23,15 @@ dev_dependencies: clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e37e +# PUBSPEC CHECKSUM: 921a diff --git a/dev/manual_tests/web/favicon.png b/dev/manual_tests/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/dev/manual_tests/web/icons/Icon-192.png b/dev/manual_tests/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 zcmZ`-2T+sGz6~)*FVZ`aW+(v>MIm&M-g^@e2u-B-DoB?qO+b1Tq<5uCCv>ESfRum& zp%X;f!~1{tzL__3=gjVJ=j=J>+nMj%ncXj1Q(b|Ckbw{Y0FWpt%4y%$uD=Z*c-x~o zE;IoE;xa#7Ll5nj-e4CuXB&G*IM~D21rCP$*xLXAK8rIMCSHuSu%bL&S3)8YI~vyp@KBu9Ph7R_pvKQ@xv>NQ`dZp(u{Z8K3yOB zn7-AR+d2JkW)KiGx0hosml;+eCXp6+w%@STjFY*CJ?udJ64&{BCbuebcuH;}(($@@ znNlgBA@ZXB)mcl9nbX#F!f_5Z=W>0kh|UVWnf!At4V*LQP%*gPdCXd6P@J4Td;!Ur z<2ZLmwr(NG`u#gDEMP19UcSzRTL@HsK+PnIXbVBT@oHm53DZr?~V(0{rsalAfwgo zEh=GviaqkF;}F_5-yA!1u3!gxaR&Mj)hLuj5Q-N-@Lra{%<4ONja8pycD90&>yMB` zchhd>0CsH`^|&TstH-8+R`CfoWqmTTF_0?zDOY`E`b)cVi!$4xA@oO;SyOjJyP^_j zx^@Gdf+w|FW@DMdOi8=4+LJl$#@R&&=UM`)G!y%6ZzQLoSL%*KE8IO0~&5XYR9 z&N)?goEiWA(YoRfT{06&D6Yuu@Qt&XVbuW@COb;>SP9~aRc+z`m`80pB2o%`#{xD@ zI3RAlukL5L>px6b?QW1Ac_0>ew%NM!XB2(H+1Y3AJC?C?O`GGs`331Nd4ZvG~bMo{lh~GeL zSL|tT*fF-HXxXYtfu5z+T5Mx9OdP7J4g%@oeC2FaWO1D{=NvL|DNZ}GO?O3`+H*SI z=grGv=7dL{+oY0eJFGO!Qe(e2F?CHW(i!!XkGo2tUvsQ)I9ev`H&=;`N%Z{L zO?vV%rDv$y(@1Yj@xfr7Kzr<~0{^T8wM80xf7IGQF_S-2c0)0D6b0~yD7BsCy+(zL z#N~%&e4iAwi4F$&dI7x6cE|B{f@lY5epaDh=2-(4N05VO~A zQT3hanGy_&p+7Fb^I#ewGsjyCEUmSCaP6JDB*=_()FgQ(-pZ28-{qx~2foO4%pM9e z*_63RT8XjgiaWY|*xydf;8MKLd{HnfZ2kM%iq}fstImB-K6A79B~YoPVa@tYN@T_$ zea+9)<%?=Fl!kd(Y!G(-o}ko28hg2!MR-o5BEa_72uj7Mrc&{lRh3u2%Y=Xk9^-qa zBPWaD=2qcuJ&@Tf6ue&)4_V*45=zWk@Z}Q?f5)*z)-+E|-yC4fs5CE6L_PH3=zI8p z*Z3!it{1e5_^(sF*v=0{`U9C741&lub89gdhKp|Y8CeC{_{wYK-LSbp{h)b~9^j!s z7e?Y{Z3pZv0J)(VL=g>l;<}xk=T*O5YR|hg0eg4u98f2IrA-MY+StQIuK-(*J6TRR z|IM(%uI~?`wsfyO6Tgmsy1b3a)j6M&-jgUjVg+mP*oTKdHg?5E`!r`7AE_#?Fc)&a z08KCq>Gc=ne{PCbRvs6gVW|tKdcE1#7C4e`M|j$C5EYZ~Y=jUtc zj`+?p4ba3uy7><7wIokM79jPza``{Lx0)zGWg;FW1^NKY+GpEi=rHJ+fVRGfXO zPHV52k?jxei_!YYAw1HIz}y8ZMwdZqU%ESwMn7~t zdI5%B;U7RF=jzRz^NuY9nM)&<%M>x>0(e$GpU9th%rHiZsIT>_qp%V~ILlyt^V`=d z!1+DX@ah?RnB$X!0xpTA0}lN@9V-ePx>wQ?-xrJr^qDlw?#O(RsXeAvM%}rg0NT#t z!CsT;-vB=B87ShG`GwO;OEbeL;a}LIu=&@9cb~Rsx(ZPNQ!NT7H{@j0e(DiLea>QD zPmpe90gEKHEZ8oQ@6%E7k-Ptn#z)b9NbD@_GTxEhbS+}Bb74WUaRy{w;E|MgDAvHw zL)ycgM7mB?XVh^OzbC?LKFMotw3r@i&VdUV%^Efdib)3@soX%vWCbnOyt@Y4swW925@bt45y0HY3YI~BnnzZYrinFy;L?2D3BAL`UQ zEj))+f>H7~g8*VuWQ83EtGcx`hun$QvuurSMg3l4IP8Fe`#C|N6mbYJ=n;+}EQm;< z!!N=5j1aAr_uEnnzrEV%_E|JpTb#1p1*}5!Ce!R@d$EtMR~%9# zd;h8=QGT)KMW2IKu_fA_>p_und#-;Q)p%%l0XZOXQicfX8M~7?8}@U^ihu;mizj)t zgV7wk%n-UOb z#!P5q?Ex+*Kx@*p`o$q8FWL*E^$&1*!gpv?Za$YO~{BHeGY*5%4HXUKa_A~~^d z=E*gf6&+LFF^`j4$T~dR)%{I)T?>@Ma?D!gi9I^HqvjPc3-v~=qpX1Mne@*rzT&Xw zQ9DXsSV@PqpEJO-g4A&L{F&;K6W60D!_vs?Vx!?w27XbEuJJP&);)^+VF1nHqHBWu z^>kI$M9yfOY8~|hZ9WB!q-9u&mKhEcRjlf2nm_@s;0D#c|@ED7NZE% zzR;>P5B{o4fzlfsn3CkBK&`OSb-YNrqx@N#4CK!>bQ(V(D#9|l!e9(%sz~PYk@8zt zPN9oK78&-IL_F zhsk1$6p;GqFbtB^ZHHP+cjMvA0(LqlskbdYE_rda>gvQLTiqOQ1~*7lg%z*&p`Ry& zRcG^DbbPj_jOKHTr8uk^15Boj6>hA2S-QY(W-6!FIq8h$<>MI>PYYRenQDBamO#Fv zAH5&ImqKBDn0v5kb|8i0wFhUBJTpT!rB-`zK)^SNnRmLraZcPYK7b{I@+}wXVdW-{Ps17qdRA3JatEd?rPV z4@}(DAMf5EqXCr4-B+~H1P#;t@O}B)tIJ(W6$LrK&0plTmnPpb1TKn3?f?Kk``?D+ zQ!MFqOX7JbsXfQrz`-M@hq7xlfNz;_B{^wbpG8des56x(Q)H)5eLeDwCrVR}hzr~= zM{yXR6IM?kXxauLza#@#u?Y|o;904HCqF<8yT~~c-xyRc0-vxofnxG^(x%>bj5r}N zyFT+xnn-?B`ohA>{+ZZQem=*Xpqz{=j8i2TAC#x-m;;mo{{sLB_z(UoAqD=A#*juZ zCv=J~i*O8;F}A^Wf#+zx;~3B{57xtoxC&j^ie^?**T`WT2OPRtC`xj~+3Kprn=rVM zVJ|h5ux%S{dO}!mq93}P+h36mZ5aZg1-?vhL$ke1d52qIiXSE(llCr5i=QUS?LIjc zV$4q=-)aaR4wsrQv}^shL5u%6;`uiSEs<1nG^?$kl$^6DL z43CjY`M*p}ew}}3rXc7Xck@k41jx}c;NgEIhKZ*jsBRZUP-x2cm;F1<5$jefl|ppO zmZd%%?gMJ^g9=RZ^#8Mf5aWNVhjAS^|DQO+q$)oeob_&ZLFL(zur$)); zU19yRm)z<4&4-M}7!9+^Wl}Uk?`S$#V2%pQ*SIH5KI-mn%i;Z7-)m$mN9CnI$G7?# zo`zVrUwoSL&_dJ92YhX5TKqaRkfPgC4=Q&=K+;_aDs&OU0&{WFH}kKX6uNQC6%oUH z2DZa1s3%Vtk|bglbxep-w)PbFG!J17`<$g8lVhqD2w;Z0zGsh-r zxZ13G$G<48leNqR!DCVt9)@}(zMI5w6Wo=N zpP1*3DI;~h2WDWgcKn*f!+ORD)f$DZFwgKBafEZmeXQMAsq9sxP9A)7zOYnkHT9JU zRA`umgmP9d6=PHmFIgx=0$(sjb>+0CHG)K@cPG{IxaJ&Ueo8)0RWgV9+gO7+Bl1(F z7!BslJ2MP*PWJ;x)QXbR$6jEr5q3 z(3}F@YO_P1NyTdEXRLU6fp?9V2-S=E+YaeLL{Y)W%6`k7$(EW8EZSA*(+;e5@jgD^I zaJQ2|oCM1n!A&-8`;#RDcZyk*+RPkn_r8?Ak@agHiSp*qFNX)&i21HE?yuZ;-C<3C zwJGd1lx5UzViP7sZJ&|LqH*mryb}y|%AOw+v)yc`qM)03qyyrqhX?ub`Cjwx2PrR! z)_z>5*!*$x1=Qa-0uE7jy0z`>|Ni#X+uV|%_81F7)b+nf%iz=`fF4g5UfHS_?PHbr zB;0$bK@=di?f`dS(j{l3-tSCfp~zUuva+=EWxJcRfp(<$@vd(GigM&~vaYZ0c#BTs z3ijkxMl=vw5AS&DcXQ%eeKt!uKvh2l3W?&3=dBHU=Gz?O!40S&&~ei2vg**c$o;i89~6DVns zG>9a*`k5)NI9|?W!@9>rzJ;9EJ=YlJTx1r1BA?H`LWijk(rTax9(OAu;q4_wTj-yj z1%W4GW&K4T=uEGb+E!>W0SD_C0RR91 diff --git a/dev/manual_tests/web/icons/Icon-512.png b/dev/manual_tests/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 zcmd5=2T+s!lYZ%-(h(2@5fr2dC?F^$C=i-}R6$UX8af(!je;W5yC_|HmujSgN*6?W z3knF*TL1$|?oD*=zPbBVex*RUIKsL<(&Rj9%^UD2IK3W?2j>D?eWQgvS-HLymHo9%~|N2Q{~j za?*X-{b9JRowv_*Mh|;*-kPFn>PI;r<#kFaxFqbn?aq|PduQg=2Q;~Qc}#z)_T%x9 zE|0!a70`58wjREmAH38H1)#gof)U3g9FZ^ zF7&-0^Hy{4XHWLoC*hOG(dg~2g6&?-wqcpf{ z&3=o8vw7lMi22jCG9RQbv8H}`+}9^zSk`nlR8?Z&G2dlDy$4#+WOlg;VHqzuE=fM@ z?OI6HEJH4&tA?FVG}9>jAnq_^tlw8NbjNhfqk2rQr?h(F&WiKy03Sn=-;ZJRh~JrD zbt)zLbnabttEZ>zUiu`N*u4sfQaLE8-WDn@tHp50uD(^r-}UsUUu)`!Rl1PozAc!a z?uj|2QDQ%oV-jxUJmJycySBINSKdX{kDYRS=+`HgR2GO19fg&lZKyBFbbXhQV~v~L za^U944F1_GtuFXtvDdDNDvp<`fqy);>Vw=ncy!NB85Tw{&sT5&Ox%-p%8fTS;OzlRBwErvO+ROe?{%q-Zge=%Up|D4L#>4K@Ke=x%?*^_^P*KD zgXueMiS63!sEw@fNLB-i^F|@Oib+S4bcy{eu&e}Xvb^(mA!=U=Xr3||IpV~3K zQWzEsUeX_qBe6fky#M zzOJm5b+l;~>=sdp%i}}0h zO?B?i*W;Ndn02Y0GUUPxERG`3Bjtj!NroLoYtyVdLtl?SE*CYpf4|_${ku2s`*_)k zN=a}V8_2R5QANlxsq!1BkT6$4>9=-Ix4As@FSS;1q^#TXPrBsw>hJ}$jZ{kUHoP+H zvoYiR39gX}2OHIBYCa~6ERRPJ#V}RIIZakUmuIoLF*{sO8rAUEB9|+A#C|@kw5>u0 zBd=F!4I)Be8ycH*)X1-VPiZ+Ts8_GB;YW&ZFFUo|Sw|x~ZajLsp+_3gv((Q#N>?Jz zFBf`~p_#^${zhPIIJY~yo!7$-xi2LK%3&RkFg}Ax)3+dFCjGgKv^1;lUzQlPo^E{K zmCnrwJ)NuSaJEmueEPO@(_6h3f5mFffhkU9r8A8(JC5eOkux{gPmx_$Uv&|hyj)gN zd>JP8l2U&81@1Hc>#*su2xd{)T`Yw< zN$dSLUN}dfx)Fu`NcY}TuZ)SdviT{JHaiYgP4~@`x{&h*Hd>c3K_To9BnQi@;tuoL z%PYQo&{|IsM)_>BrF1oB~+`2_uZQ48z9!)mtUR zdfKE+b*w8cPu;F6RYJiYyV;PRBbThqHBEu_(U{(gGtjM}Zi$pL8Whx}<JwE3RM0F8x7%!!s)UJVq|TVd#hf1zVLya$;mYp(^oZQ2>=ZXU1c$}f zm|7kfk>=4KoQoQ!2&SOW5|JP1)%#55C$M(u4%SP~tHa&M+=;YsW=v(Old9L3(j)`u z2?#fK&1vtS?G6aOt@E`gZ9*qCmyvc>Ma@Q8^I4y~f3gs7*d=ATlP>1S zyF=k&6p2;7dn^8?+!wZO5r~B+;@KXFEn^&C=6ma1J7Au6y29iMIxd7#iW%=iUzq&C=$aPLa^Q zncia$@TIy6UT@69=nbty5epP>*fVW@5qbUcb2~Gg75dNd{COFLdiz3}kODn^U*=@E z0*$7u7Rl2u)=%fk4m8EK1ctR!6%Ve`e!O20L$0LkM#f+)n9h^dn{n`T*^~d+l*Qlx z$;JC0P9+en2Wlxjwq#z^a6pdnD6fJM!GV7_%8%c)kc5LZs_G^qvw)&J#6WSp< zmsd~1-(GrgjC56Pdf6#!dt^y8Rg}!#UXf)W%~PeU+kU`FeSZHk)%sFv++#Dujk-~m zFHvVJC}UBn2jN& zs!@nZ?e(iyZPNo`p1i#~wsv9l@#Z|ag3JR>0#u1iW9M1RK1iF6-RbJ4KYg?B`dET9 zyR~DjZ>%_vWYm*Z9_+^~hJ_|SNTzBKx=U0l9 z9x(J96b{`R)UVQ$I`wTJ@$_}`)_DyUNOso6=WOmQKI1e`oyYy1C&%AQU<0-`(ow)1 zT}gYdwWdm4wW6|K)LcfMe&psE0XGhMy&xS`@vLi|1#Za{D6l@#D!?nW87wcscUZgELT{Cz**^;Zb~7 z(~WFRO`~!WvyZAW-8v!6n&j*PLm9NlN}BuUN}@E^TX*4Or#dMMF?V9KBeLSiLO4?B zcE3WNIa-H{ThrlCoN=XjOGk1dT=xwwrmt<1a)mrRzg{35`@C!T?&_;Q4Ce=5=>z^*zE_c(0*vWo2_#TD<2)pLXV$FlwP}Ik74IdDQU@yhkCr5h zn5aa>B7PWy5NQ!vf7@p_qtC*{dZ8zLS;JetPkHi>IvPjtJ#ThGQD|Lq#@vE2xdl%`x4A8xOln}BiQ92Po zW;0%A?I5CQ_O`@Ad=`2BLPPbBuPUp@Hb%a_OOI}y{Rwa<#h z5^6M}s7VzE)2&I*33pA>e71d78QpF>sNK;?lj^Kl#wU7G++`N_oL4QPd-iPqBhhs| z(uVM}$ItF-onXuuXO}o$t)emBO3Hjfyil@*+GF;9j?`&67GBM;TGkLHi>@)rkS4Nj zAEk;u)`jc4C$qN6WV2dVd#q}2X6nKt&X*}I@jP%Srs%%DS92lpDY^K*Sx4`l;aql$ zt*-V{U&$DM>pdO?%jt$t=vg5|p+Rw?SPaLW zB6nvZ69$ne4Z(s$3=Rf&RX8L9PWMV*S0@R zuIk&ba#s6sxVZ51^4Kon46X^9`?DC9mEhWB3f+o4#2EXFqy0(UTc>GU| zGCJmI|Dn-dX#7|_6(fT)>&YQ0H&&JX3cTvAq(a@ydM4>5Njnuere{J8p;3?1az60* z$1E7Yyxt^ytULeokgDnRVKQw9vzHg1>X@@jM$n$HBlveIrKP5-GJq%iWH#odVwV6cF^kKX(@#%%uQVb>#T6L^mC@)%SMd4DF? zVky!~ge27>cpUP1Vi}Z32lbLV+CQy+T5Wdmva6Fg^lKb!zrg|HPU=5Qu}k;4GVH+x z%;&pN1LOce0w@9i1Mo-Y|7|z}fbch@BPp2{&R-5{GLoeu8@limQmFF zaJRR|^;kW_nw~0V^ zfTnR!Ni*;-%oSHG1yItARs~uxra|O?YJxBzLjpeE-=~TO3Dn`JL5Gz;F~O1u3|FE- zvK2Vve`ylc`a}G`gpHg58Cqc9fMoy1L}7x7T>%~b&irrNMo?np3`q;d3d;zTK>nrK zOjPS{@&74-fA7j)8uT9~*g23uGnxwIVj9HorzUX#s0pcp2?GH6i}~+kv9fWChtPa_ z@T3m+$0pbjdQw7jcnHn;Pi85hk_u2-1^}c)LNvjdam8K-XJ+KgKQ%!?2n_!#{$H|| zLO=%;hRo6EDmnOBKCL9Cg~ETU##@u^W_5joZ%Et%X_n##%JDOcsO=0VL|Lkk!VdRJ z^|~2pB@PUspT?NOeO?=0Vb+fAGc!j%Ufn-cB`s2A~W{Zj{`wqWq_-w0wr@6VrM zbzni@8c>WS!7c&|ZR$cQ;`niRw{4kG#e z70e!uX8VmP23SuJ*)#(&R=;SxGAvq|&>geL&!5Z7@0Z(No*W561n#u$Uc`f9pD70# z=sKOSK|bF~#khTTn)B28h^a1{;>EaRnHj~>i=Fnr3+Fa4 z`^+O5_itS#7kPd20rq66_wH`%?HNzWk@XFK0n;Z@Cx{kx==2L22zWH$Yg?7 zvDj|u{{+NR3JvUH({;b*$b(U5U z7(lF!1bz2%06+|-v(D?2KgwNw7( zJB#Tz+ZRi&U$i?f34m7>uTzO#+E5cbaiQ&L}UxyOQq~afbNB4EI{E04ZWg53w0A{O%qo=lF8d zf~ktGvIgf-a~zQoWf>loF7pOodrd0a2|BzwwPDV}ShauTK8*fmF6NRbO>Iw9zZU}u zw8Ya}?seBnEGQDmH#XpUUkj}N49tP<2jYwTFp!P+&Fd(%Z#yo80|5@zN(D{_pNow*&4%ql zW~&yp@scb-+Qj-EmErY+Tu=dUmf@*BoXY2&oKT8U?8?s1d}4a`Aq>7SV800m$FE~? zjmz(LY+Xx9sDX$;vU`xgw*jLw7dWOnWWCO8o|;}f>cu0Q&`0I{YudMn;P;L3R-uz# zfns_mZED_IakFBPP2r_S8XM$X)@O-xVKi4`7373Jkd5{2$M#%cRhWer3M(vr{S6>h zj{givZJ3(`yFL@``(afn&~iNx@B1|-qfYiZu?-_&Z8+R~v`d6R-}EX9IVXWO-!hL5 z*k6T#^2zAXdardU3Ao~I)4DGdAv2bx{4nOK`20rJo>rmk3S2ZDu}))8Z1m}CKigf0 z3L`3Y`{huj`xj9@`$xTZzZc3je?n^yG<8sw$`Y%}9mUsjUR%T!?k^(q)6FH6Af^b6 zlPg~IEwg0y;`t9y;#D+uz!oE4VP&Je!<#q*F?m5L5?J3i@!0J6q#eu z!RRU`-)HeqGi_UJZ(n~|PSNsv+Wgl{P-TvaUQ9j?ZCtvb^37U$sFpBrkT{7Jpd?HpIvj2!}RIq zH{9~+gErN2+}J`>Jvng2hwM`=PLNkc7pkjblKW|+Fk9rc)G1R>Ww>RC=r-|!m-u7( zc(a$9NG}w#PjWNMS~)o=i~WA&4L(YIW25@AL9+H9!?3Y}sv#MOdY{bb9j>p`{?O(P zIvb`n?_(gP2w3P#&91JX*md+bBEr%xUHMVqfB;(f?OPtMnAZ#rm5q5mh;a2f_si2_ z3oXWB?{NF(JtkAn6F(O{z@b76OIqMC$&oJ_&S|YbFJ*)3qVX_uNf5b8(!vGX19hsG z(OP>RmZp29KH9Ge2kKjKigUmOe^K_!UXP`von)PR8Qz$%=EmOB9xS(ZxE_tnyzo}7 z=6~$~9k0M~v}`w={AeqF?_)9q{m8K#6M{a&(;u;O41j)I$^T?lx5(zlebpY@NT&#N zR+1bB)-1-xj}R8uwqwf=iP1GbxBjneCC%UrSdSxK1vM^i9;bUkS#iRZw2H>rS<2<$ zNT3|sDH>{tXb=zq7XZi*K?#Zsa1h1{h5!Tq_YbKFm_*=A5-<~j63he;4`77!|LBlo zR^~tR3yxcU=gDFbshyF6>o0bdp$qmHS7D}m3;^QZq9kBBU|9$N-~oU?G5;jyFR7>z hN`IR97YZXIo@y!QgFWddJ3|0`sjFx!m))><{BI=FK%f8s diff --git a/dev/manual_tests/web/icons/Icon-maskable-192.png b/dev/manual_tests/web/icons/Icon-maskable-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 zcmZ`-2T+sGz6~)*FVZ`aW+(v>MIm&M-g^@e2u-B-DoB?qO+b1Tq<5uCCv>ESfRum& zp%X;f!~1{tzL__3=gjVJ=j=J>+nMj%ncXj1Q(b|Ckbw{Y0FWpt%4y%$uD=Z*c-x~o zE;IoE;xa#7Ll5nj-e4CuXB&G*IM~D21rCP$*xLXAK8rIMCSHuSu%bL&S3)8YI~vyp@KBu9Ph7R_pvKQ@xv>NQ`dZp(u{Z8K3yOB zn7-AR+d2JkW)KiGx0hosml;+eCXp6+w%@STjFY*CJ?udJ64&{BCbuebcuH;}(($@@ znNlgBA@ZXB)mcl9nbX#F!f_5Z=W>0kh|UVWnf!At4V*LQP%*gPdCXd6P@J4Td;!Ur z<2ZLmwr(NG`u#gDEMP19UcSzRTL@HsK+PnIXbVBT@oHm53DZr?~V(0{rsalAfwgo zEh=GviaqkF;}F_5-yA!1u3!gxaR&Mj)hLuj5Q-N-@Lra{%<4ONja8pycD90&>yMB` zchhd>0CsH`^|&TstH-8+R`CfoWqmTTF_0?zDOY`E`b)cVi!$4xA@oO;SyOjJyP^_j zx^@Gdf+w|FW@DMdOi8=4+LJl$#@R&&=UM`)G!y%6ZzQLoSL%*KE8IO0~&5XYR9 z&N)?goEiWA(YoRfT{06&D6Yuu@Qt&XVbuW@COb;>SP9~aRc+z`m`80pB2o%`#{xD@ zI3RAlukL5L>px6b?QW1Ac_0>ew%NM!XB2(H+1Y3AJC?C?O`GGs`331Nd4ZvG~bMo{lh~GeL zSL|tT*fF-HXxXYtfu5z+T5Mx9OdP7J4g%@oeC2FaWO1D{=NvL|DNZ}GO?O3`+H*SI z=grGv=7dL{+oY0eJFGO!Qe(e2F?CHW(i!!XkGo2tUvsQ)I9ev`H&=;`N%Z{L zO?vV%rDv$y(@1Yj@xfr7Kzr<~0{^T8wM80xf7IGQF_S-2c0)0D6b0~yD7BsCy+(zL z#N~%&e4iAwi4F$&dI7x6cE|B{f@lY5epaDh=2-(4N05VO~A zQT3hanGy_&p+7Fb^I#ewGsjyCEUmSCaP6JDB*=_()FgQ(-pZ28-{qx~2foO4%pM9e z*_63RT8XjgiaWY|*xydf;8MKLd{HnfZ2kM%iq}fstImB-K6A79B~YoPVa@tYN@T_$ zea+9)<%?=Fl!kd(Y!G(-o}ko28hg2!MR-o5BEa_72uj7Mrc&{lRh3u2%Y=Xk9^-qa zBPWaD=2qcuJ&@Tf6ue&)4_V*45=zWk@Z}Q?f5)*z)-+E|-yC4fs5CE6L_PH3=zI8p z*Z3!it{1e5_^(sF*v=0{`U9C741&lub89gdhKp|Y8CeC{_{wYK-LSbp{h)b~9^j!s z7e?Y{Z3pZv0J)(VL=g>l;<}xk=T*O5YR|hg0eg4u98f2IrA-MY+StQIuK-(*J6TRR z|IM(%uI~?`wsfyO6Tgmsy1b3a)j6M&-jgUjVg+mP*oTKdHg?5E`!r`7AE_#?Fc)&a z08KCq>Gc=ne{PCbRvs6gVW|tKdcE1#7C4e`M|j$C5EYZ~Y=jUtc zj`+?p4ba3uy7><7wIokM79jPza``{Lx0)zGWg;FW1^NKY+GpEi=rHJ+fVRGfXO zPHV52k?jxei_!YYAw1HIz}y8ZMwdZqU%ESwMn7~t zdI5%B;U7RF=jzRz^NuY9nM)&<%M>x>0(e$GpU9th%rHiZsIT>_qp%V~ILlyt^V`=d z!1+DX@ah?RnB$X!0xpTA0}lN@9V-ePx>wQ?-xrJr^qDlw?#O(RsXeAvM%}rg0NT#t z!CsT;-vB=B87ShG`GwO;OEbeL;a}LIu=&@9cb~Rsx(ZPNQ!NT7H{@j0e(DiLea>QD zPmpe90gEKHEZ8oQ@6%E7k-Ptn#z)b9NbD@_GTxEhbS+}Bb74WUaRy{w;E|MgDAvHw zL)ycgM7mB?XVh^OzbC?LKFMotw3r@i&VdUV%^Efdib)3@soX%vWCbnOyt@Y4swW925@bt45y0HY3YI~BnnzZYrinFy;L?2D3BAL`UQ zEj))+f>H7~g8*VuWQ83EtGcx`hun$QvuurSMg3l4IP8Fe`#C|N6mbYJ=n;+}EQm;< z!!N=5j1aAr_uEnnzrEV%_E|JpTb#1p1*}5!Ce!R@d$EtMR~%9# zd;h8=QGT)KMW2IKu_fA_>p_und#-;Q)p%%l0XZOXQicfX8M~7?8}@U^ihu;mizj)t zgV7wk%n-UOb z#!P5q?Ex+*Kx@*p`o$q8FWL*E^$&1*!gpv?Za$YO~{BHeGY*5%4HXUKa_A~~^d z=E*gf6&+LFF^`j4$T~dR)%{I)T?>@Ma?D!gi9I^HqvjPc3-v~=qpX1Mne@*rzT&Xw zQ9DXsSV@PqpEJO-g4A&L{F&;K6W60D!_vs?Vx!?w27XbEuJJP&);)^+VF1nHqHBWu z^>kI$M9yfOY8~|hZ9WB!q-9u&mKhEcRjlf2nm_@s;0D#c|@ED7NZE% zzR;>P5B{o4fzlfsn3CkBK&`OSb-YNrqx@N#4CK!>bQ(V(D#9|l!e9(%sz~PYk@8zt zPN9oK78&-IL_F zhsk1$6p;GqFbtB^ZHHP+cjMvA0(LqlskbdYE_rda>gvQLTiqOQ1~*7lg%z*&p`Ry& zRcG^DbbPj_jOKHTr8uk^15Boj6>hA2S-QY(W-6!FIq8h$<>MI>PYYRenQDBamO#Fv zAH5&ImqKBDn0v5kb|8i0wFhUBJTpT!rB-`zK)^SNnRmLraZcPYK7b{I@+}wXVdW-{Ps17qdRA3JatEd?rPV z4@}(DAMf5EqXCr4-B+~H1P#;t@O}B)tIJ(W6$LrK&0plTmnPpb1TKn3?f?Kk``?D+ zQ!MFqOX7JbsXfQrz`-M@hq7xlfNz;_B{^wbpG8des56x(Q)H)5eLeDwCrVR}hzr~= zM{yXR6IM?kXxauLza#@#u?Y|o;904HCqF<8yT~~c-xyRc0-vxofnxG^(x%>bj5r}N zyFT+xnn-?B`ohA>{+ZZQem=*Xpqz{=j8i2TAC#x-m;;mo{{sLB_z(UoAqD=A#*juZ zCv=J~i*O8;F}A^Wf#+zx;~3B{57xtoxC&j^ie^?**T`WT2OPRtC`xj~+3Kprn=rVM zVJ|h5ux%S{dO}!mq93}P+h36mZ5aZg1-?vhL$ke1d52qIiXSE(llCr5i=QUS?LIjc zV$4q=-)aaR4wsrQv}^shL5u%6;`uiSEs<1nG^?$kl$^6DL z43CjY`M*p}ew}}3rXc7Xck@k41jx}c;NgEIhKZ*jsBRZUP-x2cm;F1<5$jefl|ppO zmZd%%?gMJ^g9=RZ^#8Mf5aWNVhjAS^|DQO+q$)oeob_&ZLFL(zur$)); zU19yRm)z<4&4-M}7!9+^Wl}Uk?`S$#V2%pQ*SIH5KI-mn%i;Z7-)m$mN9CnI$G7?# zo`zVrUwoSL&_dJ92YhX5TKqaRkfPgC4=Q&=K+;_aDs&OU0&{WFH}kKX6uNQC6%oUH z2DZa1s3%Vtk|bglbxep-w)PbFG!J17`<$g8lVhqD2w;Z0zGsh-r zxZ13G$G<48leNqR!DCVt9)@}(zMI5w6Wo=N zpP1*3DI;~h2WDWgcKn*f!+ORD)f$DZFwgKBafEZmeXQMAsq9sxP9A)7zOYnkHT9JU zRA`umgmP9d6=PHmFIgx=0$(sjb>+0CHG)K@cPG{IxaJ&Ueo8)0RWgV9+gO7+Bl1(F z7!BslJ2MP*PWJ;x)QXbR$6jEr5q3 z(3}F@YO_P1NyTdEXRLU6fp?9V2-S=E+YaeLL{Y)W%6`k7$(EW8EZSA*(+;e5@jgD^I zaJQ2|oCM1n!A&-8`;#RDcZyk*+RPkn_r8?Ak@agHiSp*qFNX)&i21HE?yuZ;-C<3C zwJGd1lx5UzViP7sZJ&|LqH*mryb}y|%AOw+v)yc`qM)03qyyrqhX?ub`Cjwx2PrR! z)_z>5*!*$x1=Qa-0uE7jy0z`>|Ni#X+uV|%_81F7)b+nf%iz=`fF4g5UfHS_?PHbr zB;0$bK@=di?f`dS(j{l3-tSCfp~zUuva+=EWxJcRfp(<$@vd(GigM&~vaYZ0c#BTs z3ijkxMl=vw5AS&DcXQ%eeKt!uKvh2l3W?&3=dBHU=Gz?O!40S&&~ei2vg**c$o;i89~6DVns zG>9a*`k5)NI9|?W!@9>rzJ;9EJ=YlJTx1r1BA?H`LWijk(rTax9(OAu;q4_wTj-yj z1%W4GW&K4T=uEGb+E!>W0SD_C0RR91 diff --git a/dev/manual_tests/web/icons/Icon-maskable-512.png b/dev/manual_tests/web/icons/Icon-maskable-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 zcmd5=2T+s!lYZ%-(h(2@5fr2dC?F^$C=i-}R6$UX8af(!je;W5yC_|HmujSgN*6?W z3knF*TL1$|?oD*=zPbBVex*RUIKsL<(&Rj9%^UD2IK3W?2j>D?eWQgvS-HLymHo9%~|N2Q{~j za?*X-{b9JRowv_*Mh|;*-kPFn>PI;r<#kFaxFqbn?aq|PduQg=2Q;~Qc}#z)_T%x9 zE|0!a70`58wjREmAH38H1)#gof)U3g9FZ^ zF7&-0^Hy{4XHWLoC*hOG(dg~2g6&?-wqcpf{ z&3=o8vw7lMi22jCG9RQbv8H}`+}9^zSk`nlR8?Z&G2dlDy$4#+WOlg;VHqzuE=fM@ z?OI6HEJH4&tA?FVG}9>jAnq_^tlw8NbjNhfqk2rQr?h(F&WiKy03Sn=-;ZJRh~JrD zbt)zLbnabttEZ>zUiu`N*u4sfQaLE8-WDn@tHp50uD(^r-}UsUUu)`!Rl1PozAc!a z?uj|2QDQ%oV-jxUJmJycySBINSKdX{kDYRS=+`HgR2GO19fg&lZKyBFbbXhQV~v~L za^U944F1_GtuFXtvDdDNDvp<`fqy);>Vw=ncy!NB85Tw{&sT5&Ox%-p%8fTS;OzlRBwErvO+ROe?{%q-Zge=%Up|D4L#>4K@Ke=x%?*^_^P*KD zgXueMiS63!sEw@fNLB-i^F|@Oib+S4bcy{eu&e}Xvb^(mA!=U=Xr3||IpV~3K zQWzEsUeX_qBe6fky#M zzOJm5b+l;~>=sdp%i}}0h zO?B?i*W;Ndn02Y0GUUPxERG`3Bjtj!NroLoYtyVdLtl?SE*CYpf4|_${ku2s`*_)k zN=a}V8_2R5QANlxsq!1BkT6$4>9=-Ix4As@FSS;1q^#TXPrBsw>hJ}$jZ{kUHoP+H zvoYiR39gX}2OHIBYCa~6ERRPJ#V}RIIZakUmuIoLF*{sO8rAUEB9|+A#C|@kw5>u0 zBd=F!4I)Be8ycH*)X1-VPiZ+Ts8_GB;YW&ZFFUo|Sw|x~ZajLsp+_3gv((Q#N>?Jz zFBf`~p_#^${zhPIIJY~yo!7$-xi2LK%3&RkFg}Ax)3+dFCjGgKv^1;lUzQlPo^E{K zmCnrwJ)NuSaJEmueEPO@(_6h3f5mFffhkU9r8A8(JC5eOkux{gPmx_$Uv&|hyj)gN zd>JP8l2U&81@1Hc>#*su2xd{)T`Yw< zN$dSLUN}dfx)Fu`NcY}TuZ)SdviT{JHaiYgP4~@`x{&h*Hd>c3K_To9BnQi@;tuoL z%PYQo&{|IsM)_>BrF1oB~+`2_uZQ48z9!)mtUR zdfKE+b*w8cPu;F6RYJiYyV;PRBbThqHBEu_(U{(gGtjM}Zi$pL8Whx}<JwE3RM0F8x7%!!s)UJVq|TVd#hf1zVLya$;mYp(^oZQ2>=ZXU1c$}f zm|7kfk>=4KoQoQ!2&SOW5|JP1)%#55C$M(u4%SP~tHa&M+=;YsW=v(Old9L3(j)`u z2?#fK&1vtS?G6aOt@E`gZ9*qCmyvc>Ma@Q8^I4y~f3gs7*d=ATlP>1S zyF=k&6p2;7dn^8?+!wZO5r~B+;@KXFEn^&C=6ma1J7Au6y29iMIxd7#iW%=iUzq&C=$aPLa^Q zncia$@TIy6UT@69=nbty5epP>*fVW@5qbUcb2~Gg75dNd{COFLdiz3}kODn^U*=@E z0*$7u7Rl2u)=%fk4m8EK1ctR!6%Ve`e!O20L$0LkM#f+)n9h^dn{n`T*^~d+l*Qlx z$;JC0P9+en2Wlxjwq#z^a6pdnD6fJM!GV7_%8%c)kc5LZs_G^qvw)&J#6WSp< zmsd~1-(GrgjC56Pdf6#!dt^y8Rg}!#UXf)W%~PeU+kU`FeSZHk)%sFv++#Dujk-~m zFHvVJC}UBn2jN& zs!@nZ?e(iyZPNo`p1i#~wsv9l@#Z|ag3JR>0#u1iW9M1RK1iF6-RbJ4KYg?B`dET9 zyR~DjZ>%_vWYm*Z9_+^~hJ_|SNTzBKx=U0l9 z9x(J96b{`R)UVQ$I`wTJ@$_}`)_DyUNOso6=WOmQKI1e`oyYy1C&%AQU<0-`(ow)1 zT}gYdwWdm4wW6|K)LcfMe&psE0XGhMy&xS`@vLi|1#Za{D6l@#D!?nW87wcscUZgELT{Cz**^;Zb~7 z(~WFRO`~!WvyZAW-8v!6n&j*PLm9NlN}BuUN}@E^TX*4Or#dMMF?V9KBeLSiLO4?B zcE3WNIa-H{ThrlCoN=XjOGk1dT=xwwrmt<1a)mrRzg{35`@C!T?&_;Q4Ce=5=>z^*zE_c(0*vWo2_#TD<2)pLXV$FlwP}Ik74IdDQU@yhkCr5h zn5aa>B7PWy5NQ!vf7@p_qtC*{dZ8zLS;JetPkHi>IvPjtJ#ThGQD|Lq#@vE2xdl%`x4A8xOln}BiQ92Po zW;0%A?I5CQ_O`@Ad=`2BLPPbBuPUp@Hb%a_OOI}y{Rwa<#h z5^6M}s7VzE)2&I*33pA>e71d78QpF>sNK;?lj^Kl#wU7G++`N_oL4QPd-iPqBhhs| z(uVM}$ItF-onXuuXO}o$t)emBO3Hjfyil@*+GF;9j?`&67GBM;TGkLHi>@)rkS4Nj zAEk;u)`jc4C$qN6WV2dVd#q}2X6nKt&X*}I@jP%Srs%%DS92lpDY^K*Sx4`l;aql$ zt*-V{U&$DM>pdO?%jt$t=vg5|p+Rw?SPaLW zB6nvZ69$ne4Z(s$3=Rf&RX8L9PWMV*S0@R zuIk&ba#s6sxVZ51^4Kon46X^9`?DC9mEhWB3f+o4#2EXFqy0(UTc>GU| zGCJmI|Dn-dX#7|_6(fT)>&YQ0H&&JX3cTvAq(a@ydM4>5Njnuere{J8p;3?1az60* z$1E7Yyxt^ytULeokgDnRVKQw9vzHg1>X@@jM$n$HBlveIrKP5-GJq%iWH#odVwV6cF^kKX(@#%%uQVb>#T6L^mC@)%SMd4DF? zVky!~ge27>cpUP1Vi}Z32lbLV+CQy+T5Wdmva6Fg^lKb!zrg|HPU=5Qu}k;4GVH+x z%;&pN1LOce0w@9i1Mo-Y|7|z}fbch@BPp2{&R-5{GLoeu8@limQmFF zaJRR|^;kW_nw~0V^ zfTnR!Ni*;-%oSHG1yItARs~uxra|O?YJxBzLjpeE-=~TO3Dn`JL5Gz;F~O1u3|FE- zvK2Vve`ylc`a}G`gpHg58Cqc9fMoy1L}7x7T>%~b&irrNMo?np3`q;d3d;zTK>nrK zOjPS{@&74-fA7j)8uT9~*g23uGnxwIVj9HorzUX#s0pcp2?GH6i}~+kv9fWChtPa_ z@T3m+$0pbjdQw7jcnHn;Pi85hk_u2-1^}c)LNvjdam8K-XJ+KgKQ%!?2n_!#{$H|| zLO=%;hRo6EDmnOBKCL9Cg~ETU##@u^W_5joZ%Et%X_n##%JDOcsO=0VL|Lkk!VdRJ z^|~2pB@PUspT?NOeO?=0Vb+fAGc!j%Ufn-cB`s2A~W{Zj{`wqWq_-w0wr@6VrM zbzni@8c>WS!7c&|ZR$cQ;`niRw{4kG#e z70e!uX8VmP23SuJ*)#(&R=;SxGAvq|&>geL&!5Z7@0Z(No*W561n#u$Uc`f9pD70# z=sKOSK|bF~#khTTn)B28h^a1{;>EaRnHj~>i=Fnr3+Fa4 z`^+O5_itS#7kPd20rq66_wH`%?HNzWk@XFK0n;Z@Cx{kx==2L22zWH$Yg?7 zvDj|u{{+NR3JvUH({;b*$b(U5U z7(lF!1bz2%06+|-v(D?2KgwNw7( zJB#Tz+ZRi&U$i?f34m7>uTzO#+E5cbaiQ&L}UxyOQq~afbNB4EI{E04ZWg53w0A{O%qo=lF8d zf~ktGvIgf-a~zQoWf>loF7pOodrd0a2|BzwwPDV}ShauTK8*fmF6NRbO>Iw9zZU}u zw8Ya}?seBnEGQDmH#XpUUkj}N49tP<2jYwTFp!P+&Fd(%Z#yo80|5@zN(D{_pNow*&4%ql zW~&yp@scb-+Qj-EmErY+Tu=dUmf@*BoXY2&oKT8U?8?s1d}4a`Aq>7SV800m$FE~? zjmz(LY+Xx9sDX$;vU`xgw*jLw7dWOnWWCO8o|;}f>cu0Q&`0I{YudMn;P;L3R-uz# zfns_mZED_IakFBPP2r_S8XM$X)@O-xVKi4`7373Jkd5{2$M#%cRhWer3M(vr{S6>h zj{givZJ3(`yFL@``(afn&~iNx@B1|-qfYiZu?-_&Z8+R~v`d6R-}EX9IVXWO-!hL5 z*k6T#^2zAXdardU3Ao~I)4DGdAv2bx{4nOK`20rJo>rmk3S2ZDu}))8Z1m}CKigf0 z3L`3Y`{huj`xj9@`$xTZzZc3je?n^yG<8sw$`Y%}9mUsjUR%T!?k^(q)6FH6Af^b6 zlPg~IEwg0y;`t9y;#D+uz!oE4VP&Je!<#q*F?m5L5?J3i@!0J6q#eu z!RRU`-)HeqGi_UJZ(n~|PSNsv+Wgl{P-TvaUQ9j?ZCtvb^37U$sFpBrkT{7Jpd?HpIvj2!}RIq zH{9~+gErN2+}J`>Jvng2hwM`=PLNkc7pkjblKW|+Fk9rc)G1R>Ww>RC=r-|!m-u7( zc(a$9NG}w#PjWNMS~)o=i~WA&4L(YIW25@AL9+H9!?3Y}sv#MOdY{bb9j>p`{?O(P zIvb`n?_(gP2w3P#&91JX*md+bBEr%xUHMVqfB;(f?OPtMnAZ#rm5q5mh;a2f_si2_ z3oXWB?{NF(JtkAn6F(O{z@b76OIqMC$&oJ_&S|YbFJ*)3qVX_uNf5b8(!vGX19hsG z(OP>RmZp29KH9Ge2kKjKigUmOe^K_!UXP`von)PR8Qz$%=EmOB9xS(ZxE_tnyzo}7 z=6~$~9k0M~v}`w={AeqF?_)9q{m8K#6M{a&(;u;O41j)I$^T?lx5(zlebpY@NT&#N zR+1bB)-1-xj}R8uwqwf=iP1GbxBjneCC%UrSdSxK1vM^i9;bUkS#iRZw2H>rS<2<$ zNT3|sDH>{tXb=zq7XZi*K?#Zsa1h1{h5!Tq_YbKFm_*=A5-<~j63he;4`77!|LBlo zR^~tR3yxcU=gDFbshyF6>o0bdp$qmHS7D}m3;^QZq9kBBU|9$N-~oU?G5;jyFR7>z hN`IR97YZXIo@y!QgFWddJ3|0`sjFx!m))><{BI=FK%f8s diff --git a/dev/manual_tests/web/index.html b/dev/manual_tests/web/index.html index 095c2ba12c297..6602df01ef15a 100644 --- a/dev/manual_tests/web/index.html +++ b/dev/manual_tests/web/index.html @@ -2,107 +2,12 @@ - - - - - - - - - - - - - - - - manual_tests - - - + diff --git a/dev/manual_tests/web/manifest.json b/dev/manual_tests/web/manifest.json deleted file mode 100644 index cf80086c6a86b..0000000000000 --- a/dev/manual_tests/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "manual_tests", - "short_name": "manual_tests", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/dev/manual_tests/windows/flutter/CMakeLists.txt b/dev/manual_tests/windows/flutter/CMakeLists.txt index b2e4bd8d658b2..66188df94bcad 100644 --- a/dev/manual_tests/windows/flutter/CMakeLists.txt +++ b/dev/manual_tests/windows/flutter/CMakeLists.txt @@ -23,7 +23,6 @@ list(APPEND FLUTTER_LIBRARY_HEADERS "flutter_windows.h" "flutter_messenger.h" "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" ) list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") add_library(flutter INTERFACE) diff --git a/dev/manual_tests/windows/runner/CMakeLists.txt b/dev/manual_tests/windows/runner/CMakeLists.txt index de2d8916b72ba..72cf6b86e49c5 100644 --- a/dev/manual_tests/windows/runner/CMakeLists.txt +++ b/dev/manual_tests/windows/runner/CMakeLists.txt @@ -4,6 +4,7 @@ project(runner LANGUAGES CXX) add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" + "run_loop.cpp" "utils.cpp" "win32_window.cpp" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" diff --git a/dev/manual_tests/windows/runner/Runner.rc b/dev/manual_tests/windows/runner/Runner.rc index 1f4ecbcebcf40..96fec5afe0366 100644 --- a/dev/manual_tests/windows/runner/Runner.rc +++ b/dev/manual_tests/windows/runner/Runner.rc @@ -45,16 +45,6 @@ END #endif // APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - ///////////////////////////////////////////////////////////////////////////// // // Version @@ -89,11 +79,11 @@ BEGIN BEGIN BLOCK "040904e4" BEGIN - VALUE "CompanyName", "dev.flutter" "\0" - VALUE "FileDescription", "manual_tests" "\0" + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "A new Flutter project." "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "manual_tests" "\0" - VALUE "LegalCopyright", "Copyright (C) 2021 dev.flutter. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2021 com.example. All rights reserved." "\0" VALUE "OriginalFilename", "manual_tests.exe" "\0" VALUE "ProductName", "manual_tests" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" diff --git a/dev/manual_tests/windows/runner/flutter_window.cpp b/dev/manual_tests/windows/runner/flutter_window.cpp index 9cbd3109c3fee..41bbc5e03429c 100644 --- a/dev/manual_tests/windows/runner/flutter_window.cpp +++ b/dev/manual_tests/windows/runner/flutter_window.cpp @@ -1,15 +1,12 @@ -// 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. - #include "flutter_window.h" #include #include "flutter/generated_plugin_registrant.h" -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} +FlutterWindow::FlutterWindow(RunLoop* run_loop, + const flutter::DartProject& project) + : run_loop_(run_loop), project_(project) {} FlutterWindow::~FlutterWindow() {} @@ -29,12 +26,14 @@ bool FlutterWindow::OnCreate() { return false; } RegisterPlugins(flutter_controller_->engine()); + run_loop_->RegisterFlutterInstance(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { + run_loop_->UnregisterFlutterInstance(flutter_controller_->engine()); flutter_controller_ = nullptr; } diff --git a/dev/manual_tests/windows/runner/flutter_window.h b/dev/manual_tests/windows/runner/flutter_window.h index bbc5836c018a2..62c11f15c3d5f 100644 --- a/dev/manual_tests/windows/runner/flutter_window.h +++ b/dev/manual_tests/windows/runner/flutter_window.h @@ -10,13 +10,16 @@ #include +#include "run_loop.h" #include "win32_window.h" // A window that does nothing but host a Flutter view. class FlutterWindow : public Win32Window { public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); + // Creates a new FlutterWindow driven by the |run_loop|, hosting a + // Flutter view running |project|. + explicit FlutterWindow(RunLoop* run_loop, + const flutter::DartProject& project); virtual ~FlutterWindow(); protected: @@ -27,6 +30,9 @@ class FlutterWindow : public Win32Window { LPARAM const lparam) noexcept override; private: + // The run loop driving events for this window. + RunLoop* run_loop_; + // The project to run. flutter::DartProject project_; diff --git a/dev/manual_tests/windows/runner/main.cpp b/dev/manual_tests/windows/runner/main.cpp index 5bd83f75abba9..876f83882d6aa 100644 --- a/dev/manual_tests/windows/runner/main.cpp +++ b/dev/manual_tests/windows/runner/main.cpp @@ -1,12 +1,9 @@ -// 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. - #include #include #include #include "flutter_window.h" +#include "run_loop.h" #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, @@ -21,6 +18,8 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, // plugins. ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + RunLoop run_loop; + flutter::DartProject project(L"data"); std::vector command_line_arguments = @@ -28,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - FlutterWindow window(project); + FlutterWindow window(&run_loop, project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); if (!window.CreateAndShow(L"manual_tests", origin, size)) { @@ -36,11 +35,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, } window.SetQuitOnClose(true); - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } + run_loop.Run(); ::CoUninitialize(); return EXIT_SUCCESS; diff --git a/dev/manual_tests/windows/runner/resource.h b/dev/manual_tests/windows/runner/resource.h index c245ff19cb580..365297a05d67b 100644 --- a/dev/manual_tests/windows/runner/resource.h +++ b/dev/manual_tests/windows/runner/resource.h @@ -6,13 +6,12 @@ // Microsoft Visual C++ generated include file. // Used by Runner.rc // -#define IDI_APP_ICON 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_RESOURCE_VALUE 101 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/dev/manual_tests/windows/runner/resources/app_icon.ico b/dev/manual_tests/windows/runner/resources/app_icon.ico deleted file mode 100644 index 2e4cc829b07d6ce44fb5c1a9ade8070767724e8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 787 zcmV+u1MK{XP)n7bpJ_;IC> zCYE;Tt!%ADOV>j1uTiiSxeX|y1X2W|o#F?!5e-@dLSPfH6C}yWC0XBixx#SC&d$C! z@6EXnmOYkbc7DH|@7n=rqKW@HjJ6Ej{Mdhprv-wf7MHF~XJt3Fl)?A#loBMBxxlL` z0mSfkqpAW@@G1mI!ix)#h8Go}0bWdi7I+Z>n&5*A&;}n=fJXRW0<^*h5uh2KU4V9Y zRsk`Y3x9QWZ((P@5Qpa)3YWr<-h8)XU@kFY@EnsNXZX=I zPYERO)YIY0@SYOL;3*eGz!$!v1X6es0cGI=?pK?LC%k@P5Ao$-P>Q;{WZ>NY8b14_XO(q&L-rqU%|kf z$Fb^ER=l{!wtB=i9sYJ>#&y{IFMPfM`RWP`U>0-tH+!kM{kRvM03Qkct?!VpEF=8P z2!0f764)0+TqW#pe1?4aIl?DcF>SVrlee%)2(ltnCSh;=6XY+SzyVAnycxn5;~daS z2(=`3s)XGyA0U7F2o8((@IrAk%$6+$W^5ZxDj}GFaS|;2_A`XHy>ScQeu6z`atVKT zPJ<_xAo8iK?IICA-CpX!QTGbKh06f##3!lRU8LB@(w$omdV^v%J<-|+mmvDN{Bbc( z36k=bAiiNjT7rr#Gm;Y2Y?_jiplaWsgamaPCs6{~#z~ZrK@&|haaQ~hU;qgkt*1!I RvP=K~002ovPDHLkV1o3TVfFw3 diff --git a/dev/manual_tests/windows/runner/run_loop.cpp b/dev/manual_tests/windows/runner/run_loop.cpp new file mode 100644 index 0000000000000..2d6636ab6bc67 --- /dev/null +++ b/dev/manual_tests/windows/runner/run_loop.cpp @@ -0,0 +1,66 @@ +#include "run_loop.h" + +#include + +#include + +RunLoop::RunLoop() {} + +RunLoop::~RunLoop() {} + +void RunLoop::Run() { + bool keep_running = true; + TimePoint next_flutter_event_time = TimePoint::clock::now(); + while (keep_running) { + std::chrono::nanoseconds wait_duration = + std::max(std::chrono::nanoseconds(0), + next_flutter_event_time - TimePoint::clock::now()); + ::MsgWaitForMultipleObjects( + 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000), + QS_ALLINPUT); + bool processed_events = false; + MSG message; + // All pending Windows messages must be processed; MsgWaitForMultipleObjects + // won't return again for items left in the queue after PeekMessage. + while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { + processed_events = true; + if (message.message == WM_QUIT) { + keep_running = false; + break; + } + ::TranslateMessage(&message); + ::DispatchMessage(&message); + // Allow Flutter to process messages each time a Windows message is + // processed, to prevent starvation. + next_flutter_event_time = + std::min(next_flutter_event_time, ProcessFlutterMessages()); + } + // If the PeekMessage loop didn't run, process Flutter messages. + if (!processed_events) { + next_flutter_event_time = + std::min(next_flutter_event_time, ProcessFlutterMessages()); + } + } +} + +void RunLoop::RegisterFlutterInstance( + flutter::FlutterEngine* flutter_instance) { + flutter_instances_.insert(flutter_instance); +} + +void RunLoop::UnregisterFlutterInstance( + flutter::FlutterEngine* flutter_instance) { + flutter_instances_.erase(flutter_instance); +} + +RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { + TimePoint next_event_time = TimePoint::max(); + for (auto instance : flutter_instances_) { + std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); + if (wait_duration != std::chrono::nanoseconds::max()) { + next_event_time = + std::min(next_event_time, TimePoint::clock::now() + wait_duration); + } + } + return next_event_time; +} diff --git a/dev/manual_tests/windows/runner/run_loop.h b/dev/manual_tests/windows/runner/run_loop.h new file mode 100644 index 0000000000000..441e7b1cd10cd --- /dev/null +++ b/dev/manual_tests/windows/runner/run_loop.h @@ -0,0 +1,44 @@ +// 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. + +#ifndef RUNNER_RUN_LOOP_H_ +#define RUNNER_RUN_LOOP_H_ + +#include + +#include +#include + +// A runloop that will service events for Flutter instances as well +// as native messages. +class RunLoop { + public: + RunLoop(); + ~RunLoop(); + + // Prevent copying + RunLoop(RunLoop const&) = delete; + RunLoop& operator=(RunLoop const&) = delete; + + // Runs the run loop until the application quits. + void Run(); + + // Registers the given Flutter instance for event servicing. + void RegisterFlutterInstance( + flutter::FlutterEngine* flutter_instance); + + // Unregisters the given Flutter instance from event servicing. + void UnregisterFlutterInstance( + flutter::FlutterEngine* flutter_instance); + + private: + using TimePoint = std::chrono::steady_clock::time_point; + + // Processes all currently pending messages for registered Flutter instances. + TimePoint ProcessFlutterMessages(); + + std::set flutter_instances_; +}; + +#endif // RUNNER_RUN_LOOP_H_ diff --git a/dev/snippets/config/templates/README.md b/dev/snippets/config/templates/README.md index d30e12e699afb..c7e1dea3c1720 100644 --- a/dev/snippets/config/templates/README.md +++ b/dev/snippets/config/templates/README.md @@ -1,21 +1,10 @@ -## Templates are only used for Engine code samples. - -They should not be used in the Framework, since the code samples should reside -in the [`examples/api`](../../../../examples/api) directory. - -If you are creating engine code samples, the following document may be of -interest. - -Eventually, Engine code samples will also be converted to point to separate -files as the framework does. - ## Creating Code Snippets In general, creating application snippets can be accomplished with the following -syntax inside the dartdoc comment for a Flutter class/variable/enum/etc.: +syntax inside of the dartdoc comment for a Flutter class/variable/enum/etc.: ```dart -/// {@tool snippet} +/// {@tool snippet --template=stateful_widget} /// Any text outside of the code blocks will be accumulated and placed at the /// top of the snippet box as a description. Don't try and say "see the code /// above" or "see the code below", since the location of the description may diff --git a/dev/tools/gen_defaults/README.md b/dev/tools/gen_defaults/README.md deleted file mode 100644 index f5c4fcda48cf1..0000000000000 --- a/dev/tools/gen_defaults/README.md +++ /dev/null @@ -1,27 +0,0 @@ -## Token Defaults Generator - -Script that generates widget component theme data defaults -based on the Material Token database. These tokens were -extracted into a JSON file from an internal Google database. - -## Usage -Run this program from the root of the git repository: -``` -dart dev/tools/gen_defaults/bin/gen_defaults.dart -``` - -## Templates - -There is a template file for every component that needs defaults from -the token database. These templates are implemented as subclasses of -`TokenTemplate`. This base class provides some utilities and a structure -for adding a new chunk of generated code to the bottom of a given file. - -Templates need to override the `generate` method to provide the generated -code chunk as a string. The tokens are represented as a `Map` -that is loaded from `data/material-tokens.json`. Templates can look up -whatever properties are needed in this structure to provide the properties -needed for the component. - -See `lib/fab_template.dart` for an example that generates defaults for the -Floating Action Button. diff --git a/dev/tools/gen_defaults/bin/gen_defaults.dart b/dev/tools/gen_defaults/bin/gen_defaults.dart deleted file mode 100644 index d014077776fe1..0000000000000 --- a/dev/tools/gen_defaults/bin/gen_defaults.dart +++ /dev/null @@ -1,29 +0,0 @@ -// 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. - -// Generate component theme data defaults based on the Material -// Design Token database. These tokens were extracted into a -// JSON file from the internal Google database. -// -// ## Usage -// -// Run this program from the root of the git repository. -// -// ``` -// dart dev/tools/gen_defaults/bin/gen_defaults.dart -// ``` - -import 'dart:convert'; -import 'dart:io'; - -import 'package:gen_defaults/fab_template.dart'; - -Future main(List args) async { - const String tokensDB = 'dev/tools/gen_defaults/data/material-tokens.json'; - final Map tokens = jsonDecode(File(tokensDB).readAsStringSync()) as Map; - - const String materialLib = 'packages/flutter/lib/src/material'; - - FABTemplate('$materialLib/floating_action_button.dart', tokens).updateFile(); -} diff --git a/dev/tools/gen_defaults/data/material-tokens.json b/dev/tools/gen_defaults/data/material-tokens.json deleted file mode 100644 index 2cd2616ffd47a..0000000000000 --- a/dev/tools/gen_defaults/data/material-tokens.json +++ /dev/null @@ -1,1044 +0,0 @@ -{ - "version": "v0.74", - "date": "2022-01-06", - "md.sys.color.light.on-tertiary": "md.ref.palette.tertiary100", - "md.sys.color.light.on-secondary-container": "md.ref.palette.secondary10", - "md.sys.color.light.on-secondary": "md.ref.palette.secondary100", - "md.sys.color.light.on-surface-variant": "md.ref.palette.neutral-variant30", - "md.sys.color.light.on-tertiary-container": "md.ref.palette.tertiary10", - "md.sys.color.light.secondary": "md.ref.palette.secondary40", - "md.sys.color.light.inverse-on-surface": "md.ref.palette.neutral95", - "md.sys.color.light.inverse-surface": "md.ref.palette.neutral20", - "md.sys.color.light.outline": "md.ref.palette.neutral-variant50", - "md.sys.color.light.on-primary": "md.ref.palette.primary100", - "md.sys.color.light.primary-container": "md.ref.palette.primary90", - "md.sys.color.light.tertiary": "md.ref.palette.tertiary40", - "md.sys.color.light.on-error": "md.ref.palette.error100", - "md.sys.color.light.shadow": "md.ref.palette.neutral0", - "md.sys.color.light.error-container": "md.ref.palette.error90", - "md.sys.color.light.surface-variant": "md.ref.palette.neutral-variant90", - "md.sys.color.light.background": "md.ref.palette.neutral99", - "md.sys.color.light.surface": "md.ref.palette.neutral99", - "md.sys.color.light.on-background": "md.ref.palette.neutral10", - "md.sys.color.light.tertiary-container": "md.ref.palette.tertiary90", - "md.sys.color.light.inverse-primary": "md.ref.palette.primary80", - "md.sys.color.light.error": "md.ref.palette.error40", - "md.sys.color.light.on-error-container": "md.ref.palette.error10", - "md.sys.color.light.on-surface": "md.ref.palette.neutral10", - "md.sys.color.light.primary": "md.ref.palette.primary40", - "md.sys.color.light.secondary-container": "md.ref.palette.secondary90", - "md.sys.color.light.on-primary-container": "md.ref.palette.primary10", - "md.sys.color.dark.on-tertiary": "md.ref.palette.tertiary20", - "md.sys.color.dark.on-secondary-container": "md.ref.palette.secondary90", - "md.sys.color.dark.on-secondary": "md.ref.palette.secondary20", - "md.sys.color.dark.on-surface-variant": "md.ref.palette.neutral-variant80", - "md.sys.color.dark.on-tertiary-container": "md.ref.palette.tertiary90", - "md.sys.color.dark.secondary": "md.ref.palette.secondary80", - "md.sys.color.dark.inverse-on-surface": "md.ref.palette.neutral20", - "md.sys.color.dark.inverse-surface": "md.ref.palette.neutral90", - "md.sys.color.dark.outline": "md.ref.palette.neutral-variant60", - "md.sys.color.dark.on-primary": "md.ref.palette.primary20", - "md.sys.color.dark.primary-container": "md.ref.palette.primary30", - "md.sys.color.dark.tertiary": "md.ref.palette.tertiary80", - "md.sys.color.dark.on-error": "md.ref.palette.error20", - "md.sys.color.dark.shadow": "md.ref.palette.neutral0", - "md.sys.color.dark.error-container": "md.ref.palette.error30", - "md.sys.color.dark.surface-variant": "md.ref.palette.neutral-variant30", - "md.sys.color.dark.background": "md.ref.palette.neutral10", - "md.sys.color.dark.surface": "md.ref.palette.neutral10", - "md.sys.color.dark.on-background": "md.ref.palette.neutral90", - "md.sys.color.dark.tertiary-container": "md.ref.palette.tertiary30", - "md.sys.color.dark.inverse-primary": "md.ref.palette.primary40", - "md.sys.color.dark.error": "md.ref.palette.error80", - "md.sys.color.dark.on-error-container": "md.ref.palette.error80", - "md.sys.color.dark.on-surface": "md.ref.palette.neutral90", - "md.sys.color.dark.primary": "md.ref.palette.primary80", - "md.sys.color.dark.secondary-container": "md.ref.palette.secondary30", - "md.sys.color.dark.on-primary-container": "md.ref.palette.primary90", - "md.ref.palette.secondary40": "#FF625B71", - "md.ref.palette.grey40": "#FF5E5E5E", - "md.ref.palette.secondary95": "#FFF6EDFF", - "md.ref.palette.red80": "#FFF2B8B5", - "md.ref.palette.grey-variant0": "#FF000000", - "md.ref.palette.blue-variant10": "#FF001D35", - "md.ref.palette.blue-variant99": "#FFF7FCFF", - "md.ref.palette.blue80": "#FFA8C7FA", - "md.ref.palette.red99": "#FFFFFBF9", - "md.ref.palette.grey-variant10": "#FF191D1C", - "md.ref.palette.neutral50": "#FF787579", - "md.ref.palette.blue-variant70": "#FF5AB3F0", - "md.ref.palette.primary30": "#FF4F378B", - "md.ref.palette.grey-variant100": "#FFFFFFFF", - "md.ref.palette.yellow40": "#FF945700", - "md.ref.palette.tertiary60": "#FFB58392", - "md.ref.palette.secondary50": "#FF7A7289", - "md.ref.palette.green99": "#FFF2FFEE", - "md.ref.palette.blue-variant100": "#FFFFFFFF", - "md.ref.palette.yellow70": "#FFF09D00", - "md.ref.palette.neutral-variant90": "#FFE7E0EC", - "md.ref.palette.grey-variant99": "#FFFAFDFB", - "md.ref.palette.primary60": "#FF9A82DB", - "md.ref.palette.green10": "#FF072711", - "md.ref.palette.grey-variant95": "#FFEFF2EF", - "md.ref.palette.blue10": "#FF041E49", - "md.ref.palette.neutral-variant0": "#FF000000", - "md.ref.palette.grey10": "#FF1F1F1F", - "md.ref.palette.grey80": "#FFC7C7C7", - "md.ref.palette.neutral99": "#FFFFFBFE", - "md.ref.palette.green90": "#FFC4EED0", - "md.ref.palette.grey50": "#FF757575", - "md.ref.palette.neutral-variant99": "#FFFFFBFE", - "md.ref.palette.yellow20": "#FF562D00", - "md.ref.palette.error0": "#FF000000", - "md.ref.palette.yellow50": "#FFB26C00", - "md.ref.palette.red0": "#FF000000", - "md.ref.palette.red20": "#FF601410", - "md.ref.palette.red60": "#FFE46962", - "md.ref.palette.grey30": "#FF474747", - "md.ref.palette.primary99": "#FFFFFBFE", - "md.ref.palette.green70": "#FF37BE5F", - "md.ref.palette.yellow80": "#FFFFBB29", - "md.ref.palette.green50": "#FF198639", - "md.ref.palette.yellow90": "#FFFFDF99", - "md.ref.palette.tertiary100": "#FFFFFFFF", - "md.ref.palette.secondary30": "#FF4A4458", - "md.ref.palette.neutral95": "#FFF4EFF4", - "md.ref.palette.neutral-variant100": "#FFFFFFFF", - "md.ref.palette.tertiary95": "#FFFFECF1", - "md.ref.palette.red40": "#FFB3261E", - "md.ref.palette.blue-variant30": "#FF004A77", - "md.ref.palette.primary0": "#FF000000", - "md.ref.palette.blue-variant20": "#FF003355", - "md.ref.palette.error30": "#FF8C1D18", - "md.ref.palette.neutral0": "#FF000000", - "md.ref.palette.error10": "#FF410E0B", - "md.ref.palette.yellow99": "#FFFFFBF0", - "md.ref.palette.neutral-variant80": "#FFCAC4D0", - "md.ref.palette.secondary10": "#FF1D192B", - "md.ref.palette.neutral-variant40": "#FF605D66", - "md.ref.palette.primary100": "#FFFFFFFF", - "md.ref.palette.error80": "#FFF2B8B5", - "md.ref.palette.red30": "#FF8C1D18", - "md.ref.palette.black": "#FF000000", - "md.ref.palette.secondary80": "#FFCCC2DC", - "md.ref.palette.blue-variant0": "#FF000000", - "md.ref.palette.neutral80": "#FFC9C5CA", - "md.ref.palette.blue70": "#FF7CACF8", - "md.ref.palette.neutral-variant70": "#FFAEA9B4", - "md.ref.palette.neutral-variant50": "#FF79747E", - "md.ref.palette.tertiary40": "#FF7D5260", - "md.ref.palette.tertiary50": "#FF986977", - "md.ref.palette.primary40": "#FF6750A4", - "md.ref.palette.secondary20": "#FF332D41", - "md.ref.palette.blue40": "#FF0B57D0", - "md.ref.palette.neutral-variant60": "#FF938F99", - "md.ref.palette.tertiary30": "#FF633B48", - "md.ref.palette.grey20": "#FF303030", - "md.ref.palette.neutral10": "#FF1C1B1F", - "md.ref.palette.tertiary80": "#FFEFB8C8", - "md.ref.palette.red50": "#FFDC362E", - "md.ref.palette.secondary0": "#FF000000", - "md.ref.palette.secondary99": "#FFFFFBFE", - "md.ref.palette.neutral90": "#FFE6E1E5", - "md.ref.palette.tertiary70": "#FFD29DAC", - "md.ref.palette.primary80": "#FFD0BCFF", - "md.ref.palette.error95": "#FFFCEEEE", - "md.ref.palette.grey99": "#FFFDFCFB", - "md.ref.palette.primary90": "#FFEADDFF", - "md.ref.palette.yellow30": "#FF754200", - "md.ref.palette.green0": "#FF000000", - "md.ref.palette.blue50": "#FF1B6EF3", - "md.ref.palette.green40": "#FF146C2E", - "md.ref.palette.blue95": "#FFECF3FE", - "md.ref.palette.red10": "#FF410E0B", - "md.ref.palette.neutral-variant20": "#FF322F37", - "md.ref.palette.primary20": "#FF381E72", - "md.ref.palette.error50": "#FFDC362E", - "md.ref.palette.primary95": "#FFF6EDFF", - "md.ref.palette.green20": "#FF0A3818", - "md.ref.palette.blue-variant80": "#FF7FCFFF", - "md.ref.palette.primary70": "#FFB69DF8", - "md.ref.palette.tertiary20": "#FF492532", - "md.ref.palette.yellow60": "#FFD68400", - "md.ref.palette.green60": "#FF1EA446", - "md.ref.palette.neutral-variant10": "#FF1D1A22", - "md.ref.palette.tertiary99": "#FFFFFBFA", - "md.ref.palette.tertiary10": "#FF31111D", - "md.ref.palette.neutral70": "#FFAEAAAE", - "md.ref.palette.yellow0": "#FF000000", - "md.ref.palette.red95": "#FFFCEEEE", - "md.ref.palette.green30": "#FF0F5223", - "md.ref.palette.blue-variant60": "#FF3998D3", - "md.ref.palette.neutral40": "#FF605D62", - "md.ref.palette.grey70": "#FFABABAB", - "md.ref.palette.secondary100": "#FFFFFFFF", - "md.ref.palette.grey-variant30": "#FF444746", - "md.ref.palette.secondary60": "#FF958DA5", - "md.ref.palette.grey-variant90": "#FFE1E3E1", - "md.ref.palette.grey60": "#FF8F8F8F", - "md.ref.palette.blue-variant50": "#FF047DB7", - "md.ref.palette.yellow100": "#FFFFFFFF", - "md.ref.palette.grey95": "#FFF2F2F2", - "md.ref.palette.grey90": "#FFE3E3E3", - "md.ref.palette.error60": "#FFE46962", - "md.ref.palette.grey-variant50": "#FF747775", - "md.ref.palette.error99": "#FFFFFBF9", - "md.ref.palette.tertiary90": "#FFFFD8E4", - "md.ref.palette.yellow10": "#FF421F00", - "md.ref.palette.blue90": "#FFD3E3FD", - "md.ref.palette.error70": "#FFEC928E", - "md.ref.palette.neutral60": "#FF939094", - "md.ref.palette.error40": "#FFB3261E", - "md.ref.palette.blue0": "#FF000000", - "md.ref.palette.neutral-variant30": "#FF49454F", - "md.ref.palette.green95": "#FFE7F8ED", - "md.ref.palette.blue30": "#FF0842A0", - "md.ref.palette.secondary90": "#FFE8DEF8", - "md.ref.palette.neutral20": "#FF313033", - "md.ref.palette.blue-variant95": "#FFDFF3FF", - "md.ref.palette.red100": "#FFFFFFFF", - "md.ref.palette.blue99": "#FFFAFBFF", - "md.ref.palette.red70": "#FFEC928E", - "md.ref.palette.grey0": "#FF000000", - "md.ref.palette.neutral30": "#FF484649", - "md.ref.palette.blue-variant90": "#FFC2E7FF", - "md.ref.palette.grey-variant40": "#FF5C5F5E", - "md.ref.palette.white": "#FFFFFFFF", - "md.ref.palette.blue100": "#FFFFFFFF", - "md.ref.palette.neutral100": "#FFFFFFFF", - "md.ref.palette.grey-variant60": "#FF8E918F", - "md.ref.palette.yellow95": "#FFFFF0D1", - "md.ref.palette.blue20": "#FF062E6F", - "md.ref.palette.error20": "#FF601410", - "md.ref.palette.green80": "#FF6DD58C", - "md.ref.palette.grey100": "#FFFFFFFF", - "md.ref.palette.error90": "#FFF9DEDC", - "md.ref.palette.blue-variant40": "#FF00639B", - "md.ref.palette.blue60": "#FF4C8DF6", - "md.ref.palette.primary10": "#FF21005D", - "md.ref.palette.secondary70": "#FFB0A7C0", - "md.ref.palette.primary50": "#FF7F67BE", - "md.ref.palette.tertiary0": "#FF000000", - "md.ref.palette.error100": "#FFFFFFFF", - "md.ref.palette.grey-variant80": "#FFC4C7C5", - "md.ref.palette.red90": "#FFF9DEDC", - "md.ref.palette.grey-variant70": "#FFA9ACAA", - "md.ref.palette.green100": "#FFFFFFFF", - "md.ref.palette.neutral-variant95": "#FFF5EEFA", - "md.ref.palette.grey-variant20": "#FF2D312F", - "md.sys.elevation.surface-tint-color": "primary", - "md.sys.elevation.level5": { - "value": 12.0, - "units": "DIPS" - }, - "md.sys.elevation.level4": { - "value": 8.0, - "units": "DIPS" - }, - "md.sys.elevation.level3": { - "value": 6.0, - "units": "DIPS" - }, - "md.sys.elevation.level2": { - "value": 3.0, - "units": "DIPS" - }, - "md.sys.elevation.level1": { - "value": 1.0, - "units": "DIPS" - }, - "md.sys.elevation.level0": { - "value": 0.0, - "units": "DIPS" - }, - "md.sys.shape.corner.full": { - "family": "SHAPE_FAMILY_UNSPECIFIED", - "value": { - "value": 0.0, - "units": "UNIT_UNSPECIFIED" - } - }, - "md.sys.shape.corner.extra-large.top": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 0.0, - "units": "DIPS" - } - }, - "md.sys.shape.corner.extra-large": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 28.0, - "units": "DIPS" - } - }, - "md.sys.shape.corner.large.top": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 0.0, - "units": "DIPS" - } - }, - "md.sys.shape.corner.large.end": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 0.0, - "units": "DIPS" - } - }, - "md.sys.shape.corner.large": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 16.0, - "units": "DIPS" - } - }, - "md.sys.shape.corner.medium": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 12.0, - "units": "DIPS" - } - }, - "md.sys.shape.corner.small": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 8.0, - "units": "DIPS" - } - }, - "md.sys.shape.corner.extra-small.top": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 0.0, - "units": "DIPS" - } - }, - "md.sys.shape.corner.extra-small": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 4.0, - "units": "DIPS" - } - }, - "md.sys.shape.corner.none": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 0.0, - "units": "DIPS" - } - }, - "md.sys.shape.small": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 4.0, - "units": "DIPS" - } - }, - "md.sys.shape.medium": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 8.0, - "units": "DIPS" - } - }, - "md.sys.shape.large": { - "family": "SHAPE_FAMILY_ROUNDED_CORNERS", - "value": { - "value": 8.0, - "units": "DIPS" - } - }, - "md.sys.state.dragged.state-layer-opacity": 0.16, - "md.sys.state.pressed.state-layer-opacity": 0.12, - "md.sys.state.focus.state-layer-opacity": 0.12, - "md.sys.state.hover.state-layer-opacity": 0.08, - "md.sys.typescale.label-small": "labelSmall", - "md.sys.typescale.label-small.line-height": { - "value": 16.0, - "units": "POINTS" - }, - "md.sys.typescale.label-small.tracking": { - "value": 0.1, - "units": "POINTS" - }, - "md.sys.typescale.label-small.size": { - "value": 11.0, - "units": "POINTS" - }, - "md.sys.typescale.label-small.weight": "weightMedium", - "md.sys.typescale.label-small.font": "plainMedium", - "md.sys.typescale.label-medium": "labelMedium", - "md.sys.typescale.label-medium.text-transform": "TEXT_TRANSFORM_UNSPECIFIED", - "md.sys.typescale.label-medium.line-height": { - "value": 16.0, - "units": "POINTS" - }, - "md.sys.typescale.label-medium.tracking": { - "value": 0.1, - "units": "POINTS" - }, - "md.sys.typescale.label-medium.size": { - "value": 12.0, - "units": "POINTS" - }, - "md.sys.typescale.label-medium.weight": "weightMedium", - "md.sys.typescale.label-medium.font": "plainMedium", - "md.sys.typescale.label-large": "labelLarge", - "md.sys.typescale.label-large.line-height": { - "value": 20.0, - "units": "POINTS" - }, - "md.sys.typescale.label-large.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.label-large.size": { - "value": 14.0, - "units": "POINTS" - }, - "md.sys.typescale.label-large.weight": "weightMedium", - "md.sys.typescale.label-large.font": "plainMedium", - "md.sys.typescale.body-small": "bodySmall", - "md.sys.typescale.body-small.line-height": { - "value": 16.0, - "units": "POINTS" - }, - "md.sys.typescale.body-small.tracking": { - "value": 0.1, - "units": "POINTS" - }, - "md.sys.typescale.body-small.size": { - "value": 12.0, - "units": "POINTS" - }, - "md.sys.typescale.body-small.weight": "weightRegular", - "md.sys.typescale.body-small.font": "plainRegular", - "md.sys.typescale.body-medium": "bodyMedium", - "md.sys.typescale.body-medium.line-height": { - "value": 20.0, - "units": "POINTS" - }, - "md.sys.typescale.body-medium.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.body-medium.size": { - "value": 14.0, - "units": "POINTS" - }, - "md.sys.typescale.body-medium.weight": "weightRegular", - "md.sys.typescale.body-medium.font": "plainRegular", - "md.sys.typescale.body-large": "bodyLarge", - "md.sys.typescale.body-large.line-height": { - "value": 24.0, - "units": "POINTS" - }, - "md.sys.typescale.body-large.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.body-large.size": { - "value": 16.0, - "units": "POINTS" - }, - "md.sys.typescale.body-large.weight": "weightRegular", - "md.sys.typescale.body-large.font": "plainRegular", - "md.sys.typescale.title-small": "titleSmall", - "md.sys.typescale.title-small.line-height": { - "value": 20.0, - "units": "POINTS" - }, - "md.sys.typescale.title-small.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.title-small.size": { - "value": 14.0, - "units": "POINTS" - }, - "md.sys.typescale.title-small.weight": "weightMedium", - "md.sys.typescale.title-small.font": "plainMedium", - "md.sys.typescale.title-medium": "titleMedium", - "md.sys.typescale.title-medium.line-height": { - "value": 24.0, - "units": "POINTS" - }, - "md.sys.typescale.title-medium.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.title-medium.size": { - "value": 16.0, - "units": "POINTS" - }, - "md.sys.typescale.title-medium.weight": "weightMedium", - "md.sys.typescale.title-medium.font": "plainMedium", - "md.sys.typescale.title-large": "titleLarge", - "md.sys.typescale.title-large.line-height": { - "value": 28.0, - "units": "POINTS" - }, - "md.sys.typescale.title-large.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.title-large.size": { - "value": 22.0, - "units": "POINTS" - }, - "md.sys.typescale.title-large.weight": "weightRegular", - "md.sys.typescale.title-large.font": "brandRegular", - "md.sys.typescale.headline-small": "headlineSmall", - "md.sys.typescale.headline-small.line-height": { - "value": 32.0, - "units": "POINTS" - }, - "md.sys.typescale.headline-small.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.headline-small.size": { - "value": 24.0, - "units": "POINTS" - }, - "md.sys.typescale.headline-small.weight": "weightRegular", - "md.sys.typescale.headline-small.font": "brandRegular", - "md.sys.typescale.headline-medium": "headlineMedium", - "md.sys.typescale.headline-medium.line-height": { - "value": 36.0, - "units": "POINTS" - }, - "md.sys.typescale.headline-medium.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.headline-medium.size": { - "value": 28.0, - "units": "POINTS" - }, - "md.sys.typescale.headline-medium.weight": "weightRegular", - "md.sys.typescale.headline-medium.font": "brandRegular", - "md.sys.typescale.headline-large": "headlineLarge", - "md.sys.typescale.headline-large.line-height": { - "value": 40.0, - "units": "POINTS" - }, - "md.sys.typescale.headline-large.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.headline-large.size": { - "value": 32.0, - "units": "POINTS" - }, - "md.sys.typescale.headline-large.font": "brandRegular", - "md.sys.typescale.headline-large.weight": "weightRegular", - "md.sys.typescale.display-small": "displaySmall", - "md.sys.typescale.display-small.line-height": { - "value": 44.0, - "units": "POINTS" - }, - "md.sys.typescale.display-small.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.display-small.size": { - "value": 36.0, - "units": "POINTS" - }, - "md.sys.typescale.display-small.weight": "weightRegular", - "md.sys.typescale.display-small.font": "brandRegular", - "md.sys.typescale.display-medium": "displayMedium", - "md.sys.typescale.display-medium.line-height": { - "value": 52.0, - "units": "POINTS" - }, - "md.sys.typescale.display-medium.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.display-medium.size": { - "value": 45.0, - "units": "POINTS" - }, - "md.sys.typescale.display-medium.weight": "weightRegular", - "md.sys.typescale.display-medium.font": "brandRegular", - "md.sys.typescale.display-large": "displayLarge", - "md.sys.typescale.display-large.line-height": { - "value": 64.0, - "units": "POINTS" - }, - "md.sys.typescale.display-large.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.display-large.size": { - "value": 57.0, - "units": "POINTS" - }, - "md.sys.typescale.display-large.weight": "weightRegular", - "md.sys.typescale.display-large.font": "brandRegular", - "md.sys.typescale.subtitle2": "subtitle2", - "md.sys.typescale.subtitle1": "subtitle1", - "md.sys.typescale.headline6": "headline6", - "md.sys.typescale.display1": "display1", - "md.sys.typescale.display1.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.subtitle2.line-height": { - "value": 20.0, - "units": "POINTS" - }, - "md.sys.typescale.subtitle2.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.subtitle2.size": { - "value": 14.0, - "units": "POINTS" - }, - "md.sys.typescale.subtitle1.line-height": { - "value": 24.0, - "units": "POINTS" - }, - "md.sys.typescale.subtitle1.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.subtitle1.size": { - "value": 16.0, - "units": "POINTS" - }, - "md.sys.typescale.headline6.line-height": { - "value": 24.0, - "units": "POINTS" - }, - "md.sys.typescale.headline6.tracking": { - "value": 0.0, - "units": "POINTS" - }, - "md.sys.typescale.headline6.size": { - "value": 18.0, - "units": "POINTS" - }, - "md.sys.typescale.display1.line-height": { - "value": 76.0, - "units": "POINTS" - }, - "md.sys.typescale.display1.size": { - "value": 64.0, - "units": "POINTS" - }, - "md.sys.typescale.subtitle2.weight": "weightMedium", - "md.sys.typescale.subtitle2.font": "plainMedium", - "md.sys.typescale.subtitle1.weight": "weightMedium", - "md.sys.typescale.subtitle1.font": "plainMedium", - "md.sys.typescale.headline6.weight": "weightRegular", - "md.sys.typescale.headline6.font": "brandRegular", - "md.sys.typescale.display1.weight": "weightRegular", - "md.sys.typescale.display1.font": "brandRegular", - "md.ref.typeface.brand-display-regular": "Roboto Regular", - "md.ref.typeface.weight-bold": 700.0, - "md.ref.typeface.weight-medium": 500.0, - "md.ref.typeface.weight-regular": 400.0, - "md.ref.typeface.plain-medium": "Roboto Medium", - "md.ref.typeface.plain-regular": "Roboto Regular", - "md.ref.typeface.brand-medium": "Roboto Medium", - "md.ref.typeface.brand-regular": "Roboto Regular", - "md.comp.fab.primary.container.shape": "md.sys.shape.corner.large", - "md.comp.fab.primary.pressed.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.focus.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.hover.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.lowered.pressed.container.elevation": "md.sys.elevation.level1", - "md.comp.fab.primary.pressed.state-layer.opacity": "md.sys.state.pressed.state-layer-opacity", - "md.comp.fab.primary.pressed.state-layer.color": "onPrimaryContainer", - "md.comp.fab.primary.pressed.container.elevation": "md.sys.elevation.level3", - "md.comp.fab.primary.lowered.focus.container.elevation": "md.sys.elevation.level1", - "md.comp.fab.primary.focus.container.elevation": "md.sys.elevation.level3", - "md.comp.fab.primary.focus.state-layer.opacity": "md.sys.state.focus.state-layer-opacity", - "md.comp.fab.primary.focus.state-layer.color": "onPrimaryContainer", - "md.comp.fab.primary.lowered.hover.container.elevation": "md.sys.elevation.level2", - "md.comp.fab.primary.hover.state-layer.opacity": "md.sys.state.hover.state-layer-opacity", - "md.comp.fab.primary.hover.state-layer.color": "onPrimaryContainer", - "md.comp.fab.primary.hover.container.elevation": "md.sys.elevation.level4", - "md.comp.fab.primary.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.icon.size": { - "value": 24.0, - "units": "DIPS" - }, - "md.comp.fab.primary.lowered.container.elevation": "md.sys.elevation.level1", - "md.comp.fab.primary.container.shadow-color": "shadow", - "md.comp.fab.primary.container.elevation": "md.sys.elevation.level3", - "md.comp.fab.primary.container.height": { - "value": 56.0, - "units": "DIPS" - }, - "md.comp.fab.primary.container.width": { - "value": 56.0, - "units": "DIPS" - }, - "md.comp.fab.primary.container.color": "primaryContainer", - "md.comp.fab.primary.large.container.shape": "md.sys.shape.corner.extra-large", - "md.comp.fab.primary.large.pressed.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.large.focus.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.large.hover.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.large.lowered.pressed.container.elevation": "md.sys.elevation.level1", - "md.comp.fab.primary.large.pressed.state-layer.opacity": "md.sys.state.pressed.state-layer-opacity", - "md.comp.fab.primary.large.pressed.state-layer.color": "onPrimaryContainer", - "md.comp.fab.primary.large.pressed.container.elevation": "md.sys.elevation.level3", - "md.comp.fab.primary.large.lowered.focus.container.elevation": "md.sys.elevation.level1", - "md.comp.fab.primary.large.focus.container.elevation": "md.sys.elevation.level3", - "md.comp.fab.primary.large.focus.state-layer.opacity": "md.sys.state.focus.state-layer-opacity", - "md.comp.fab.primary.large.focus.state-layer.color": "onPrimaryContainer", - "md.comp.fab.primary.large.lowered.hover.container.elevation": "md.sys.elevation.level2", - "md.comp.fab.primary.large.hover.state-layer.opacity": "md.sys.state.hover.state-layer-opacity", - "md.comp.fab.primary.large.hover.state-layer.color": "onPrimaryContainer", - "md.comp.fab.primary.large.hover.container.elevation": "md.sys.elevation.level4", - "md.comp.fab.primary.large.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.large.icon.size": { - "value": 36.0, - "units": "DIPS" - }, - "md.comp.fab.primary.large.lowered.container.elevation": "md.sys.elevation.level1", - "md.comp.fab.primary.large.container.shadow-color": "shadow", - "md.comp.fab.primary.large.container.elevation": "md.sys.elevation.level3", - "md.comp.fab.primary.large.container.height": { - "value": 96.0, - "units": "DIPS" - }, - "md.comp.fab.primary.large.container.width": { - "value": 96.0, - "units": "DIPS" - }, - "md.comp.fab.primary.large.container.color": "primaryContainer", - "md.comp.fab.primary.small.container.shape": "md.sys.shape.corner.medium", - "md.comp.fab.primary.small.pressed.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.small.focus.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.small.hover.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.small.lowered.pressed.container.elevation": "md.sys.elevation.level1", - "md.comp.fab.primary.small.pressed.state-layer.opacity": "md.sys.state.pressed.state-layer-opacity", - "md.comp.fab.primary.small.pressed.state-layer.color": "onPrimaryContainer", - "md.comp.fab.primary.small.pressed.container.elevation": "md.sys.elevation.level3", - "md.comp.fab.primary.small.lowered.focus.container.elevation": "md.sys.elevation.level1", - "md.comp.fab.primary.small.focus.container.elevation": "md.sys.elevation.level3", - "md.comp.fab.primary.small.focus.state-layer.opacity": "md.sys.state.focus.state-layer-opacity", - "md.comp.fab.primary.small.focus.state-layer.color": "onPrimaryContainer", - "md.comp.fab.primary.small.lowered.hover.container.elevation": "md.sys.elevation.level2", - "md.comp.fab.primary.small.hover.state-layer.opacity": "md.sys.state.hover.state-layer-opacity", - "md.comp.fab.primary.small.hover.state-layer.color": "onPrimaryContainer", - "md.comp.fab.primary.small.hover.container.elevation": "md.sys.elevation.level4", - "md.comp.fab.primary.small.icon.color": "onPrimaryContainer", - "md.comp.fab.primary.small.icon.size": { - "value": 24.0, - "units": "DIPS" - }, - "md.comp.fab.primary.small.lowered.container.elevation": "md.sys.elevation.level1", - "md.comp.fab.primary.small.container.shadow-color": "shadow", - "md.comp.fab.primary.small.container.elevation": "md.sys.elevation.level3", - "md.comp.fab.primary.small.container.height": { - "value": 40.0, - "units": "DIPS" - }, - "md.comp.fab.primary.small.container.width": { - "value": 40.0, - "units": "DIPS" - }, - "md.comp.fab.primary.small.container.color": "primaryContainer", - "md.comp.extended-fab.primary.container.shape": "md.sys.shape.corner.large", - "md.comp.extended-fab.primary.pressed.label-text.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.pressed.icon.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.focus.label-text.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.focus.icon.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.hover.label-text.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.hover.icon.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.lowered.pressed.container.elevation": "md.sys.elevation.level1", - "md.comp.extended-fab.primary.pressed.state-layer.opacity": "md.sys.state.pressed.state-layer-opacity", - "md.comp.extended-fab.primary.pressed.state-layer.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.pressed.container.elevation": "md.sys.elevation.level3", - "md.comp.extended-fab.primary.lowered.focus.container.elevation": "md.sys.elevation.level1", - "md.comp.extended-fab.primary.focus.container.elevation": "md.sys.elevation.level3", - "md.comp.extended-fab.primary.focus.state-layer.opacity": "md.sys.state.focus.state-layer-opacity", - "md.comp.extended-fab.primary.focus.state-layer.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.lowered.hover.container.elevation": "md.sys.elevation.level2", - "md.comp.extended-fab.primary.hover.state-layer.opacity": "md.sys.state.hover.state-layer-opacity", - "md.comp.extended-fab.primary.hover.state-layer.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.hover.container.elevation": "md.sys.elevation.level4", - "md.comp.extended-fab.primary.label-text.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.label-text.type": "labelText", - "md.comp.extended-fab.primary.label-text.tracking": "labelLarge", - "md.comp.extended-fab.primary.label-text.weight": "labelLarge", - "md.comp.extended-fab.primary.label-text.size": "labelLarge", - "md.comp.extended-fab.primary.label-text.line-height": "labelLarge", - "md.comp.extended-fab.primary.label-text.font": "labelLarge", - "md.comp.extended-fab.primary.icon.color": "onPrimaryContainer", - "md.comp.extended-fab.primary.icon.size": { - "value": 24.0, - "units": "DIPS" - }, - "md.comp.extended-fab.primary.lowered.container.elevation": "md.sys.elevation.level1", - "md.comp.extended-fab.primary.container.shadow-color": "shadow", - "md.comp.extended-fab.primary.container.elevation": "md.sys.elevation.level3", - "md.comp.extended-fab.primary.container.height": { - "value": 56.0, - "units": "DIPS" - }, - "md.comp.extended-fab.primary.container.color": "primaryContainer", - "md.comp.assist-chip.container.shape": "md.sys.shape.corner.small", - "md.comp.assist-chip.container.surface-tint-layer.color": "md.sys.elevation.surface-tint-color", - "md.comp.assist-chip.label-text.tracking": "labelLarge", - "md.comp.assist-chip.label-text.weight": "labelLarge", - "md.comp.assist-chip.label-text.size": "labelLarge", - "md.comp.assist-chip.label-text.line-height": "labelLarge", - "md.comp.assist-chip.label-text.font": "labelLarge", - "md.comp.assist-chip.with-icon.dragged.icon.color": "primary", - "md.comp.assist-chip.dragged.label-text.color": "onSurface", - "md.comp.assist-chip.dragged.state-layer.color": "onSurface", - "md.comp.assist-chip.with-icon.pressed.icon.color": "primary", - "md.comp.assist-chip.pressed.label-text.color": "onSurface", - "md.comp.assist-chip.pressed.state-layer.color": "onSurface", - "md.comp.assist-chip.with-icon.focus.icon.color": "primary", - "md.comp.assist-chip.flat.focus.outline.color": "onSurface", - "md.comp.assist-chip.focus.label-text.color": "onSurface", - "md.comp.assist-chip.focus.state-layer.color": "onSurface", - "md.comp.assist-chip.with-icon.hover.icon.color": "primary", - "md.comp.assist-chip.hover.label-text.color": "onSurface", - "md.comp.assist-chip.hover.state-layer.color": "onSurface", - "md.comp.assist-chip.dragged.state-layer.opacity": "md.sys.state.dragged.state-layer-opacity", - "md.comp.assist-chip.pressed.state-layer.opacity": "md.sys.state.pressed.state-layer-opacity", - "md.comp.assist-chip.focus.state-layer.opacity": "md.sys.state.focus.state-layer-opacity", - "md.comp.assist-chip.hover.state-layer.opacity": "md.sys.state.hover.state-layer-opacity", - "md.comp.assist-chip.label-text.type": "labelText", - "md.comp.assist-chip.dragged.container.elevation": "md.sys.elevation.level4", - "md.comp.assist-chip.elevated.pressed.container.elevation": "md.sys.elevation.level1", - "md.comp.assist-chip.elevated.focus.container.elevation": "md.sys.elevation.level1", - "md.comp.assist-chip.elevated.hover.container.elevation": "md.sys.elevation.level2", - "md.comp.assist-chip.elevated.disabled.container.opacity": 0.12, - "md.comp.assist-chip.elevated.disabled.container.color": "onSurface", - "md.comp.assist-chip.elevated.disabled.container.elevation": "md.sys.elevation.level0", - "md.comp.assist-chip.with-icon.disabled.icon.opacity": 0.38, - "md.comp.assist-chip.with-icon.disabled.icon.color": "onSurface", - "md.comp.assist-chip.disabled.label-text.opacity": 0.38, - "md.comp.assist-chip.disabled.label-text.color": "onSurface", - "md.comp.assist-chip.flat.disabled.outline.opacity": 0.12, - "md.comp.assist-chip.flat.disabled.outline.color": "onSurface", - "md.comp.assist-chip.with-icon.icon.color": "primary", - "md.comp.assist-chip.with-icon.icon.size": { - "value": 18.0, - "units": "DIPS" - }, - "md.comp.assist-chip.label-text.color": "onSurface", - "md.comp.assist-chip.elevated.container.shadow-color": "shadow", - "md.comp.assist-chip.elevated.container.color": "surface", - "md.comp.assist-chip.elevated.container.elevation": "md.sys.elevation.level1", - "md.comp.assist-chip.flat.outline.width": { - "value": 1.0, - "units": "DIPS" - }, - "md.comp.assist-chip.flat.outline.color": "outline", - "md.comp.assist-chip.flat.container.elevation": "md.sys.elevation.level0", - "md.comp.assist-chip.container.height": { - "value": 32.0, - "units": "DIPS" - }, - "md.comp.filter-chip.container.shape": "md.sys.shape.corner.small", - "md.comp.filter-chip.container.surface-tint-layer.color": "md.sys.elevation.surface-tint-color", - "md.comp.filter-chip.label-text.tracking": "labelLarge", - "md.comp.filter-chip.label-text.weight": "labelLarge", - "md.comp.filter-chip.label-text.size": "labelLarge", - "md.comp.filter-chip.label-text.line-height": "labelLarge", - "md.comp.filter-chip.label-text.font": "labelLarge", - "md.comp.filter-chip.with-icon.selected.dragged.icon.color": "onSecondaryContainer", - "md.comp.filter-chip.with-icon.unselected.dragged.icon.color": "onSurfaceVariant", - "md.comp.filter-chip.selected.dragged.label-text.color": "onSecondaryContainer", - "md.comp.filter-chip.selected.dragged.state-layer.color": "onSecondaryContainer", - "md.comp.filter-chip.unselected.dragged.label-text.color": "onSurfaceVariant", - "md.comp.filter-chip.unselected.dragged.state-layer.color": "onSurfaceVariant", - "md.comp.filter-chip.with-icon.selected.pressed.icon.color": "onSecondaryContainer", - "md.comp.filter-chip.with-icon.unselected.pressed.icon.color": "onSurfaceVariant", - "md.comp.filter-chip.selected.pressed.label-text.color": "onSecondaryContainer", - "md.comp.filter-chip.selected.pressed.state-layer.color": "onSurfaceVariant", - "md.comp.filter-chip.unselected.pressed.label-text.color": "onSurfaceVariant", - "md.comp.filter-chip.unselected.pressed.state-layer.color": "onSecondaryContainer", - "md.comp.filter-chip.with-icon.selected.focus.icon.color": "onSecondaryContainer", - "md.comp.filter-chip.with-icon.unselected.focus.icon.color": "onSurfaceVariant", - "md.comp.filter-chip.flat.unselected.focus.outline.color": "onSurfaceVariant", - "md.comp.filter-chip.selected.focus.label-text.color": "onSecondaryContainer", - "md.comp.filter-chip.selected.focus.state-layer.color": "onSecondaryContainer", - "md.comp.filter-chip.unselected.focus.label-text.color": "onSurfaceVariant", - "md.comp.filter-chip.unselected.focus.state-layer.color": "onSurfaceVariant", - "md.comp.filter-chip.with-icon.selected.hover.icon.color": "onSecondaryContainer", - "md.comp.filter-chip.with-icon.unselected.hover.icon.color": "onSurfaceVariant", - "md.comp.filter-chip.selected.hover.label-text.color": "onSecondaryContainer", - "md.comp.filter-chip.selected.hover.state-layer.color": "onSecondaryContainer", - "md.comp.filter-chip.unselected.hover.label-text.color": "onSurfaceVariant", - "md.comp.filter-chip.unselected.hover.state-layer.color": "onSurfaceVariant", - "md.comp.filter-chip.selected.dragged.state-layer.opacity": "md.sys.state.dragged.state-layer-opacity", - "md.comp.filter-chip.unselected.dragged.state-layer.opacity": "md.sys.state.dragged.state-layer-opacity", - "md.comp.filter-chip.selected.pressed.state-layer.opacity": "md.sys.state.pressed.state-layer-opacity", - "md.comp.filter-chip.unselected.pressed.state-layer.opacity": "md.sys.state.pressed.state-layer-opacity", - "md.comp.filter-chip.selected.focus.state-layer.opacity": "md.sys.state.focus.state-layer-opacity", - "md.comp.filter-chip.unselected.focus.state-layer.opacity": "md.sys.state.focus.state-layer-opacity", - "md.comp.filter-chip.selected.hover.state-layer.opacity": "md.sys.state.hover.state-layer-opacity", - "md.comp.filter-chip.unselected.hover.state-layer.opacity": "md.sys.state.hover.state-layer-opacity", - "md.comp.filter-chip.label-text.type": "labelText", - "md.comp.filter-chip.dragged.container.elevation": "md.sys.elevation.level4", - "md.comp.filter-chip.flat.unselected.pressed.container.elevation": "md.sys.elevation.level0", - "md.comp.filter-chip.flat.selected.pressed.container.elevation": "md.sys.elevation.level0", - "md.comp.filter-chip.elevated.pressed.container.elevation": "md.sys.elevation.level1", - "md.comp.filter-chip.flat.unselected.focus.container.elevation": "md.sys.elevation.level0", - "md.comp.filter-chip.flat.selected.focus.container.elevation": "md.sys.elevation.level0", - "md.comp.filter-chip.elevated.focus.container.elevation": "md.sys.elevation.level1", - "md.comp.filter-chip.flat.unselected.hover.container.elevation": "md.sys.elevation.level0", - "md.comp.filter-chip.flat.selected.hover.container.elevation": "md.sys.elevation.level1", - "md.comp.filter-chip.elevated.hover.container.elevation": "md.sys.elevation.level2", - "md.comp.filter-chip.elevated.disabled.container.opacity": 0.12, - "md.comp.filter-chip.elevated.disabled.container.color": "onSurface", - "md.comp.filter-chip.elevated.disabled.container.elevation": "md.sys.elevation.level0", - "md.comp.filter-chip.with-icon.disabled.icon.opacity": 0.38, - "md.comp.filter-chip.with-icon.disabled.icon.color": "onSurface", - "md.comp.filter-chip.flat.disabled.selected.container.opacity": 0.12, - "md.comp.filter-chip.flat.disabled.selected.container.color": "onSurface", - "md.comp.filter-chip.flat.disabled.unselected.outline.opacity": 0.12, - "md.comp.filter-chip.flat.disabled.unselected.outline.color": "onSurface", - "md.comp.filter-chip.disabled.label-text.opacity": 0.38, - "md.comp.filter-chip.disabled.label-text.color": "onSurface", - "md.comp.filter-chip.with-icon.selected.icon.color": "onSecondaryContainer", - "md.comp.filter-chip.with-icon.unselected.icon.color": "onSurfaceVariant", - "md.comp.filter-chip.with-icon.icon.size": { - "value": 18.0, - "units": "DIPS" - }, - "md.comp.filter-chip.selected.label-text.color": "onSecondaryContainer", - "md.comp.filter-chip.unselected.label-text.color": "onSurfaceVariant", - "md.comp.filter-chip.elevated.selected.container.color": "secondaryContainer", - "md.comp.filter-chip.elevated.unselected.container.color": "surface", - "md.comp.filter-chip.elevated.container.elevation": "md.sys.elevation.level1", - "md.comp.filter-chip.flat.selected.outline.width": { - "value": 0.0, - "units": "DIPS" - }, - "md.comp.filter-chip.flat.selected.container.color": "secondaryContainer", - "md.comp.filter-chip.flat.unselected.outline.width": { - "value": 1.0, - "units": "DIPS" - }, - "md.comp.filter-chip.flat.unselected.outline.color": "outline", - "md.comp.filter-chip.flat.container.elevation": "md.sys.elevation.level0", - "md.comp.filter-chip.container.shadow-color": "shadow", - "md.comp.filter-chip.container.height": { - "value": 32.0, - "units": "DIPS" - }, - "md.comp.input-chip.with-avatar.avatar.shape": "md.sys.shape.corner.full", - "md.comp.input-chip.container.shape": "md.sys.shape.corner.small", - "md.comp.input-chip.label-text.tracking": "labelLarge", - "md.comp.input-chip.label-text.weight": "labelLarge", - "md.comp.input-chip.label-text.size": "labelLarge", - "md.comp.input-chip.label-text.line-height": "labelLarge", - "md.comp.input-chip.label-text.font": "labelLarge", - "md.comp.input-chip.with-leading-icon.dragged.leading-icon.color": "onSurfaceVariant", - "md.comp.input-chip.with-trailing-icon.dragged.trailing-icon.color": "onSurfaceVariant", - "md.comp.input-chip.dragged.label-text.color": "onSurfaceVariant", - "md.comp.input-chip.dragged.state-layer.color": "onSurfaceVariant", - "md.comp.input-chip.with-leading-icon.pressed.leading-icon.color": "onSurfaceVariant", - "md.comp.input-chip.with-trailing-icon.pressed.trailing-icon.color": "onSurfaceVariant", - "md.comp.input-chip.pressed.label-text.color": "onSurfaceVariant", - "md.comp.input-chip.pressed.state-layer.color": "onSurfaceVariant", - "md.comp.input-chip.with-leading-icon.focus.leading-icon.color": "onSurfaceVariant", - "md.comp.input-chip.with-trailing-icon.focus.trailing-icon.color": "onSurfaceVariant", - "md.comp.input-chip.focus.outline.color": "onSurfaceVariant", - "md.comp.input-chip.focus.label-text.color": "onSurfaceVariant", - "md.comp.input-chip.focus.state-layer.color": "onSurfaceVariant", - "md.comp.input-chip.with-leading-icon.hover.leading-icon.color": "onSurfaceVariant", - "md.comp.input-chip.with-trailing-icon.hover.trailing-icon.color": "onSurfaceVariant", - "md.comp.input-chip.hover.label-text.color": "onSurfaceVariant", - "md.comp.input-chip.hover.state-layer.color": "onSurfaceVariant", - "md.comp.input-chip.dragged.state-layer.opacity": "md.sys.state.dragged.state-layer-opacity", - "md.comp.input-chip.pressed.state-layer.opacity": "md.sys.state.pressed.state-layer-opacity", - "md.comp.input-chip.focus.state-layer.opacity": "md.sys.state.focus.state-layer-opacity", - "md.comp.input-chip.hover.state-layer.opacity": "md.sys.state.hover.state-layer-opacity", - "md.comp.input-chip.label-text.type": "labelText", - "md.comp.input-chip.with-trailing-icon.trailing-icon.color": "onSurfaceVariant", - "md.comp.input-chip.dragged.container.elevation": "md.sys.elevation.level4", - "md.comp.input-chip.with-avatar.disabled.avatar.opacity": 0.38, - "md.comp.input-chip.with-leading-icon.disabled.leading-icon.opacity": 0.38, - "md.comp.input-chip.with-leading-icon.disabled.leading-icon.color": "onSurface", - "md.comp.input-chip.with-trailing-icon.disabled.trailing-icon.opacity": 0.38, - "md.comp.input-chip.with-trailing-icon.disabled.trailing-icon.color": "onSurface", - "md.comp.input-chip.disabled.label-text.opacity": 0.38, - "md.comp.input-chip.disabled.label-text.color": "onSurface", - "md.comp.input-chip.disabled.outline.opacity": 0.12, - "md.comp.input-chip.disabled.outline.color": "onSurface", - "md.comp.input-chip.with-avatar.avatar.size": { - "value": 24.0, - "units": "DIPS" - }, - "md.comp.input-chip.with-leading-icon.leading-icon.color": "onSurfaceVariant", - "md.comp.input-chip.with-leading-icon.leading-icon.size": { - "value": 18.0, - "units": "DIPS" - }, - "md.comp.input-chip.with-trailing-icon.trailing-icon.size": { - "value": 18.0, - "units": "DIPS" - }, - "md.comp.input-chip.label-text.color": "onSurfaceVariant", - "md.comp.input-chip.outline.width": { - "value": 1.0, - "units": "DIPS" - }, - "md.comp.input-chip.outline.color": "outline", - "md.comp.input-chip.container.elevation": "md.sys.elevation.level0", - "md.comp.input-chip.container.height": { - "value": 32.0, - "units": "DIPS" - }, - "md.comp.suggestion-chip.container.shape": "md.sys.shape.corner.small", - "md.comp.suggestion-chip.container.surface-tint-layer.color": "md.sys.elevation.surface-tint-color", - "md.comp.suggestion-chip.label-text.tracking": "labelLarge", - "md.comp.suggestion-chip.label-text.weight": "labelLarge", - "md.comp.suggestion-chip.label-text.size": "labelLarge", - "md.comp.suggestion-chip.label-text.line-height": "labelLarge", - "md.comp.suggestion-chip.label-text.font": "labelLarge", - "md.comp.suggestion-chip.dragged.label-text.color": "onSurfaceVariant", - "md.comp.suggestion-chip.dragged.state-layer.color": "onSurfaceVariant", - "md.comp.suggestion-chip.pressed.label-text.color": "onSurfaceVariant", - "md.comp.suggestion-chip.pressed.state-layer.color": "onSurfaceVariant", - "md.comp.suggestion-chip.flat.focus.outline.color": "onSurfaceVariant", - "md.comp.suggestion-chip.focus.label-text.color": "onSurfaceVariant", - "md.comp.suggestion-chip.focus.state-layer.color": "onSurfaceVariant", - "md.comp.suggestion-chip.hover.label-text.color": "onSurfaceVariant", - "md.comp.suggestion-chip.hover.state-layer.color": "onSurfaceVariant", - "md.comp.suggestion-chip.dragged.state-layer.opacity": "md.sys.state.dragged.state-layer-opacity", - "md.comp.suggestion-chip.pressed.state-layer.opacity": "md.sys.state.pressed.state-layer-opacity", - "md.comp.suggestion-chip.focus.state-layer.opacity": "md.sys.state.focus.state-layer-opacity", - "md.comp.suggestion-chip.hover.state-layer.opacity": "md.sys.state.hover.state-layer-opacity", - "md.comp.suggestion-chip.label-text.type": "labelText", - "md.comp.suggestion-chip.dragged.container.elevation": "md.sys.elevation.level4", - "md.comp.suggestion-chip.elevated.pressed.container.elevation": "md.sys.elevation.level1", - "md.comp.suggestion-chip.elevated.focus.container.elevation": "md.sys.elevation.level1", - "md.comp.suggestion-chip.elevated.hover.container.elevation": "md.sys.elevation.level2", - "md.comp.suggestion-chip.elevated.disabled.container.opacity": 0.12, - "md.comp.suggestion-chip.elevated.disabled.container.color": "onSurface", - "md.comp.suggestion-chip.elevated.disabled.container.elevation": "md.sys.elevation.level0", - "md.comp.suggestion-chip.disabled.label-text.opacity": 0.38, - "md.comp.suggestion-chip.disabled.label-text.color": "onSurface", - "md.comp.suggestion-chip.flat.disabled.outline.opacity": 0.12, - "md.comp.suggestion-chip.flat.disabled.outline.color": "onSurface", - "md.comp.suggestion-chip.label-text.color": "onSurfaceVariant", - "md.comp.suggestion-chip.elevated.container.shadow-color": "shadow", - "md.comp.suggestion-chip.elevated.container.color": "surface", - "md.comp.suggestion-chip.elevated.container.elevation": "md.sys.elevation.level1", - "md.comp.suggestion-chip.flat.outline.width": { - "value": 1.0, - "units": "DIPS" - }, - "md.comp.suggestion-chip.flat.outline.color": "outline", - "md.comp.suggestion-chip.flat.container.elevation": "md.sys.elevation.level0", - "md.comp.suggestion-chip.container.height": { - "value": 32.0, - "units": "DIPS" - } -} diff --git a/dev/tools/gen_defaults/lib/fab_template.dart b/dev/tools/gen_defaults/lib/fab_template.dart deleted file mode 100644 index a5e7f7cab23c4..0000000000000 --- a/dev/tools/gen_defaults/lib/fab_template.dart +++ /dev/null @@ -1,90 +0,0 @@ -// 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 'template.dart'; - -class FABTemplate extends TokenTemplate { - const FABTemplate(String fileName, Map tokens) : super(fileName, tokens); - - @override - String generate() => ''' -// Generated version ${tokens["version"]}, ${tokens["date"]} -class _M3Defaults extends FloatingActionButtonThemeData { - _M3Defaults(this.context, this.type, this.hasChild) - : _colors = Theme.of(context).colorScheme, - _textTheme = Theme.of(context).textTheme; - - final BuildContext context; - final _FloatingActionButtonType type; - final bool hasChild; - final ColorScheme _colors; - final TextTheme _textTheme; - - bool get _isExtended => type == _FloatingActionButtonType.extended; - - @override Color? get foregroundColor => _colors.${color("md.comp.fab.primary.icon")}; - @override Color? get backgroundColor => _colors.${color("md.comp.fab.primary.container")}; - @override Color? get splashColor => _colors.${color("md.comp.fab.primary.pressed.state-layer")}; - @override double get elevation => ${elevation("md.comp.fab.primary.container")}; - @override Color? get focusColor => _colors.${color("md.comp.fab.primary.focus.state-layer")}; - @override double get focusElevation => ${elevation("md.comp.fab.primary.focus.container")}; - @override Color? get hoverColor => _colors.${color("md.comp.fab.primary.hover.state-layer")}; - @override double get hoverElevation => ${elevation("md.comp.fab.primary.hover.container")}; - @override double get highlightElevation => ${elevation("md.comp.fab.primary.pressed.container")}; - - @override - ShapeBorder? get shape { - switch (type) { - case _FloatingActionButtonType.regular: - return ${shape("md.comp.fab.primary.container.shape")}; - case _FloatingActionButtonType.small: - return ${shape("md.comp.fab.primary.small.container.shape")}; - case _FloatingActionButtonType.large: - return ${shape("md.comp.fab.primary.large.container.shape")}; - case _FloatingActionButtonType.extended: - return ${shape("md.comp.extended-fab.primary.container.shape")}; - } - } - - @override bool? get enableFeedback => true; - - @override - double? get iconSize { - switch (type) { - case _FloatingActionButtonType.regular: return ${value("md.comp.fab.primary.icon.size")}; - case _FloatingActionButtonType.small: return ${value("md.comp.fab.primary.small.icon.size")}; - case _FloatingActionButtonType.large: return ${value("md.comp.fab.primary.large.icon.size")}; - case _FloatingActionButtonType.extended: return ${value("md.comp.extended-fab.primary.icon.size")}; - } - } - - @override - BoxConstraints? get sizeConstraints => const BoxConstraints.tightFor( - width: ${value("md.comp.fab.primary.container.width")}, - height: ${value("md.comp.fab.primary.container.height")}, - ); - - @override - BoxConstraints? get smallSizeConstraints => const BoxConstraints.tightFor( - width: ${value("md.comp.fab.primary.small.container.width")}, - height: ${value("md.comp.fab.primary.small.container.height")}, - ); - - @override - BoxConstraints? get largeSizeConstraints => const BoxConstraints.tightFor( - width: ${value("md.comp.fab.primary.large.container.width")}, - height: ${value("md.comp.fab.primary.large.container.height")}, - ); - - @override - BoxConstraints? get extendedSizeConstraints => const BoxConstraints.tightFor( - height: ${value("md.comp.extended-fab.primary.container.height")}, - ); - - @override double? get extendedIconLabelSpacing => 8.0; - @override EdgeInsetsGeometry? get extendedPadding => EdgeInsetsDirectional.only(start: hasChild && _isExtended ? 16.0 : 20.0, end: 20.0); - @override TextStyle? get extendedTextStyle => _textTheme.${textStyle("md.comp.extended-fab.primary.label-text")}; -} -'''; -} diff --git a/dev/tools/gen_defaults/lib/template.dart b/dev/tools/gen_defaults/lib/template.dart deleted file mode 100644 index 587d4461aad80..0000000000000 --- a/dev/tools/gen_defaults/lib/template.dart +++ /dev/null @@ -1,91 +0,0 @@ -// 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:io'; - -abstract class TokenTemplate { - const TokenTemplate(this.fileName, this.tokens); - - static const String beginGeneratedComment = ''' - -// BEGIN GENERATED TOKEN PROPERTIES -'''; - - static const String headerComment = ''' - -// Generated code to the end of this file. Do not edit by hand. -// These defaults are generated from the Material Design Token -// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart. - -'''; - - static const String endGeneratedComment = ''' - -// END GENERATED TOKEN PROPERTIES -'''; - - final String fileName; - final Map tokens; - - /// Replace or append the contents of the file with the text from [generate]. - /// - /// If the file already contains generated block at the end, it will - /// be replaced by the [generate] output. Otherwise the content will - /// just be appended to the end of the file. - Future updateFile() async { - String contents = File(fileName).readAsStringSync(); - final int previousGeneratedIndex = contents.indexOf(beginGeneratedComment); - if (previousGeneratedIndex != -1) { - contents = contents.substring(0, previousGeneratedIndex); - } - final StringBuffer buffer = StringBuffer(contents); - buffer.write(beginGeneratedComment); - buffer.write(headerComment); - buffer.write(generate()); - buffer.write(endGeneratedComment); - File(fileName).writeAsStringSync(buffer.toString()); - } - - /// Provide the generated content for the template. - /// - /// This abstract method needs to be implemented by subclasses - /// to provide the content that [updateFile] will append to the - /// bottom of the file. - String generate(); - - String color(String tokenName) { - final String tokenColor = '$tokenName.color'; - final String tokenOpacity = '$tokenName.opacity'; - String value = '${tokens[tokenColor]!}'; - if (tokens.containsKey(tokenOpacity)) { - final String opacity = tokens[tokens[tokenOpacity]!]!.toString(); - value += '.withOpacity($opacity)'; - } - return value; - } - - String elevation(String tokenName) { - final String elevationName = '$tokenName.elevation'; - final Map elevationValue = tokens[tokens[elevationName]!]! as Map; - return elevationValue['value']!.toString(); - } - - String shape(String tokenName) { - // TODO(darrenaustin): handle more than just rounded rectangle shapes - final String shapeToken = tokens[tokenName]! as String; - final Map shape = tokens[shapeToken]! as Map; - final Map shapeValue = shape['value']! as Map; - return 'const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(${shapeValue['value']!})))'; - } - - String value(String tokenName) { - final Map value = tokens[tokenName]! as Map; - return value['value'].toString(); - } - - String textStyle(String tokenName) { - final String fontName = '$tokenName.font'; - return tokens[fontName]!.toString(); - } -} diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml deleted file mode 100644 index 0b51114fa201e..0000000000000 --- a/dev/tools/gen_defaults/pubspec.yaml +++ /dev/null @@ -1,60 +0,0 @@ -name: gen_defaults -description: A command line script to generate Material component defaults from the token database. -version: 1.0.0 - -environment: - sdk: ">=2.12.0-0 <3.0.0" - -dependencies: - -dev_dependencies: - path: 1.8.1 - test: 1.20.1 - - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - charcode: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - -# PUBSPEC CHECKSUM: 80de diff --git a/dev/tools/gen_defaults/test/gen_defaults_test.dart b/dev/tools/gen_defaults/test/gen_defaults_test.dart deleted file mode 100644 index 918241d564398..0000000000000 --- a/dev/tools/gen_defaults/test/gen_defaults_test.dart +++ /dev/null @@ -1,110 +0,0 @@ -// 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:io'; - -import 'package:gen_defaults/template.dart'; -import 'package:path/path.dart' as path; -import 'package:test/test.dart'; - -void main() { - test('Templates will append to the end of a file', () { - final Directory tempDir = Directory.systemTemp.createTempSync('gen_defaults'); - try { - // Create a temporary file with some content. - final File tempFile = File(path.join(tempDir.path, 'test_template.txt')); - tempFile.createSync(); - tempFile.writeAsStringSync(''' -// This is a file with stuff in it. -// This part shouldn't be changed by -// the template. -'''); - - // Have a test template append new parameterized content to the end of - // the file. - final Map tokens = {'foo': 'Foobar', 'bar': 'Barfoo'}; - TestTemplate(tempFile.path, tokens).updateFile(); - - expect(tempFile.readAsStringSync(), ''' -// This is a file with stuff in it. -// This part shouldn't be changed by -// the template. - -// BEGIN GENERATED TOKEN PROPERTIES - -// Generated code to the end of this file. Do not edit by hand. -// These defaults are generated from the Material Design Token -// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart. - -static final String tokenFoo = 'Foobar'; -static final String tokenBar = 'Barfoo'; - -// END GENERATED TOKEN PROPERTIES -'''); - - } finally { - tempDir.deleteSync(recursive: true); - } - }); - - test('Templates will update over previously generated code at the end of a file', () { - final Directory tempDir = Directory.systemTemp.createTempSync('gen_defaults'); - try { - // Create a temporary file with some content. - final File tempFile = File(path.join(tempDir.path, 'test_template.txt')); - tempFile.createSync(); - tempFile.writeAsStringSync(''' -// This is a file with stuff in it. -// This part shouldn't be changed by -// the template. - -// BEGIN GENERATED TOKEN PROPERTIES - -// Generated code to the end of this file. Do not edit by hand. -// These defaults are generated from the Material Design Token -// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart. - -static final String tokenFoo = 'Foobar'; -static final String tokenBar = 'Barfoo'; - -// END GENERATED TOKEN PROPERTIES -'''); - - // Have a test template append new parameterized content to the end of - // the file. - final Map tokens = {'foo': 'foo', 'bar': 'bar'}; - TestTemplate(tempFile.path, tokens).updateFile(); - - expect(tempFile.readAsStringSync(), ''' -// This is a file with stuff in it. -// This part shouldn't be changed by -// the template. - -// BEGIN GENERATED TOKEN PROPERTIES - -// Generated code to the end of this file. Do not edit by hand. -// These defaults are generated from the Material Design Token -// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart. - -static final String tokenFoo = 'foo'; -static final String tokenBar = 'bar'; - -// END GENERATED TOKEN PROPERTIES -'''); - - } finally { - tempDir.deleteSync(recursive: true); - } - }); -} - -class TestTemplate extends TokenTemplate { - TestTemplate(String fileName, Map tokens) : super(fileName, tokens); - - @override - String generate() => ''' -static final String tokenFoo = '${tokens['foo']}'; -static final String tokenBar = '${tokens['bar']}'; -'''; -} diff --git a/dev/tools/gen_keycodes/data/keyboard_key.tmpl b/dev/tools/gen_keycodes/data/keyboard_key.tmpl index 71dd1c6a95fdc..e0b8f0fb40119 100644 --- a/dev/tools/gen_keycodes/data/keyboard_key.tmpl +++ b/dev/tools/gen_keycodes/data/keyboard_key.tmpl @@ -46,11 +46,75 @@ abstract class KeyboardKey with Diagnosticable { /// look at the physical key to make sure that regardless of the character the /// key produces, you got the key that is in that location on the keyboard. /// -/// {@tool dartpad} +/// {@tool dartpad --template=stateful_widget_scaffold} /// This example shows how to detect if the user has selected the logical "Q" /// key. /// -/// ** See code in examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart ** +/// ```dart imports +/// import 'package:flutter/foundation.dart'; +/// import 'package:flutter/services.dart'; +/// ``` +/// +/// ```dart +/// // The node used to request the keyboard focus. +/// final FocusNode _focusNode = FocusNode(); +/// // The message to display. +/// String? _message; +/// +/// // Focus nodes need to be disposed. +/// @override +/// void dispose() { +/// _focusNode.dispose(); +/// super.dispose(); +/// } +/// +/// // Handles the key events from the RawKeyboardListener and update the +/// // _message. +/// void _handleKeyEvent(RawKeyEvent event) { +/// setState(() { +/// if (event.logicalKey == LogicalKeyboardKey.keyQ) { +/// _message = 'Pressed the "Q" key!'; +/// } else { +/// if (kReleaseMode) { +/// _message = 'Not a Q: Pressed 0x${event.logicalKey.keyId.toRadixString(16)}'; +/// } else { +/// // The debugName will only print useful information in debug mode. +/// _message = 'Not a Q: Pressed ${event.logicalKey.debugName}'; +/// } +/// } +/// }); +/// } +/// +/// @override +/// Widget build(BuildContext context) { +/// final TextTheme textTheme = Theme.of(context).textTheme; +/// return Container( +/// color: Colors.white, +/// alignment: Alignment.center, +/// child: DefaultTextStyle( +/// style: textTheme.headline4!, +/// child: RawKeyboardListener( +/// focusNode: _focusNode, +/// onKey: _handleKeyEvent, +/// child: AnimatedBuilder( +/// animation: _focusNode, +/// builder: (BuildContext context, Widget? child) { +/// if (!_focusNode.hasFocus) { +/// return GestureDetector( +/// onTap: () { +/// FocusScope.of(context).requestFocus(_focusNode); +/// }, +/// child: const Text('Tap to focus'), +/// ); +/// } +/// return Text(_message ?? 'Press a key'); +/// }, +/// ), +/// ), +/// ), +/// ); +/// } +/// ``` /// {@end-tool} /// See also: /// @@ -254,9 +318,9 @@ class LogicalKeyboardKey extends KeyboardKey { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('keyId', '0x${keyId.toRadixString(16).padLeft(8, '0')}')); - properties.add(StringProperty('keyLabel', keyLabel)); - properties.add(StringProperty('debugName', debugName, defaultValue: null)); + properties.add(StringProperty('keyId', '0x${keyId.toRadixString(16).padLeft(8, '0')}', showName: true)); + properties.add(StringProperty('keyLabel', keyLabel, showName: true)); + properties.add(StringProperty('debugName', debugName, showName: true, defaultValue: null)); } @@@MASK_CONSTANTS@@@ @@ -301,11 +365,69 @@ class LogicalKeyboardKey extends KeyboardKey { /// looking for "the key next to the TAB key", since on a French keyboard, /// the key next to the TAB key has an "A" on it. /// -/// {@tool dartpad} +/// {@tool dartpad --template=stateful_widget_scaffold} /// This example shows how to detect if the user has selected the physical key /// to the right of the CAPS LOCK key. /// -/// ** See code in examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart ** +/// ```dart imports +/// import 'package:flutter/services.dart'; +/// ``` +/// +/// ```dart +/// // The node used to request the keyboard focus. +/// final FocusNode _focusNode = FocusNode(); +/// // The message to display. +/// String? _message; +/// +/// // Focus nodes need to be disposed. +/// @override +/// void dispose() { +/// _focusNode.dispose(); +/// super.dispose(); +/// } +/// +/// // Handles the key events from the RawKeyboardListener and update the +/// // _message. +/// void _handleKeyEvent(RawKeyEvent event) { +/// setState(() { +/// if (event.physicalKey == PhysicalKeyboardKey.keyA) { +/// _message = 'Pressed the key next to CAPS LOCK!'; +/// } else { +/// _message = 'Wrong key.'; +/// } +/// }); +/// } +/// +/// @override +/// Widget build(BuildContext context) { +/// final TextTheme textTheme = Theme.of(context).textTheme; +/// return Container( +/// color: Colors.white, +/// alignment: Alignment.center, +/// child: DefaultTextStyle( +/// style: textTheme.headline4!, +/// child: RawKeyboardListener( +/// focusNode: _focusNode, +/// onKey: _handleKeyEvent, +/// child: AnimatedBuilder( +/// animation: _focusNode, +/// builder: (BuildContext context, Widget? child) { +/// if (!_focusNode.hasFocus) { +/// return GestureDetector( +/// onTap: () { +/// FocusScope.of(context).requestFocus(_focusNode); +/// }, +/// child: const Text('Tap to focus'), +/// ); +/// } +/// return Text(_message ?? 'Press a key'); +/// }, +/// ), +/// ), +/// ), +/// ); +/// } +/// ``` /// {@end-tool} /// /// See also: @@ -361,8 +483,8 @@ class PhysicalKeyboardKey extends KeyboardKey { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty('usbHidUsage', '0x${usbHidUsage.toRadixString(16).padLeft(8, '0')}')); - properties.add(StringProperty('debugName', debugName, defaultValue: null)); + properties.add(StringProperty('usbHidUsage', '0x${usbHidUsage.toRadixString(16).padLeft(8, '0')}', showName: true)); + properties.add(StringProperty('debugName', debugName, showName: true, defaultValue: null)); } // Key constants for all keyboard keys in the USB HID specification at the diff --git a/dev/tools/gen_keycodes/data/logical_key_data.json b/dev/tools/gen_keycodes/data/logical_key_data.json index 49c589621be14..1143b52e92cab 100644 --- a/dev/tools/gen_keycodes/data/logical_key_data.json +++ b/dev/tools/gen_keycodes/data/logical_key_data.json @@ -3075,9 +3075,6 @@ "gtk": [ "3270_PrintScreen" ], - "windows": [ - "SNAPSHOT" - ], "android": [ "SYSRQ" ], @@ -3089,9 +3086,6 @@ "gtk": [ 64797 ], - "windows": [ - 44 - ], "android": [ 120 ], diff --git a/dev/tools/gen_keycodes/data/physical_key_data.json b/dev/tools/gen_keycodes/data/physical_key_data.json index 1f0c526afa9a3..df368694450e4 100644 --- a/dev/tools/gen_keycodes/data/physical_key_data.json +++ b/dev/tools/gen_keycodes/data/physical_key_data.json @@ -80,17 +80,6 @@ "xkb": 641 } }, - "MicrophoneMuteToggle": { - "names": { - "name": "MicrophoneMuteToggle", - "chromium": "MicrophoneMuteToggle" - }, - "scanCodes": { - "usb": 24, - "linux": 248, - "xkb": 256 - } - }, "Sleep": { "names": { "name": "Sleep", diff --git a/dev/tools/gen_keycodes/data/windows_logical_to_window_vk.json b/dev/tools/gen_keycodes/data/windows_logical_to_window_vk.json index 5ab26b25e845d..5d8b68d7f8204 100644 --- a/dev/tools/gen_keycodes/data/windows_logical_to_window_vk.json +++ b/dev/tools/gen_keycodes/data/windows_logical_to_window_vk.json @@ -27,6 +27,7 @@ "Select": ["SELECT"], "Print": ["PRINT"], "Execute": ["EXECUTE"], + "Snapshot": ["SNAPSHOT"], "Insert": ["INSERT"], "Delete": ["DELETE"], "Help": ["HELP"], @@ -35,7 +36,6 @@ "ContextMenu": ["APPS"], "PageDown": ["NEXT"], "PageUp": ["PRIOR"], - "PrintScreen": ["SNAPSHOT"], "Numpad0": ["NUMPAD0"], "Numpad1": ["NUMPAD1"], "Numpad2": ["NUMPAD2"], diff --git a/dev/tools/gen_keycodes/lib/logical_key_data.dart b/dev/tools/gen_keycodes/lib/logical_key_data.dart index a7d0d72843e2e..7a40e21b6785a 100644 --- a/dev/tools/gen_keycodes/lib/logical_key_data.dart +++ b/dev/tools/gen_keycodes/lib/logical_key_data.dart @@ -387,7 +387,7 @@ class LogicalKeyData { } // Map Web key to the pair of key names - static final Map _chromeModifiers = () { + static late final Map _chromeModifiers = () { final String rawJson = File(path.join(dataRoot, 'chromium_modifiers.json',)).readAsStringSync(); return (json.decode(rawJson) as Map).map((String key, dynamic value) { final List pair = value as List; @@ -396,7 +396,7 @@ class LogicalKeyData { }(); /// Returns the static map of printable representations. - static final Map printable = (() { + static late final Map printable = (() { final String printableKeys = File(path.join(dataRoot, 'printable.json',)).readAsStringSync(); return (json.decode(printableKeys) as Map) .cast(); @@ -407,7 +407,7 @@ class LogicalKeyData { /// These include synonyms for keys which don't have printable /// representations, and appear in more than one place on the keyboard (e.g. /// SHIFT, ALT, etc.). - static final Map> synonyms = (() { + static late final Map> synonyms = (() { final String synonymKeys = File(path.join(dataRoot, 'synonyms.json',)).readAsStringSync(); final Map dynamicSynonym = json.decode(synonymKeys) as Map; return dynamicSynonym.map((String name, dynamic values) { diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index f2521f962e8b5..38a61315b5ffe 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -8,8 +8,8 @@ dependencies: args: 2.3.0 http: 0.13.4 meta: 1.7.0 - path: 1.8.1 - platform: 3.1.0 + path: 1.8.0 + platform: 3.0.2 async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" charcode: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,11 +21,11 @@ dependencies: typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.20.1 - test_api: 0.4.9 + test: 1.17.12 + test_api: 0.4.3 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,12 +36,13 @@ dev_dependencies: glob: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,11 +53,11 @@ dev_dependencies: source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 37d3 +# PUBSPEC CHECKSUM: 8c9b diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 1cd90edd7e8dc..84b831fb07092 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -5,12 +5,12 @@ environment: sdk: ">=2.13.0 <3.0.0" dependencies: - archive: 3.1.8 + archive: 3.1.6 args: 2.3.0 http: 0.13.4 intl: 0.17.0 meta: 1.7.0 - path: 1.8.1 + path: 1.8.0 process: 4.2.4 async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -20,18 +20,18 @@ dependencies: crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.20.1 - test_api: 0.4.9 + test: 1.17.12 + test_api: 0.4.3 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -40,12 +40,13 @@ dev_dependencies: glob: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,11 +57,11 @@ dev_dependencies: source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 5cee +# PUBSPEC CHECKSUM: c9b4 diff --git a/dev/tools/test/update_icons_test.dart b/dev/tools/test/update_icons_test.dart deleted file mode 100644 index a24a5f658ffe3..0000000000000 --- a/dev/tools/test/update_icons_test.dart +++ /dev/null @@ -1,39 +0,0 @@ -// 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 'package:test/test.dart'; - -import '../update_icons.dart'; - -Map codepointsA = { - 'airplane': '111', - 'boat': '222', -}; -Map codepointsB = { - 'airplane': '333', -}; -Map codepointsC = { - 'airplane': '111', - 'train': '444', -}; - -void main() { - group('safety checks', () { - test('superset', () { - expect(testIsSuperset(codepointsA, codepointsA), true); - - expect(testIsSuperset(codepointsA, codepointsB), true); - expect(testIsSuperset(codepointsB, codepointsA), false); - }); - test('stability', () { - expect(testIsStable(codepointsA, codepointsA), true); - - expect(testIsStable(codepointsA, codepointsB), false); - expect(testIsStable(codepointsB, codepointsA), false); - - expect(testIsStable(codepointsA, codepointsC), true); - expect(testIsStable(codepointsC, codepointsA), true); - }); - }); -} diff --git a/dev/tools/update_icons.dart b/dev/tools/update_icons.dart index 539aa35911388..33cb323c493b8 100644 --- a/dev/tools/update_icons.dart +++ b/dev/tools/update_icons.dart @@ -10,21 +10,16 @@ import 'dart:convert' show LineSplitter; import 'dart:io'; import 'package:args/args.dart'; -import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; -const String _iconsPathOption = 'icons'; -const String _iconsTemplatePathOption = 'icons-template'; const String _newCodepointsPathOption = 'new-codepoints'; const String _oldCodepointsPathOption = 'old-codepoints'; -const String _fontFamilyOption = 'font-family'; -const String _enforceSafetyChecks = 'enforce-safety-checks'; +const String _iconsClassPathOption = 'icons'; const String _dryRunOption = 'dry-run'; -const String _defaultIconsPath = 'packages/flutter/lib/src/material/icons.dart'; const String _defaultNewCodepointsPath = 'codepoints'; const String _defaultOldCodepointsPath = 'bin/cache/artifacts/material_fonts/codepoints'; -const String _defaultFontFamily = 'MaterialIcons'; +const String _defaultIconsPath = 'packages/flutter/lib/src/material/icons.dart'; const String _beginGeneratedMark = '// BEGIN GENERATED ICONS'; const String _endGeneratedMark = '// END GENERATED ICONS'; @@ -43,37 +38,36 @@ const Map> _platformAdaptiveIdentifiers = identifierPrefixRewrites = { - '1': 'one_', - '2': 'two_', - '3': 'three_', - '4': 'four_', - '5': 'five_', - '6': 'six_', - '7': 'seven_', - '8': 'eight_', - '9': 'nine_', - '10': 'ten_', - '11': 'eleven_', - '12': 'twelve_', - '13': 'thirteen_', - '14': 'fourteen_', - '15': 'fifteen_', - '16': 'sixteen_', - '17': 'seventeen_', - '18': 'eighteen_', - '19': 'nineteen_', - '20': 'twenty_', - '21': 'twenty_one_', - '22': 'twenty_two_', - '23': 'twenty_three_', - '24': 'twenty_four_', - '30': 'thirty_', - '60': 'sixty_', - '123': 'onetwothree', - '360': 'threesixty', - '2d': 'twod', - '3d': 'threed', - '3d_rotation': 'threed_rotation', + '_1': 'one_', + '_2': 'two_', + '_3': 'three_', + '_4': 'four_', + '_5': 'five_', + '_6': 'six_', + '_7': 'seven_', + '_8': 'eight_', + '_9': 'nine_', + '_10': 'ten_', + '_11': 'eleven_', + '_12': 'twelve_', + '_13': 'thirteen_', + '_14': 'fourteen_', + '_15': 'fifteen_', + '_16': 'sixteen_', + '_17': 'seventeen_', + '_18': 'eighteen_', + '_19': 'nineteen_', + '_20': 'twenty_', + '_21': 'twenty_one_', + '_22': 'twenty_two_', + '_23': 'twenty_three_', + '_24': 'twenty_four_', + '_30': 'thirty_', + '_60': 'sixty_', + '_360': 'threesixty', + '_2d': 'twod', + '_3d': 'threed', + '_3d_rotation': 'threed_rotation', }; // Rewrite certain Flutter IDs (reserved keywords) using exact matching. @@ -169,14 +163,9 @@ void main(List args) { final ArgResults argResults = _handleArguments(args); - final File iconsFile = File(path.normalize(path.absolute(argResults[_iconsPathOption] as String))); - if (!iconsFile.existsSync()) { - stderr.writeln('Error: Icons file not found: ${iconsFile.path}'); - exit(1); - } - final File iconsTemplateFile = File(path.normalize(path.absolute(argResults[_iconsTemplatePathOption] as String))); - if (!iconsTemplateFile.existsSync()) { - stderr.writeln('Error: Icons template file not found: ${iconsTemplateFile.path}'); + final File iconClassFile = File(path.normalize(path.absolute(argResults[_iconsClassPathOption] as String))); + if (!iconClassFile.existsSync()) { + stderr.writeln('Error: Icons file not found: ${iconClassFile.path}'); exit(1); } final File newCodepointsFile = File(argResults[_newCodepointsPathOption] as String); @@ -196,51 +185,33 @@ void main(List args) { final String oldCodepointsString = oldCodepointsFile.readAsStringSync(); final Map oldTokenPairMap = _stringToTokenPairMap(oldCodepointsString); - stderr.writeln('Performing safety checks'); - final bool isSuperset = testIsSuperset(newTokenPairMap, oldTokenPairMap); - final bool isStable = testIsStable(newTokenPairMap, oldTokenPairMap); - if ((!isSuperset || !isStable) && argResults[_enforceSafetyChecks] as bool) { - exit(1); - } - final String iconsTemplateContents = iconsTemplateFile.readAsStringSync(); + _testIsMapSuperset(newTokenPairMap, oldTokenPairMap); + + final String iconClassFileData = iconClassFile.readAsStringSync(); - stderr.writeln("Generating icons ${argResults[_dryRunOption] as bool ? '' : 'to ${iconsFile.path}'}"); - final String newIconsContents = _regenerateIconsFile( - iconsTemplateContents, - newTokenPairMap, - argResults[_fontFamilyOption] as String, - argResults[_enforceSafetyChecks] as bool, - ); + stderr.writeln('Generating icons file...'); + final String newIconData = _regenerateIconsFile(iconClassFileData, newTokenPairMap); if (argResults[_dryRunOption] as bool) { - stdout.write(newIconsContents); + stdout.write(newIconData); } else { - iconsFile.writeAsStringSync(newIconsContents); + stderr.writeln('\nWriting to ${iconClassFile.path}.'); + iconClassFile.writeAsStringSync(newIconData); _regenerateCodepointsFile(oldCodepointsFile, newTokenPairMap); } } ArgResults _handleArguments(List args) { final ArgParser argParser = ArgParser() - ..addOption(_iconsPathOption, - defaultsTo: _defaultIconsPath, - help: 'Location of the material icons file') - ..addOption(_iconsTemplatePathOption, - defaultsTo: _defaultIconsPath, - help: - 'Location of the material icons file template. Usually the same as --$_iconsPathOption') ..addOption(_newCodepointsPathOption, defaultsTo: _defaultNewCodepointsPath, help: 'Location of the new codepoints directory') ..addOption(_oldCodepointsPathOption, defaultsTo: _defaultOldCodepointsPath, help: 'Location of the existing codepoints directory') - ..addOption(_fontFamilyOption, - defaultsTo: _defaultFontFamily, - help: 'The font family to use for the IconData constants') - ..addFlag(_enforceSafetyChecks, - defaultsTo: true, - help: 'Whether to exit if safety checks fail (e.g. codepoints are missing or unstable') + ..addOption(_iconsClassPathOption, + defaultsTo: _defaultIconsPath, + help: 'Location of the material icons file') ..addFlag(_dryRunOption); argParser.addFlag('help', abbr: 'h', negatable: false, callback: (bool help) { if (help) { @@ -256,7 +227,7 @@ Map _stringToTokenPairMap(String codepointData) { .map((String line) => line.trim()) .where((String line) => line.isNotEmpty); - final Map pairs = {}; + final Map pairs = {}; for (final String line in cleanData) { final List tokens = line.split(' '); @@ -269,49 +240,40 @@ Map _stringToTokenPairMap(String codepointData) { return pairs; } -String _regenerateIconsFile( - String templateFileContents, - Map tokenPairMap, - String fontFamily, - bool enforceSafetyChecks, - ) { +String _regenerateIconsFile(String iconData, Map tokenPairMap) { final List<_Icon> newIcons = tokenPairMap.entries - .map((MapEntry entry) => _Icon(entry, fontFamily)) + .map((MapEntry entry) => _Icon(entry)) .toList(); newIcons.sort((_Icon a, _Icon b) => a._compareTo(b)); final StringBuffer buf = StringBuffer(); bool generating = false; - for (final String line in LineSplitter.split(templateFileContents)) { + for (final String line in LineSplitter.split(iconData)) { if (!generating) { buf.writeln(line); } - // Generate for PlatformAdaptiveIcons + // Generate for _PlatformAdaptiveIcons if (line.contains(_beginPlatformAdaptiveGeneratedMark)) { generating = true; final List platformAdaptiveDeclarations = []; _platformAdaptiveIdentifiers.forEach((String flutterId, List ids) { - // Automatically finds and generates all icon declarations. + // Automatically finds and generates styled icon declarations. for (final String style in ['', '_outlined', '_rounded', '_sharp']) { try { final _Icon agnosticIcon = newIcons.firstWhere( - (_Icon icon) => icon.id == '${ids[0]}$style', + (_Icon icon) => icon.id == '${ids[0]}$style', orElse: () => throw ids[0]); final _Icon iOSIcon = newIcons.firstWhere( - (_Icon icon) => icon.id == '${ids[1]}$style', + (_Icon icon) => icon.id == '${ids[1]}$style', orElse: () => throw ids[1]); - platformAdaptiveDeclarations.add(_Icon.platformAdaptiveDeclaration('$flutterId$style', agnosticIcon, iOSIcon), - ); + platformAdaptiveDeclarations.add(_Icon.platformAdaptiveDeclaration('$flutterId$style', agnosticIcon, iOSIcon)); } catch (e) { if (style == '') { - // Throw an error for baseline icons. - stderr.writeln("❌ Platform adaptive icon '$e' not found."); - if (enforceSafetyChecks) { - stderr.writeln('Safety checks failed'); - exit(1); - } + // Throw an error for regular (unstyled) icons. + stderr.writeln("Error while generating platformAdaptiveDeclarations: Icon '$e' not found."); + exit(1); } else { // Ignore errors for styled icons since some don't exist. } @@ -337,50 +299,28 @@ String _regenerateIconsFile( return buf.toString(); } -@visibleForTesting -bool testIsSuperset(Map newCodepoints, Map oldCodepoints) { +void _testIsMapSuperset(Map newCodepoints, Map oldCodepoints) { final Set newCodepointsSet = newCodepoints.keys.toSet(); final Set oldCodepointsSet = oldCodepoints.keys.toSet(); - final int diff = newCodepointsSet.length - oldCodepointsSet.length; - if (diff > 0) { - stderr.writeln('🆕 $diff new codepoints: ${newCodepointsSet.difference(oldCodepointsSet)}'); - } if (!newCodepointsSet.containsAll(oldCodepointsSet)) { - stderr.writeln( - '❌ new codepoints file does not contain all ${oldCodepointsSet.length} ' - 'existing codepoints. Missing: ${oldCodepointsSet.difference(newCodepointsSet)}'); - return false; + stderr.writeln(''' +Error: New codepoints file does not contain all ${oldCodepointsSet.length} existing codepoints.\n + Missing: ${oldCodepointsSet.difference(newCodepointsSet)} + ''', + ); + exit(1); } else { - stderr.writeln('✅ new codepoints file contains all ${oldCodepointsSet.length} existing codepoints'); - } - return true; -} - -@visibleForTesting -bool testIsStable(Map newCodepoints, Map oldCodepoints) { - final int oldCodepointsCount = oldCodepoints.length; - final List unstable = []; - - oldCodepoints.forEach((String key, String value) { - if (newCodepoints.containsKey(key)) { - if (value != newCodepoints[key]) { - unstable.add(key); - } + final int diff = newCodepointsSet.length - oldCodepointsSet.length; + stderr.writeln('New codepoints file contains all ${oldCodepointsSet.length} existing codepoints.'); + if (diff > 0) { + stderr.writeln('It also contains $diff new codepoints: ${newCodepointsSet.difference(oldCodepointsSet)}'); } - }); - - if (unstable.isNotEmpty) { - stderr.writeln('❌ out of $oldCodepointsCount existing codepoints, ${unstable.length} were unstable: $unstable'); - return false; - } else { - stderr.writeln('✅ all existing $oldCodepointsCount codepoints are stable'); - return true; } } void _regenerateCodepointsFile(File oldCodepointsFile, Map newTokenPairMap) { - stderr.writeln('Regenerating old codepoints file ${oldCodepointsFile.path}'); + stderr.writeln('Regenerating old codepoints file ${oldCodepointsFile.path}.\n'); final StringBuffer buf = StringBuffer(); final SplayTreeMap sortedNewTokenPairMap = SplayTreeMap.of(newTokenPairMap); @@ -390,7 +330,7 @@ void _regenerateCodepointsFile(File oldCodepointsFile, Map newTo class _Icon { // Parse tokenPair (e.g. {"6_ft_apart_outlined": "e004"}). - _Icon(MapEntry tokenPair, this.fontFamily) { + _Icon(MapEntry tokenPair) { id = tokenPair.key; hexCodepoint = tokenPair.value; @@ -409,15 +349,14 @@ class _Icon { htmlSuffix = '-filled'; } else { family = 'material'; - if (id.endsWith('_baseline')) { - id = _removeLast(id, '_baseline'); - htmlSuffix = ''; - } else if (id.endsWith('_outlined')) { + if (id.endsWith('_outlined') && id != 'insert_chart_outlined') { htmlSuffix = '-outlined'; } else if (id.endsWith('_rounded')) { htmlSuffix = '-round'; } else if (id.endsWith('_sharp')) { htmlSuffix = '-sharp'; + } else { + htmlSuffix = ''; } } @@ -440,8 +379,7 @@ class _Icon { late String flutterId; // e.g. five_g, five_g_outlined, five_g_rounded, five_g_sharp late String family; // e.g. material late String hexCodepoint; // e.g. e547 - late String htmlSuffix = ''; // The suffix for the 'material-icons' HTML class. - String fontFamily; // The IconData font family. + late String htmlSuffix; // The suffix for the 'material-icons' HTML class. String get name => shortId.replaceAll('_', ' ').trim(); @@ -455,7 +393,7 @@ class _Icon { : ''; String get declaration => - "static const IconData $flutterId = IconData(0x$hexCodepoint, fontFamily: '$fontFamily'$mirroredInRTL);"; + "static const IconData $flutterId = IconData(0x$hexCodepoint, fontFamily: 'MaterialIcons'$mirroredInRTL);"; String get fullDeclaration => ''' @@ -481,14 +419,16 @@ class _Icon { return shortId.compareTo(b.shortId); } - static String _removeLast(String string, String toReplace) { + static String _replaceLast(String string, String toReplace) { return string.replaceAll(RegExp('$toReplace\$'), ''); } static String _generateShortId(String id) { String shortId = id; for (final String styleSuffix in _idSuffixes) { - shortId = _removeLast(shortId, styleSuffix); + if (styleSuffix == '_outlined' && id == 'insert_chart_outlined') + continue; + shortId = _replaceLast(shortId, styleSuffix); if (shortId != id) { break; } @@ -500,22 +440,22 @@ class _Icon { static String generateFlutterId(String id) { String flutterId = id; // Exact identifier rewrites. - for (final MapEntry rewritePair in identifierExactRewrites.entries) { + for (final MapEntry rewritePair + in identifierExactRewrites.entries) { final String shortId = _Icon._generateShortId(id); if (shortId == rewritePair.key) { - flutterId = id.replaceFirst( - rewritePair.key, - identifierExactRewrites[rewritePair.key]!, - ); + flutterId = id.replaceFirst(rewritePair.key, identifierExactRewrites[rewritePair.key]!); } } // Prefix identifier rewrites. - for (final MapEntry rewritePair in identifierPrefixRewrites.entries) { + for (final MapEntry rewritePair + in identifierPrefixRewrites.entries) { if (id.startsWith(rewritePair.key)) { - flutterId = id.replaceFirst( - rewritePair.key, - identifierPrefixRewrites[rewritePair.key]!, - ); + flutterId = id.replaceFirst(rewritePair.key, identifierPrefixRewrites[rewritePair.key]!); + } + // TODO(guidezpl): With the next icon update, this won't be necessary, remove it. + if (id.startsWith(rewritePair.key.replaceFirst('_', ''))) { + flutterId = id.replaceFirst(rewritePair.key.replaceFirst('_', ''), identifierPrefixRewrites[rewritePair.key]!); } } return flutterId; diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index 330462183c63f..1cac54981df9c 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -15,7 +15,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" petitparser: 4.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,12 +29,12 @@ dev_dependencies: clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ab23 +# PUBSPEC CHECKSUM: 74be diff --git a/dev/tracing_tests/README.md b/dev/tracing_tests/README.md index b09135a9f5e30..9801c105925a3 100644 --- a/dev/tracing_tests/README.md +++ b/dev/tracing_tests/README.md @@ -1,16 +1,5 @@ # Tracing tests -## "Application" - -The `lib/test.dart` and `lib/control.dart` files in this directory are -used by `dev/bots/test.dart`'s `runTracingTests` function to check -whether aspects of the tracing logic in the framework get compiled out -in profile and release builds. They're not meant to be run directly. - -The strings in these files are used in `dev/bots/test.dart`. - -## Tests - The tests in this folder must be run with `flutter test --enable-vmservice`, since they test that trace data is written to the timeline by connecting to the observatory. diff --git a/dev/tracing_tests/android/.gitignore b/dev/tracing_tests/android/.gitignore deleted file mode 100644 index 6f568019d3c69..0000000000000 --- a/dev/tracing_tests/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -**/*.keystore -**/*.jks diff --git a/dev/tracing_tests/android/app/build.gradle b/dev/tracing_tests/android/app/build.gradle deleted file mode 100644 index ad537193a0302..0000000000000 --- a/dev/tracing_tests/android/app/build.gradle +++ /dev/null @@ -1,72 +0,0 @@ -// 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. - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion flutter.compileSdkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.tracing_tests" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/dev/tracing_tests/android/app/src/debug/AndroidManifest.xml b/dev/tracing_tests/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index f628cb7d7e02d..0000000000000 --- a/dev/tracing_tests/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/dev/tracing_tests/android/app/src/main/AndroidManifest.xml b/dev/tracing_tests/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index dab8bc6b077a4..0000000000000 --- a/dev/tracing_tests/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/dev/tracing_tests/android/app/src/main/kotlin/com/example/tracing_tests/MainActivity.kt b/dev/tracing_tests/android/app/src/main/kotlin/com/example/tracing_tests/MainActivity.kt deleted file mode 100644 index a44690912cade..0000000000000 --- a/dev/tracing_tests/android/app/src/main/kotlin/com/example/tracing_tests/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.tracing_tests - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/dev/tracing_tests/android/app/src/main/res/drawable-v21/launch_background.xml b/dev/tracing_tests/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index 70e372f4ecb80..0000000000000 --- a/dev/tracing_tests/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - diff --git a/dev/tracing_tests/android/app/src/main/res/drawable/launch_background.xml b/dev/tracing_tests/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index bb6811b2ee10d..0000000000000 --- a/dev/tracing_tests/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - diff --git a/dev/tracing_tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/dev/tracing_tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/dev/tracing_tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/dev/tracing_tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/dev/tracing_tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/dev/tracing_tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/dev/tracing_tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/dev/tracing_tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/dev/tracing_tests/android/app/src/main/res/values-night/styles.xml b/dev/tracing_tests/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 60accd81dc42f..0000000000000 --- a/dev/tracing_tests/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - diff --git a/dev/tracing_tests/android/app/src/main/res/values/styles.xml b/dev/tracing_tests/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 8c276104923a5..0000000000000 --- a/dev/tracing_tests/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - diff --git a/dev/tracing_tests/android/app/src/profile/AndroidManifest.xml b/dev/tracing_tests/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index f628cb7d7e02d..0000000000000 --- a/dev/tracing_tests/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/dev/tracing_tests/android/build.gradle b/dev/tracing_tests/android/build.gradle deleted file mode 100644 index ccf18861d7795..0000000000000 --- a/dev/tracing_tests/android/build.gradle +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -buildscript { - ext.kotlin_version = '1.6.0' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/dev/tracing_tests/android/gradle.properties b/dev/tracing_tests/android/gradle.properties deleted file mode 100644 index 94adc3a3f97aa..0000000000000 --- a/dev/tracing_tests/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/dev/tracing_tests/android/settings.gradle b/dev/tracing_tests/android/settings.gradle deleted file mode 100644 index d3b6a4013d714..0000000000000 --- a/dev/tracing_tests/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -// 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. - -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/dev/tracing_tests/lib/control.dart b/dev/tracing_tests/lib/control.dart deleted file mode 100644 index c0c73f6173a65..0000000000000 --- a/dev/tracing_tests/lib/control.dart +++ /dev/null @@ -1,16 +0,0 @@ -// 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. - -// This file is part of dev/bots/test.dart's runTracingTests test. - -import 'package:flutter/foundation.dart'; - -void main() { - // This file is intended to be compiled in profile mode. - // In that mode, the function below throws an exception. - // The dev/bots/test.dart test looks for the string from that exception. - // The string below is matched verbatim in dev/bots/test.dart as a control - // to make sure this file did get compiled. - DiagnosticsNode.message('TIMELINE ARGUMENTS TEST CONTROL FILE').toTimelineArguments(); -} diff --git a/dev/tracing_tests/lib/test.dart b/dev/tracing_tests/lib/test.dart deleted file mode 100644 index d99d77b92d02c..0000000000000 --- a/dev/tracing_tests/lib/test.dart +++ /dev/null @@ -1,70 +0,0 @@ -// 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:developer'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/widgets.dart'; - -class TestWidget extends LeafRenderObjectWidget { - const TestWidget({ - Key? key, - }) : super(key: key); - - @override - RenderObject createRenderObject(BuildContext context) => RenderTest(); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - // This string is searched for verbatim by dev/bots/test.dart: - properties.add(MessageProperty('test', 'TestWidget.debugFillProperties called')); - } -} - -class RenderTest extends RenderBox { - @override - bool get sizedByParent => true; - - @override - void performResize() { - Timeline.instantSync('RenderTest.performResize called'); - size = constraints.biggest; - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - // This string is searched for verbatim by dev/bots/test.dart: - properties.add(MessageProperty('test', 'RenderTest.debugFillProperties called')); - } -} - - -Future main() async { - // This section introduces strings that we can search for in dev/bots/test.dart - // as a sanity check: - if (kDebugMode) { - print('BUILT IN DEBUG MODE'); - } - if (kProfileMode) { - print('BUILT IN PROFILE MODE'); - } - if (kReleaseMode) { - print('BUILT IN RELEASE MODE'); - } - - // The point of this file is to make sure that toTimelineArguments is not - // called when we have debugProfileBuildsEnabled (et al) turned on. If that - // method is not called then the debugFillProperties methods above should also - // not get called and we should end up tree-shaking the entire Diagnostics - // logic out of the app. The dev/bots/test.dart test checks for this by - // looking for the strings in the methods above. - - debugProfileBuildsEnabled = true; - debugProfileLayoutsEnabled = true; - debugProfilePaintsEnabled = true; - runApp(const TestWidget()); -} diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 9e74c312ddd01..013057b89e707 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -8,11 +8,10 @@ dependencies: flutter: sdk: flutter - vm_service: 7.5.0 + vm_service: 7.3.0 characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,12 +26,12 @@ dev_dependencies: clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c409 +# PUBSPEC CHECKSUM: 14a2 diff --git a/dev/tracing_tests/test/common.dart b/dev/tracing_tests/test/common.dart deleted file mode 100644 index 13b684ca4a442..0000000000000 --- a/dev/tracing_tests/test/common.dart +++ /dev/null @@ -1,34 +0,0 @@ -// 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:developer' as developer; -import 'dart:isolate' as isolate; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service/vm_service_io.dart'; - -export 'package:vm_service/vm_service.dart' show TimelineEvent; - -late String isolateId; - -late VmService _vmService; - -void initTimelineTests() { - setUpAll(() async { - final developer.ServiceProtocolInfo info = await developer.Service.getInfo(); - if (info.serverUri == null) { - fail('This test _must_ be run with --enable-vmservice.'); - } - _vmService = await vmServiceConnectUri('ws://localhost:${info.serverUri!.port}${info.serverUri!.path}ws'); - await _vmService.setVMTimelineFlags(['Dart']); - isolateId = developer.Service.getIsolateID(isolate.Isolate.current)!; - }); -} - -Future> fetchTimelineEvents() async { - final Timeline timeline = await _vmService.getVMTimeline(); - await _vmService.clearVMTimeline(); - return timeline.traceEvents!; -} diff --git a/dev/tracing_tests/test/image_cache_tracing_test.dart b/dev/tracing_tests/test/image_cache_tracing_test.dart index af99af6922464..524be6ca85b65 100644 --- a/dev/tracing_tests/test/image_cache_tracing_test.dart +++ b/dev/tracing_tests/test/image_cache_tracing_test.dart @@ -3,15 +3,31 @@ // found in the LICENSE file. import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:isolate' as isolate; import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; - -import 'common.dart'; +import 'package:vm_service/vm_service.dart'; +import 'package:vm_service/vm_service_io.dart'; void main() { - initTimelineTests(); - TestWidgetsFlutterBinding.ensureInitialized(); + late VmService vmService; + late String isolateId; + setUpAll(() async { + final developer.ServiceProtocolInfo info = await developer.Service.getInfo(); + + if (info.serverUri == null) { + fail('This test _must_ be run with --enable-vmservice.'); + } + + vmService = await vmServiceConnectUri('ws://localhost:${info.serverUri!.port}${info.serverUri!.path}ws'); + await vmService.setVMTimelineFlags(['Dart']); + isolateId = developer.Service.getIsolateID(isolate.Isolate.current)!; + + // Initialize the image cache. + TestWidgetsFlutterBinding.ensureInitialized(); + }); test('Image cache tracing', () async { final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); @@ -29,8 +45,9 @@ void main() { ); PaintingBinding.instance!.imageCache!.evict('Test2'); + final Timeline timeline = await vmService.getVMTimeline(); _expectTimelineEvents( - await fetchTimelineEvents(), + timeline.traceEvents!, >[ { 'name': 'ImageCache.putIfAbsent', diff --git a/dev/tracing_tests/test/timeline_test.dart b/dev/tracing_tests/test/timeline_test.dart deleted file mode 100644 index 567734ac3f708..0000000000000 --- a/dev/tracing_tests/test/timeline_test.dart +++ /dev/null @@ -1,155 +0,0 @@ -// 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 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'common.dart'; - -final Set interestingLabels = { - 'BUILD', - 'LAYOUT', - 'UPDATING COMPOSITING BITS', - 'PAINT', - 'COMPOSITING', - 'FINALIZE TREE', - '$Placeholder', - '$CustomPaint', - '$RenderCustomPaint', -}; - -Future> fetchInterestingEvents() async { - return (await fetchTimelineEvents()).where((TimelineEvent event) { - return interestingLabels.contains(event.json!['name']) - && event.json!['ph'] == 'B'; // "Begin" mark of events, vs E which is for the "End" mark of events. - }).toList(); -} - -String eventToName(TimelineEvent event) => event.json!['name'] as String; - -class TestRoot extends StatefulWidget { - const TestRoot({ Key? key }) : super(key: key); - - static late final TestRootState state; - - @override - State createState() => TestRootState(); -} - -class TestRootState extends State { - @override - void initState() { - super.initState(); - TestRoot.state = this; - } - - Widget _widget = const Placeholder(); - - void updateWidget(Widget newWidget) { - setState(() { - _widget = newWidget; - }); - } - - void rebuild() { - setState(() { - // no change, just force a rebuild - }); - } - - @override - Widget build(BuildContext context) { - return _widget; - } -} - -Future runFrame(VoidCallback callback) { - final Future result = SchedulerBinding.instance!.endOfFrame; // schedules a frame - callback(); - return result; -} - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - initTimelineTests(); - test('Timeline', () async { - // We don't have expectations around the first frame because there's a race around - // the warm-up frame that we don't want to get involved in here. - await runFrame(() { runApp(const TestRoot()); }); - await SchedulerBinding.instance!.endOfFrame; - await fetchInterestingEvents(); - - // The next few cases build the exact same tree so should have no effect. - - debugProfileBuildsEnabled = true; - await runFrame(() { TestRoot.state.rebuild(); }); - expect( - (await fetchInterestingEvents()).map(eventToName), - ['BUILD', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'], - ); - debugProfileBuildsEnabled = false; - - debugProfileLayoutsEnabled = true; - await runFrame(() { TestRoot.state.rebuild(); }); - expect( - (await fetchInterestingEvents()).map(eventToName), - ['BUILD', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'], - ); - debugProfileLayoutsEnabled = false; - - debugProfilePaintsEnabled = true; - await runFrame(() { TestRoot.state.rebuild(); }); - expect( - (await fetchInterestingEvents()).map(eventToName), - ['BUILD', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'], - ); - debugProfilePaintsEnabled = false; - - - // Now we replace the widgets each time to cause a rebuild. - - List events; - Map args; - - debugProfileBuildsEnabled = true; - await runFrame(() { TestRoot.state.updateWidget(Placeholder(key: UniqueKey(), color: const Color(0xFFFFFFFF))); }); - events = await fetchInterestingEvents(); - expect( - events.map(eventToName), - ['BUILD', 'Placeholder', 'CustomPaint', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'], - ); - args = (events.where((TimelineEvent event) => event.json!['name'] == '$Placeholder').single.json!['args'] as Map).cast(); - expect(args['color'], 'Color(0xffffffff)'); - debugProfileBuildsEnabled = false; - - debugProfileLayoutsEnabled = true; - await runFrame(() { TestRoot.state.updateWidget(Placeholder(key: UniqueKey())); }); - events = await fetchInterestingEvents(); - expect( - events.map(eventToName), - ['BUILD', 'LAYOUT', 'RenderCustomPaint', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'], - ); - args = (events.where((TimelineEvent event) => event.json!['name'] == '$RenderCustomPaint').single.json!['args'] as Map).cast(); - expect(args['creator'], startsWith('CustomPaint')); - expect(args['creator'], contains('Placeholder')); - expect(args['foregroundPainter'], startsWith('_PlaceholderPainter#')); - debugProfileLayoutsEnabled = false; - - debugProfilePaintsEnabled = true; - await runFrame(() { TestRoot.state.updateWidget(Placeholder(key: UniqueKey())); }); - events = await fetchInterestingEvents(); - expect( - events.map(eventToName), - ['BUILD', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'RenderCustomPaint', 'COMPOSITING', 'FINALIZE TREE'], - ); - args = (events.where((TimelineEvent event) => event.json!['name'] == '$RenderCustomPaint').single.json!['args'] as Map).cast(); - expect(args['creator'], startsWith('CustomPaint')); - expect(args['creator'], contains('Placeholder')); - expect(args['foregroundPainter'], startsWith('_PlaceholderPainter#')); - debugProfilePaintsEnabled = false; - - }, skip: isBrowser); // [intended] uses dart:isolate and io. -} diff --git a/examples/api/android/build.gradle b/examples/api/android/build.gradle index 8c8f28ccecd0f..05c070104b651 100644 --- a/examples/api/android/build.gradle +++ b/examples/api/android/build.gradle @@ -3,7 +3,7 @@ // found in the LICENSE file. buildscript { - ext.kotlin_version = '1.4.32' + ext.kotlin_version = '1.3.50' repositories { google() mavenCentral() diff --git a/examples/api/lib/cupertino/button/cupertino_button.0.dart b/examples/api/lib/cupertino/button/cupertino_button.0.dart deleted file mode 100644 index 6b82b26e393cf..0000000000000 --- a/examples/api/lib/cupertino/button/cupertino_button.0.dart +++ /dev/null @@ -1,57 +0,0 @@ -// 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. - -// Flutter code sample for CupertinoButton - -import 'package:flutter/cupertino.dart'; - -void main() => runApp(const MyApp()); - -class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); - - static const String _title = 'Flutter Code Sample'; - - @override - Widget build(BuildContext context) { - return const CupertinoApp( - title: _title, - home: MyStatelessWidget(), - ); - } -} - -class MyStatelessWidget extends StatelessWidget { - const MyStatelessWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const CupertinoButton( - onPressed: null, - child: Text('Disabled'), - ), - const SizedBox(height: 30), - const CupertinoButton.filled( - onPressed: null, - child: Text('Disabled'), - ), - const SizedBox(height: 30), - CupertinoButton( - onPressed: () {}, - child: const Text('Enabled'), - ), - const SizedBox(height: 30), - CupertinoButton.filled( - onPressed: () {}, - child: const Text('Enabled'), - ), - ], - ), - ); - } -} diff --git a/examples/api/lib/cupertino/date_picker/cupertino_date_picker.0.dart b/examples/api/lib/cupertino/date_picker/cupertino_date_picker.0.dart deleted file mode 100644 index 2763ae2408c7c..0000000000000 --- a/examples/api/lib/cupertino/date_picker/cupertino_date_picker.0.dart +++ /dev/null @@ -1,186 +0,0 @@ -// 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. - -// Flutter code sample for CupertinoDatePicker - -import 'package:flutter/cupertino.dart'; - -void main() => runApp(const MyApp()); - -class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); - - static const String _title = 'Flutter Code Sample'; - - @override - Widget build(BuildContext context) { - return const CupertinoApp( - title: _title, - home: MyStatelessWidget(), - ); - } -} - -class MyStatelessWidget extends StatefulWidget { - const MyStatelessWidget({Key? key}) : super(key: key); - - @override - State createState() => _MyStatelessWidgetState(); -} - -class _MyStatelessWidgetState extends State { - DateTime date = DateTime(2016, 10, 26); - DateTime time = DateTime(2016, 5, 10, 22, 35); - DateTime dateTime = DateTime(2016, 8, 3, 17, 45); - - // This shows a CupertinoModalPopup with a reasonable fixed height which hosts CupertinoDatePicker. - void _showDialog(Widget child) { - showCupertinoModalPopup( - context: context, - builder: (BuildContext context) => Container( - height: 216, - padding: const EdgeInsets.only(top: 6.0), - // The Bottom margin is provided to align the popup above the system navigation bar. - margin: EdgeInsets.only( - bottom: MediaQuery.of(context).viewInsets.bottom, - ), - // Provide a background color for the popup. - color: CupertinoColors.systemBackground.resolveFrom(context), - // Use a SafeArea widget to avoid system overlaps. - child: SafeArea( - top: false, - child: child, - ), - ) - ); - } - - @override - Widget build(BuildContext context) { - return CupertinoPageScaffold( - child: DefaultTextStyle( - style: TextStyle( - color: CupertinoColors.label.resolveFrom(context), - fontSize: 22.0, - ), - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _DatePickerItem( - children: [ - const Text('Date'), - CupertinoButton( - // Display a CupertinoDatePicker in date picker mode. - onPressed: () => _showDialog( - CupertinoDatePicker( - initialDateTime: date, - mode: CupertinoDatePickerMode.date, - use24hFormat: true, - // This is called when the user changes the date. - onDateTimeChanged: (DateTime newDate) { - setState(() => date = newDate); - }, - ), - ), - // In this example, the date value is formatted manually. You can use intl package - // to format the value based on user's locale settings. - child: Text('${date.month}-${date.day}-${date.year}', - style: const TextStyle( - fontSize: 22.0, - ), - ), - ), - ], - ), - _DatePickerItem( - children: [ - const Text('Time'), - CupertinoButton( - // Display a CupertinoDatePicker in time picker mode. - onPressed: () => _showDialog( - CupertinoDatePicker( - initialDateTime: time, - mode: CupertinoDatePickerMode.time, - use24hFormat: true, - // This is called when the user changes the time. - onDateTimeChanged: (DateTime newTime) { - setState(() => time = newTime); - }, - ), - ), - // In this example, the time value is formatted manually. You can use intl package to - // format the value based on the user's locale settings. - child: Text('${time.hour}:${time.minute}', - style: const TextStyle( - fontSize: 22.0, - ), - ), - ), - ], - ), - _DatePickerItem( - children: [ - const Text('DateTime'), - CupertinoButton( - // Display a CupertinoDatePicker in dateTime picker mode. - onPressed: () => _showDialog( - CupertinoDatePicker( - initialDateTime: dateTime, - use24hFormat: true, - // This is called when the user changes the dateTime. - onDateTimeChanged: (DateTime newDateTime) { - setState(() => dateTime = newDateTime); - }, - ), - ), - // In this example, time value is formatted manually. You can use intl package to - // format the value based on the user's locale settings. - child: Text('${dateTime.month}-${dateTime.day}-${dateTime.year} ${dateTime.hour}:${dateTime.minute}', - style: const TextStyle( - fontSize: 22.0, - ), - ), - ), - ], - ), - ], - ), - ), - ), - ); - } -} - -// This class simply decorates a row of widgets. -class _DatePickerItem extends StatelessWidget { - const _DatePickerItem({required this.children}); - - final List children; - - @override - Widget build(BuildContext context) { - return DecoratedBox( - decoration: const BoxDecoration( - border: Border( - top: BorderSide( - color: CupertinoColors.inactiveGray, - width: 0.0, - ), - bottom: BorderSide( - color: CupertinoColors.inactiveGray, - width: 0.0, - ), - ), - ), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: children, - ), - ), - ); - } -} diff --git a/examples/api/lib/material/chip/deletable_chip_attributes.on_deleted.0.dart b/examples/api/lib/material/chip/deletable_chip_attributes.on_deleted.0.dart index 757042694f5fb..67a6f6fb4c927 100644 --- a/examples/api/lib/material/chip/deletable_chip_attributes.on_deleted.0.dart +++ b/examples/api/lib/material/chip/deletable_chip_attributes.on_deleted.0.dart @@ -48,9 +48,9 @@ class CastListState extends State { const Actor('James Madison', 'JM'), ]; - Iterable get actorWidgets { - return _cast.map((Actor actor) { - return Padding( + Iterable get actorWidgets sync* { + for (final Actor actor in _cast) { + yield Padding( padding: const EdgeInsets.all(4.0), child: Chip( avatar: CircleAvatar(child: Text(actor.initials)), @@ -64,7 +64,7 @@ class CastListState extends State { }, ), ); - }); + } } @override diff --git a/examples/api/lib/material/ink/ink.image_clip.0.dart b/examples/api/lib/material/ink/ink.image_clip.0.dart deleted file mode 100644 index 1914a0dc2fc68..0000000000000 --- a/examples/api/lib/material/ink/ink.image_clip.0.dart +++ /dev/null @@ -1,55 +0,0 @@ -// 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. - -// Flutter code sample for Image.frameBuilder - -import 'package:flutter/material.dart'; - -void main() { - runApp(MaterialApp( - title: 'Flutter Code Sample', - home: Scaffold( - appBar: AppBar(title: const Text('Flutter Code Sample')), - body: const Center( - child: MyStatelessWidget( - image: NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/puffin.jpg'), - ), - ), - ), - )); -} - -class MyStatelessWidget extends StatelessWidget { - const MyStatelessWidget({Key? key, required this.image}) : super(key: key); - - final ImageProvider image; - - @override - Widget build(BuildContext context) { - return ClipRRect( - borderRadius: BorderRadius.circular(100), - child: Ink.image( - fit: BoxFit.fill, - width: 300, - height: 300, - image: image, - child: InkWell( - onTap: () {/* ... */}, - child: const Align( - child: Padding( - padding: EdgeInsets.all(10.0), - child: Text( - 'PUFFIN', - style: TextStyle( - fontWeight: FontWeight.w900, - color: Colors.white, - ), - ), - ), - ), - ), - ), - ); - } -} diff --git a/examples/api/lib/material/ink/ink.image_clip.1.dart b/examples/api/lib/material/ink/ink.image_clip.1.dart deleted file mode 100644 index 2cb0bf89145a1..0000000000000 --- a/examples/api/lib/material/ink/ink.image_clip.1.dart +++ /dev/null @@ -1,57 +0,0 @@ -// 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. - -// Flutter code sample for Image.frameBuilder - -import 'package:flutter/material.dart'; - -void main() { - runApp(MaterialApp( - title: 'Flutter Code Sample', - home: Scaffold( - appBar: AppBar(title: const Text('Flutter Code Sample')), - body: const Center( - child: MyStatelessWidget( - image: NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/puffin.jpg'), - ), - ), - ), - )); -} - -class MyStatelessWidget extends StatelessWidget { - const MyStatelessWidget({Key? key, required this.image}) : super(key: key); - - final ImageProvider image; - - @override - Widget build(BuildContext context) { - return ClipRRect( - borderRadius: BorderRadius.circular(100), - child: Material( - child: Ink.image( - fit: BoxFit.fill, - width: 300, - height: 300, - image: image, - child: InkWell( - onTap: () {/* ... */}, - child: const Align( - child: Padding( - padding: EdgeInsets.all(10.0), - child: Text( - 'PUFFIN', - style: TextStyle( - fontWeight: FontWeight.w900, - color: Colors.white, - ), - ), - ), - ), - ), - ), - ), - ); - } -} diff --git a/examples/api/lib/material/input_decorator/input_decoration.floating_label_style_error.0.dart b/examples/api/lib/material/input_decorator/input_decoration.floating_label_style_error.0.dart deleted file mode 100644 index 532b0d7171dc2..0000000000000 --- a/examples/api/lib/material/input_decorator/input_decoration.floating_label_style_error.0.dart +++ /dev/null @@ -1,58 +0,0 @@ -// 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. - -// Flutter code sample for InputDecorator - -import 'package:flutter/material.dart'; - -void main() => runApp(const MyApp()); - -class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); - - static const String _title = 'Flutter Code Sample'; - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: _title, - home: Scaffold( - appBar: AppBar(title: const Text(_title)), - body: const Center( - child: InputDecoratorExample(), - ), - ), - ); - } -} - -class InputDecoratorExample extends StatelessWidget { - const InputDecoratorExample({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return TextFormField( - decoration: InputDecoration( - border: const OutlineInputBorder(), - labelText: 'Name', - // The MaterialStateProperty's value is a text style that is orange - // by default, but the theme's error color if the input decorator - // is in its error state. - floatingLabelStyle: MaterialStateTextStyle.resolveWith( - (Set states) { - final Color color = states.contains(MaterialState.error) ? Theme.of(context).errorColor: Colors.orange; - return TextStyle(color: color, letterSpacing: 1.3); - } - ), - ), - validator: (String? value) { - if (value == null || value == '') { - return 'Enter name'; - } - return null; - }, - autovalidateMode: AutovalidateMode.always, - ); - } -} diff --git a/examples/api/lib/material/input_decorator/input_decoration.label_style_error.0.dart b/examples/api/lib/material/input_decorator/input_decoration.label_style_error.0.dart deleted file mode 100644 index c615bf04d6fd7..0000000000000 --- a/examples/api/lib/material/input_decorator/input_decoration.label_style_error.0.dart +++ /dev/null @@ -1,58 +0,0 @@ -// 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. - -// Flutter code sample for InputDecorator - -import 'package:flutter/material.dart'; - -void main() => runApp(const MyApp()); - -class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); - - static const String _title = 'Flutter Code Sample'; - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: _title, - home: Scaffold( - appBar: AppBar(title: const Text(_title)), - body: const Center( - child: InputDecoratorExample(), - ), - ), - ); - } -} - -class InputDecoratorExample extends StatelessWidget { - const InputDecoratorExample({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return TextFormField( - decoration: InputDecoration( - border: const OutlineInputBorder(), - labelText: 'Name', - // The MaterialStateProperty's value is a text style that is orange - // by default, but the theme's error color if the input decorator - // is in its error state. - labelStyle: MaterialStateTextStyle.resolveWith( - (Set states) { - final Color color = states.contains(MaterialState.error) ? Theme.of(context).errorColor: Colors.orange; - return TextStyle(color: color, letterSpacing: 1.3); - } - ), - ), - validator: (String? value) { - if (value == null || value == '') { - return 'Enter name'; - } - return null; - }, - autovalidateMode: AutovalidateMode.always, - ); - } -} diff --git a/examples/api/lib/material/reorderable_list/reorderable_list_view.0.dart b/examples/api/lib/material/reorderable_list/reorderable_list_view.0.dart index 38605cf2685b6..ff9bd683b258b 100644 --- a/examples/api/lib/material/reorderable_list/reorderable_list_view.0.dart +++ b/examples/api/lib/material/reorderable_list/reorderable_list_view.0.dart @@ -44,7 +44,7 @@ class _MyStatefulWidgetState extends State { return ReorderableListView( padding: const EdgeInsets.symmetric(horizontal: 40), children: [ - for (int index = 0; index < _items.length; index += 1) + for (int index = 0; index < _items.length; index++) ListTile( key: Key('$index'), tileColor: _items[index].isOdd ? oddItemColor : evenItemColor, diff --git a/examples/api/lib/material/reorderable_list/reorderable_list_view.1.dart b/examples/api/lib/material/reorderable_list/reorderable_list_view.1.dart deleted file mode 100644 index e1898b8220db5..0000000000000 --- a/examples/api/lib/material/reorderable_list/reorderable_list_view.1.dart +++ /dev/null @@ -1,85 +0,0 @@ -// 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. - -// Flutter code sample for ReorderableListView -import 'dart:ui'; - -import 'package:flutter/material.dart'; - -void main() => runApp(const MyApp()); - -class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); - - static const String _title = 'Flutter Code Sample'; - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: _title, - home: Scaffold( - appBar: AppBar(title: const Text(_title)), - body: const MyStatefulWidget(), - ), - ); - } -} - -class MyStatefulWidget extends StatefulWidget { - const MyStatefulWidget({Key? key}) : super(key: key); - - @override - State createState() => _MyStatefulWidgetState(); -} - -class _MyStatefulWidgetState extends State { - final List _items = List.generate(50, (int index) => index); - - @override - Widget build(BuildContext context) { - final ColorScheme colorScheme = Theme.of(context).colorScheme; - final Color oddItemColor = colorScheme.secondary.withOpacity(0.05); - final Color evenItemColor = colorScheme.secondary.withOpacity(0.15); - final Color draggableItemColor = colorScheme.secondary; - - Widget _proxyDecorator(Widget child, int index, Animation animation) { - return AnimatedBuilder( - animation: animation, - builder: (BuildContext context, Widget? child) { - final double animValue = Curves.easeInOut.transform(animation.value); - final double elevation = lerpDouble(0, 6, animValue)!; - return Material( - elevation: elevation, - color: draggableItemColor, - shadowColor: draggableItemColor, - child: child, - ); - }, - child: child, - ); - } - - return ReorderableListView( - padding: const EdgeInsets.symmetric(horizontal: 40), - proxyDecorator: _proxyDecorator, - children: [ - for (int index = 0; index < _items.length; index += 1) - ListTile( - key: Key('$index'), - tileColor: _items[index].isOdd ? oddItemColor : evenItemColor, - title: Text('Item ${_items[index]}'), - ), - ], - onReorder: (int oldIndex, int newIndex) { - setState(() { - if (oldIndex < newIndex) { - newIndex -= 1; - } - final int item = _items.removeAt(oldIndex); - _items.insert(newIndex, item); - }); - }, - ); - } -} diff --git a/examples/api/lib/services/mouse_cursor/mouse_cursor.0.dart b/examples/api/lib/services/mouse_cursor/mouse_cursor.0.dart deleted file mode 100644 index 6357d8d095d11..0000000000000 --- a/examples/api/lib/services/mouse_cursor/mouse_cursor.0.dart +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - -// Flutter code sample for MouseCursor - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - -void main() => runApp(const MyApp()); - -class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); - - static const String _title = 'MouseCursor Code Sample'; - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: _title, - home: Scaffold( - appBar: AppBar(title: const Text(_title)), - body: const MyStatelessWidget(), - ), - ); - } -} - -class MyStatelessWidget extends StatelessWidget { - const MyStatelessWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Center( - child: MouseRegion( - cursor: SystemMouseCursors.text, - child: Container( - width: 200, - height: 100, - decoration: BoxDecoration( - color: Colors.blue, - border: Border.all(color: Colors.yellow), - ), - ), - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.0.dart b/examples/api/lib/ui/text/font_feature.0.dart deleted file mode 100644 index 070333eb7e80b..0000000000000 --- a/examples/api/lib/ui/text/font_feature.0.dart +++ /dev/null @@ -1,79 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature -import 'dart:ui'; - -import 'package:flutter/material.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: ExampleWidget(), - ); - } -} - -final TextStyle titleStyle = TextStyle( - fontSize: 18, - fontFeatures: const [FontFeature.enable('smcp')], - color: Colors.blueGrey[600], -); - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Cardo, Milonga and Raleway Dots fonts can be downloaded from - // Google Fonts (https://www.google.com/fonts). - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Spacer(flex: 5), - Text('regular numbers have their place:', style: titleStyle), - const Text('The 1972 cup final was a 1-1 draw.', - style: TextStyle( - fontFamily: 'Cardo', - fontSize: 24, - )), - const Spacer(), - Text('but old-style figures blend well with lower case:', style: titleStyle), - const Text('The 1972 cup final was a 1-1 draw.', - style: TextStyle( - fontFamily: 'Cardo', fontSize: 24, fontFeatures: [FontFeature.oldstyleFigures()])), - const Spacer(), - const Divider(), - const Spacer(), - Text('fractions look better with a custom ligature:', style: titleStyle), - const Text('Add 1/2 tsp of flour and stir.', - style: TextStyle( - fontFamily: 'Milonga', - fontSize: 24, - fontFeatures: [FontFeature.alternativeFractions()])), - const Spacer(), - const Divider(), - const Spacer(), - Text('multiple stylistic sets in one font:', style: titleStyle), - const Text('Raleway Dots', style: TextStyle(fontFamily: 'Raleway Dots', fontSize: 48)), - Text('Raleway Dots', - style: TextStyle( - fontFeatures: [FontFeature.stylisticSet(1)], - fontFamily: 'Raleway Dots', - fontSize: 48, - )), - const Spacer(flex: 5), - ], - ), - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_alternative.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_alternative.0.dart deleted file mode 100644 index ce2155acbac0c..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_alternative.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.alternative -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Raleway font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'The infamous Tuna Torture.', - style: TextStyle( - fontFamily: 'Raleway', - fontFeatures: [ - FontFeature.alternative(1), // or 2, or 3, or... - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_alternative_fractions.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_alternative_fractions.0.dart deleted file mode 100644 index 3ceebb4ed1adf..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_alternative_fractions.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.alternativeFractions -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Ubuntu Mono font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'Fractions: 1/2 2/3 3/4 4/5', - style: TextStyle( - fontFamily: 'Ubuntu Mono', - fontFeatures: [ - FontFeature.alternativeFractions(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_case_sensitive_forms.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_case_sensitive_forms.0.dart deleted file mode 100644 index a70f5b389c8c3..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_case_sensitive_forms.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.caseSensitiveForms -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Piazzolla font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - '(A) [A] {A} «A» A/B A•B', - style: TextStyle( - fontFamily: 'Piazzolla', - fontFeatures: [ - FontFeature.caseSensitiveForms(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_character_variant.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_character_variant.0.dart deleted file mode 100644 index 58c4eed650635..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_character_variant.0.dart +++ /dev/null @@ -1,42 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.characterVariant -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Source Code Pro font can be downloaded from Google Fonts (https://www.google.com/fonts). - return Text( - 'aáâ β gǵĝ θб Iiíî Ll', - style: TextStyle( - fontFamily: 'Source Code Pro', - fontFeatures: [ - FontFeature.characterVariant(1), - FontFeature.characterVariant(2), - FontFeature.characterVariant(4), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_contextual_alternates.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_contextual_alternates.0.dart deleted file mode 100644 index 05fadd8900369..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_contextual_alternates.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.contextualAlternates -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Barriecito font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - "Ooohh, we weren't going to tell him that.", - style: TextStyle( - fontFamily: 'Barriecito', - fontFeatures: [ - FontFeature.contextualAlternates(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_denominator.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_denominator.0.dart deleted file mode 100644 index 516ba413ccc3e..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_denominator.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.denominator -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Piazzolla font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'Fractions: 1/2 2/3 3/4 4/5', - style: TextStyle( - fontFamily: 'Piazzolla', - fontFeatures: [ - FontFeature.denominator(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_fractions.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_fractions.0.dart deleted file mode 100644 index 306d463eb3188..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_fractions.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.fractions -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Ubuntu Mono font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'Fractions: 1/2 2/3 3/4 4/5', - style: TextStyle( - fontFamily: 'Ubuntu Mono', - fontFeatures: [ - FontFeature.fractions(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_historical_forms.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_historical_forms.0.dart deleted file mode 100644 index 81d6a4792cb49..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_historical_forms.0.dart +++ /dev/null @@ -1,41 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.historicalForms -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Cardo font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'VIBRANT fish assisted his business.', - style: TextStyle( - fontFamily: 'Sorts Mill Goudy', - fontFeatures: [ - FontFeature.historicalForms(), // Enables "hist". - // Use FontFeature.historicalLigatures() to enable "hlig" as well. - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_historical_ligatures.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_historical_ligatures.0.dart deleted file mode 100644 index 459f1ca7f22ca..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_historical_ligatures.0.dart +++ /dev/null @@ -1,42 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.historicalLigatures - -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Cardo font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'VIBRANT fish assisted his business.', - style: TextStyle( - fontFamily: 'Sorts Mill Goudy', - fontFeatures: [ - FontFeature.historicalForms(), // Enables "hist". - FontFeature.historicalLigatures() // Enables "hlig". - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_lining_figures.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_lining_figures.0.dart deleted file mode 100644 index 26cf4eb52094b..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_lining_figures.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.liningFigures -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Sorts Mill Goudy font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'CALL 311-555-2368 NOW!', - style: TextStyle( - fontFamily: 'Sorts Mill Goudy', - fontFeatures: [ - FontFeature.liningFigures(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_locale_aware.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_locale_aware.0.dart deleted file mode 100644 index b45b0976e2fec..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_locale_aware.0.dart +++ /dev/null @@ -1,38 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.localeAware -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Noto family of fonts can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - '次 化 刃 直 入 令', - locale: Locale('zh', 'CN'), // or Locale('ja'), Locale('ko'), Locale('zh', 'TW'), etc - style: TextStyle( - fontFamily: 'Noto Sans', - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_notational_forms.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_notational_forms.0.dart deleted file mode 100644 index e617a75cf3ade..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_notational_forms.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.notationalForms -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Gothic A1 font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'abc 123', - style: TextStyle( - fontFamily: 'Gothic A1', - fontFeatures: [ - FontFeature.notationalForms(3), // circled letters and digits - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_numerators.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_numerators.0.dart deleted file mode 100644 index d7af51cba784f..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_numerators.0.dart +++ /dev/null @@ -1,41 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.numerators -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -/// This is the stateless widget that the main application instantiates. -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Piazzolla font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'Fractions: 1/2 2/3 3/4 4/5', - style: TextStyle( - fontFamily: 'Piazzolla', - fontFeatures: [ - FontFeature.numerators(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_oldstyle_figures.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_oldstyle_figures.0.dart deleted file mode 100644 index a18d2399944d4..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_oldstyle_figures.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.oldstyleFigures -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Piazzolla font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'Call 311-555-2368 now!', - style: TextStyle( - fontFamily: 'Piazzolla', - fontFeatures: [ - FontFeature.oldstyleFigures(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_ordinal_forms.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_ordinal_forms.0.dart deleted file mode 100644 index 4b8ef03627333..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_ordinal_forms.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.ordinalForms -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Piazzolla font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - '1st, 2nd, 3rd, 4th...', - style: TextStyle( - fontFamily: 'Piazzolla', - fontFeatures: [ - FontFeature.ordinalForms(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_proportional_figures.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_proportional_figures.0.dart deleted file mode 100644 index 4113b79b13582..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_proportional_figures.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.proportionalFigures -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Kufam font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'Call 311-555-2368 now!', - style: TextStyle( - fontFamily: 'Kufam', - fontFeatures: [ - FontFeature.proportionalFigures(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_scientific_inferiors.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_scientific_inferiors.0.dart deleted file mode 100644 index f30a35dd28415..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_scientific_inferiors.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.scientificInferiors -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Piazzolla font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'C8H10N4O2', - style: TextStyle( - fontFamily: 'Piazzolla', - fontFeatures: [ - FontFeature.scientificInferiors(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_slashed_zero.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_slashed_zero.0.dart deleted file mode 100644 index ae1873913f7f2..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_slashed_zero.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.slashedZero -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Source Code Pro font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'One million is: 1,000,000.00', - style: TextStyle( - fontFamily: 'Source Code Pro', - fontFeatures: [ - FontFeature.slashedZero(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_stylistic_alternates.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_stylistic_alternates.0.dart deleted file mode 100644 index d1dc90099ee24..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_stylistic_alternates.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.stylisticAlternates -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Source Code Pro font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - r'Agile Game - $100 initial bet', - style: TextStyle( - fontFamily: 'Source Code Pro', - fontFeatures: [ - FontFeature.stylisticAlternates(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_stylistic_set.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_stylistic_set.0.dart deleted file mode 100644 index 70dd1d6d3ab28..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_stylistic_set.0.dart +++ /dev/null @@ -1,42 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.stylisticSet -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Source Code Pro font can be downloaded from Google Fonts (https://www.google.com/fonts). - return Text( - 'aáâ β gǵĝ θб Iiíî Ll', - style: TextStyle( - fontFamily: 'Source Code Pro', - fontFeatures: [ - FontFeature.stylisticSet(2), - FontFeature.stylisticSet(3), - FontFeature.stylisticSet(4), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_stylistic_set.1.dart b/examples/api/lib/ui/text/font_feature.font_feature_stylistic_set.1.dart deleted file mode 100644 index 650f03646846c..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_stylistic_set.1.dart +++ /dev/null @@ -1,41 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.stylisticSet -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Piazzolla font can be downloaded from Google Fonts (https://www.google.com/fonts). - return Text( - '-> MCMXCVII <-', // 1997 - style: TextStyle( - fontFamily: 'Piazzolla', - fontFeatures: [ - FontFeature.stylisticSet(1), - FontFeature.stylisticSet(2), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_subscripts.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_subscripts.0.dart deleted file mode 100644 index cfaea355e7268..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_subscripts.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.subscripts -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Piazzolla font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'Line from x1,y1 to x2,y2', - style: TextStyle( - fontFamily: 'Piazzolla', - fontFeatures: [ - FontFeature.subscripts(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_superscripts.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_superscripts.0.dart deleted file mode 100644 index 81d64781a2cab..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_superscripts.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.superscripts -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Sorts Mill Goudy font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'The isotope 238U decays to 206Pb', - style: TextStyle( - fontFamily: 'Sorts Mill Goudy', - fontFeatures: [ - FontFeature.superscripts(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_swash.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_swash.0.dart deleted file mode 100644 index bebf97c3cd9fb..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_swash.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for FontFeature.FontFeature.swash -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The BioRhyme Expanded font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'Queer & Romantic', - style: TextStyle( - fontFamily: 'BioRhyme Expanded', - fontFeatures: [ - FontFeature.swash(), - ], - ), - ); - } -} diff --git a/examples/api/lib/ui/text/font_feature.font_feature_tabular_figures.0.dart b/examples/api/lib/ui/text/font_feature.font_feature_tabular_figures.0.dart deleted file mode 100644 index 989def890e417..0000000000000 --- a/examples/api/lib/ui/text/font_feature.font_feature_tabular_figures.0.dart +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -// Flutter code sample for dart:ui FontFeature.FontFeature.tabularFigures -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return WidgetsApp( - builder: (BuildContext context, Widget? navigator) => const ExampleWidget(), - color: const Color(0xffffffff), - ); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - // The Piazzolla font can be downloaded from Google Fonts (https://www.google.com/fonts). - return const Text( - 'Call 311-555-2368 now!', - style: TextStyle( - fontFamily: 'Piazzolla', - fontFeatures: [ - FontFeature.tabularFigures(), - ], - ), - ); - } -} diff --git a/examples/api/lib/widgets/actions/action.action_overridable.0.dart b/examples/api/lib/widgets/actions/action.action_overridable.0.dart index 06fb11cf8f0bf..502b72f17b427 100644 --- a/examples/api/lib/widgets/actions/action.action_overridable.0.dart +++ b/examples/api/lib/widgets/actions/action.action_overridable.0.dart @@ -18,7 +18,7 @@ void main() { } // This implements a custom phone number input field that handles the -// [DeleteCharacterIntent] intent. +// [DeleteTextIntent] intent. class DigitInput extends StatefulWidget { const DigitInput({ Key? key, @@ -38,12 +38,11 @@ class DigitInput extends StatefulWidget { } class DigitInputState extends State { - late final Action _deleteTextAction = - CallbackAction( - onInvoke: (DeleteCharacterIntent intent) { + late final Action _deleteTextAction = + CallbackAction( + onInvoke: (DeleteTextIntent intent) { // For simplicity we delete everything in the section. widget.controller.clear(); - return null; }, ); @@ -51,8 +50,8 @@ class DigitInputState extends State { Widget build(BuildContext context) { return Actions( actions: >{ - // Make the default `DeleteCharacterIntent` handler overridable. - DeleteCharacterIntent: Action.overridable( + // Make the default `DeleteTextIntent` handler overridable. + DeleteTextIntent: Action.overridable( defaultAction: _deleteTextAction, context: context), }, child: TextField( @@ -80,12 +79,12 @@ class SimpleUSPhoneNumberEntry extends StatefulWidget { _SimpleUSPhoneNumberEntryState(); } -class _DeleteDigit extends Action { +class _DeleteDigit extends Action { _DeleteDigit(this.state); final _SimpleUSPhoneNumberEntryState state; @override - void invoke(DeleteCharacterIntent intent) { + Object? invoke(DeleteTextIntent intent) { assert(callingAction != null); callingAction?.invoke(intent); @@ -117,7 +116,7 @@ class _SimpleUSPhoneNumberEntryState extends State { Widget build(BuildContext context) { return Actions( actions: >{ - DeleteCharacterIntent: _DeleteDigit(this), + DeleteTextIntent: _DeleteDigit(this), }, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/examples/api/lib/widgets/async/stream_builder.0.dart b/examples/api/lib/widgets/async/stream_builder.0.dart index c7e313f0b8aa3..2ec59351fa405 100644 --- a/examples/api/lib/widgets/async/stream_builder.0.dart +++ b/examples/api/lib/widgets/async/stream_builder.0.dart @@ -4,8 +4,6 @@ // Flutter code sample for StreamBuilder -import 'dart:async'; - import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); @@ -32,17 +30,10 @@ class MyStatefulWidget extends StatefulWidget { } class _MyStatefulWidgetState extends State { - final Stream _bids = (() { - late final StreamController controller; - controller = StreamController( - onListen: () async { - await Future.delayed(const Duration(seconds: 1)); - controller.add(1); - await Future.delayed(const Duration(seconds: 1)); - await controller.close(); - }, - ); - return controller.stream; + final Stream _bids = (() async* { + await Future.delayed(const Duration(seconds: 1)); + yield 1; + await Future.delayed(const Duration(seconds: 1)); })(); @override diff --git a/examples/api/lib/widgets/basic/custom_multi_child_layout.0.dart b/examples/api/lib/widgets/basic/custom_multi_child_layout.0.dart deleted file mode 100644 index 332754e19c00a..0000000000000 --- a/examples/api/lib/widgets/basic/custom_multi_child_layout.0.dart +++ /dev/null @@ -1,124 +0,0 @@ -// 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. - -// Flutter code sample for CustomMultiChildLayout - -import 'package:flutter/material.dart'; - -void main() => runApp(const ExampleApp()); - -class ExampleApp extends StatelessWidget { - const ExampleApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: Directionality( - // TRY THIS: Try changing the direction here and hot-reloading to - // see the layout change. - textDirection: TextDirection.ltr, - child: Scaffold( - body: ExampleWidget(), - ), - ), - ); - } -} - -/// Lays out the children in a cascade, where the top corner of the next child -/// is a little above (`overlap`) the lower end corner of the previous child. -/// -/// Will relayout if the text direction changes. -class _CascadeLayoutDelegate extends MultiChildLayoutDelegate { - _CascadeLayoutDelegate({ - required this.colors, - required this.overlap, - required this.textDirection, - }); - - final Map colors; - final double overlap; - final TextDirection textDirection; - - // Perform layout will be called when re-layout is needed. - @override - void performLayout(Size size) { - final double columnWidth = size.width / colors.length; - Offset childPosition = Offset.zero; - switch (textDirection) { - case TextDirection.rtl: - childPosition += Offset(size.width, 0); - break; - case TextDirection.ltr: - break; - } - for (final String color in colors.keys) { - // layoutChild must be called exactly once for each child. - final Size currentSize = layoutChild( - color, - BoxConstraints(maxHeight: size.height, maxWidth: columnWidth), - ); - // positionChild must be called to change the position of a child from - // what it was in the previous layout. Each child starts at (0, 0) for the - // first layout. - switch (textDirection) { - case TextDirection.rtl: - positionChild(color, childPosition - Offset(currentSize.width, 0)); - childPosition += Offset(-currentSize.width, currentSize.height - overlap); - break; - case TextDirection.ltr: - positionChild(color, childPosition); - childPosition += Offset(currentSize.width, currentSize.height - overlap); - break; - } - } - } - - // shouldRelayout is called to see if the delegate has changed and requires a - // layout to occur. Should only return true if the delegate state itself - // changes: changes in the CustomMultiChildLayout attributes will - // automatically cause a relayout, like any other widget. - @override - bool shouldRelayout(_CascadeLayoutDelegate oldDelegate) { - return oldDelegate.textDirection != textDirection - || oldDelegate.overlap != overlap; - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - static const Map _colors = { - 'Red': Colors.red, - 'Green': Colors.green, - 'Blue': Colors.blue, - 'Cyan': Colors.cyan, - }; - - @override - Widget build(BuildContext context) { - return CustomMultiChildLayout( - delegate: _CascadeLayoutDelegate( - colors: _colors, - overlap: 30.0, - textDirection: Directionality.of(context), - ), - children: [ - // Create all of the colored boxes in the colors map. - for (MapEntry entry in _colors.entries) - // The "id" can be any Object, not just a String. - LayoutId( - id: entry.key, - child: Container( - color: entry.value, - width: 100.0, - height: 100.0, - alignment: Alignment.center, - child: Text(entry.key), - ), - ), - ], - ); - } -} diff --git a/examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart b/examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart index 64930d280ee0b..6005b48cb3a47 100644 --- a/examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart +++ b/examples/api/lib/widgets/focus_manager/focus_node.unfocus.0.dart @@ -74,7 +74,7 @@ class _MyStatefulWidgetState extends State { }, value: UnfocusDisposition.values[index], ), - Text(UnfocusDisposition.values[index].name), + Text(describeEnum(UnfocusDisposition.values[index])), ], ); }), diff --git a/examples/api/lib/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart b/examples/api/lib/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart deleted file mode 100644 index 7e89dc9282083..0000000000000 --- a/examples/api/lib/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart +++ /dev/null @@ -1,289 +0,0 @@ -// 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 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -/// Slots used for the children of [Diagonal] and [RenderDiagonal]. -enum DiagonalSlot { - topLeft, - bottomRight, -} - -/// A widget that demonstrates the usage of [SlottedMultiChildRenderObjectWidgetMixin] -/// by providing slots for two children that will be arranged diagonally. -class Diagonal extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin { - const Diagonal({ - Key? key, - this.topLeft, - this.bottomRight, - this.backgroundColor, - }) : super(key: key); - - final Widget? topLeft; - final Widget? bottomRight; - final Color? backgroundColor; - - @override - Iterable get slots => DiagonalSlot.values; - - @override - Widget? childForSlot(DiagonalSlot slot) { - switch (slot) { - case DiagonalSlot.topLeft: - return topLeft; - case DiagonalSlot.bottomRight: - return bottomRight; - } - } - - // The [createRenderObject] and [updateRenderObject] methods configure the - // [RenderObject] backing this widget with the configuration of the widget. - // They do not need to do anything with the children of the widget, though. - // The children of the widget are automatically configured on the - // [RenderObject] by [SlottedRenderObjectElement.mount] and - // [SlottedRenderObjectElement.update]. - - @override - SlottedContainerRenderObjectMixin createRenderObject( - BuildContext context, - ) { - return RenderDiagonal( - backgroundColor: backgroundColor, - ); - } - - @override - void updateRenderObject( - BuildContext context, - SlottedContainerRenderObjectMixin renderObject, - ) { - (renderObject as RenderDiagonal).backgroundColor = backgroundColor; - } -} - -/// A render object that demonstrates the usage of [SlottedContainerRenderObjectMixin] -/// by providing slots for two children that will be arranged diagonally. -class RenderDiagonal extends RenderBox with SlottedContainerRenderObjectMixin, DebugOverflowIndicatorMixin { - RenderDiagonal({Color? backgroundColor}) : _backgroundColor = backgroundColor; - - // Getters and setters to configure the [RenderObject] with the configuration - // of the [Widget]. These mostly contain boilerplate code, but depending on - // where the configuration value is used, the setter has to call - // [markNeedsLayout], [markNeedsPaint], or [markNeedsSemanticsUpdate]. - Color? get backgroundColor => _backgroundColor; - Color? _backgroundColor; - set backgroundColor(Color? value) { - assert(value != null); - if (_backgroundColor == value) { - return; - } - _backgroundColor = value; - markNeedsPaint(); - } - - // Getters to simplify accessing the slotted children. - RenderBox? get _topLeft => childForSlot(DiagonalSlot.topLeft); - RenderBox? get _bottomRight => childForSlot(DiagonalSlot.bottomRight); - - // The size this render object would have if the incoming constraints were - // unconstrained; calculated during performLayout used during paint for an - // assertion that checks for unintended overflow. - late Size _childrenSize; - - // Returns children in hit test order. - @override - Iterable get children { - return [ - if (_topLeft != null) - _topLeft!, - if (_bottomRight != null) - _bottomRight!, - ]; - } - - // LAYOUT - - @override - void performLayout() { - // Children are allowed to be as big as they want (= unconstrained). - const BoxConstraints childConstraints = BoxConstraints(); - - // Lay out the top left child and position it at offset zero. - Size topLeftSize = Size.zero; - final RenderBox? topLeft = _topLeft; - if (topLeft != null) { - topLeft.layout(childConstraints, parentUsesSize: true); - _positionChild(topLeft, Offset.zero); - topLeftSize = topLeft.size; - } - - // Lay out the bottom right child and position it at the bottom right corner - // of the top left child. - Size bottomRightSize = Size.zero; - final RenderBox? bottomRight = _bottomRight; - if (bottomRight != null) { - bottomRight.layout(childConstraints, parentUsesSize: true); - _positionChild( - bottomRight, - Offset(topLeftSize.width, topLeftSize.height), - ); - bottomRightSize = bottomRight.size; - } - - // Calculate the overall size and constrain it to the given constraints. - // Any overflow is marked (in debug mode) during paint. - _childrenSize = Size( - topLeftSize.width + bottomRightSize.width, - topLeftSize.height + bottomRightSize.height, - ); - size = constraints.constrain(_childrenSize); - } - - void _positionChild(RenderBox child, Offset offset) { - (child.parentData! as BoxParentData).offset = offset; - } - - // PAINT - - @override - void paint(PaintingContext context, Offset offset) { - // Paint the background. - if (backgroundColor != null) { - context.canvas.drawRect( - offset & size, - Paint() - ..color = backgroundColor!, - ); - } - - void paintChild(RenderBox child, PaintingContext context, Offset offset) { - final BoxParentData childParentData = child.parentData! as BoxParentData; - context.paintChild(child, childParentData.offset + offset); - } - - // Paint the children at the offset calculated during layout. - final RenderBox? topLeft = _topLeft; - if (topLeft != null) { - paintChild(topLeft, context, offset); - } - final RenderBox? bottomRight = _bottomRight; - if (bottomRight != null) { - paintChild(bottomRight, context, offset); - } - - // Paint an overflow indicator in debug mode if the children want to be - // larger than the incoming constraints allow. - assert(() { - paintOverflowIndicator( - context, - offset, - Offset.zero & size, - Offset.zero & _childrenSize, - ); - return true; - }()); - } - - // HIT TEST - - @override - bool hitTestChildren(BoxHitTestResult result, { required Offset position }) { - for (final RenderBox child in children) { - final BoxParentData parentData = child.parentData! as BoxParentData; - final bool isHit = result.addWithPaintOffset( - offset: parentData.offset, - position: position, - hitTest: (BoxHitTestResult result, Offset transformed) { - assert(transformed == position - parentData.offset); - return child.hitTest(result, position: transformed); - }, - ); - if (isHit) { - return true; - } - } - return false; - } - - // INTRINSICS - - // Incoming height/width are ignored as children are always laid out unconstrained. - - @override - double computeMinIntrinsicWidth(double height) { - final double topLeftWidth = _topLeft?.getMinIntrinsicWidth(double.infinity) ?? 0; - final double bottomRightWith = _bottomRight?.getMinIntrinsicWidth(double.infinity) ?? 0; - return topLeftWidth + bottomRightWith; - } - - @override - double computeMaxIntrinsicWidth(double height) { - final double topLeftWidth = _topLeft?.getMaxIntrinsicWidth(double.infinity) ?? 0; - final double bottomRightWith = _bottomRight?.getMaxIntrinsicWidth(double.infinity) ?? 0; - return topLeftWidth + bottomRightWith; } - - @override - double computeMinIntrinsicHeight(double width) { - final double topLeftHeight = _topLeft?.getMinIntrinsicHeight(double.infinity) ?? 0; - final double bottomRightHeight = _bottomRight?.getMinIntrinsicHeight(double.infinity) ?? 0; - return topLeftHeight + bottomRightHeight; - } - - @override - double computeMaxIntrinsicHeight(double width) { - final double topLeftHeight = _topLeft?.getMaxIntrinsicHeight(double.infinity) ?? 0; - final double bottomRightHeight = _bottomRight?.getMaxIntrinsicHeight(double.infinity) ?? 0; - return topLeftHeight + bottomRightHeight; - } - - @override - Size computeDryLayout(BoxConstraints constraints) { - const BoxConstraints childConstraints = BoxConstraints(); - final Size topLeftSize = _topLeft?.computeDryLayout(childConstraints) ?? Size.zero; - final Size bottomRightSize = _bottomRight?.computeDryLayout(childConstraints) ?? Size.zero; - return constraints.constrain(Size( - topLeftSize.width + bottomRightSize.width, - topLeftSize.height + bottomRightSize.height, - )); - } -} - -class ExampleWidget extends StatelessWidget { - const ExampleWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - appBar: AppBar(title: const Text('Slotted RenderObject Example')), - body: Center( - child: Diagonal( - topLeft: Container( - color: Colors.green, - height: 100, - width: 200, - child: const Center( - child: Text('topLeft'), - ), - ), - bottomRight: Container( - color: Colors.yellow, - height: 60, - width: 30, - child: const Center( - child: Text('bottomRight'), - ), - ), - backgroundColor: Colors.blue, - ), - ), - ), - ); - } -} - -void main() { - runApp(const ExampleWidget()); -} diff --git a/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart b/examples/api/lib/widgets/will_pop_scope/will_pop_scope.1.dart similarity index 97% rename from examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart rename to examples/api/lib/widgets/will_pop_scope/will_pop_scope.1.dart index 5e39870ba5ce6..bef2d32816292 100644 --- a/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart +++ b/examples/api/lib/widgets/will_pop_scope/will_pop_scope.1.dart @@ -69,7 +69,7 @@ class _MyStatefulWidgetState extends State { ), const Text('Push to a new screen, then tap on shouldPop ' 'button to toggle its value. Press the back ' - 'button in the appBar to check its behavior ' + 'button in the appBar to check its behaviour ' 'for different values of shouldPop'), ], ), diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index eb5fbfa65cd00..a396a97fc83c4 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -9,13 +9,12 @@ environment: flutter: ">=2.5.0-6.0.pre.30 <3.0.0" dependencies: - cupertino_icons: 1.0.4 + cupertino_icons: 1.0.3 flutter: sdk: flutter characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,11 +26,11 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,13 +47,14 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,9 +69,9 @@ dev_dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 1171 +# PUBSPEC CHECKSUM: 03d7 diff --git a/examples/api/test/cupertino/button/cupertino_button.0_test.dart b/examples/api/test/cupertino/button/cupertino_button.0_test.dart deleted file mode 100644 index 9d9397e3b9cc7..0000000000000 --- a/examples/api/test/cupertino/button/cupertino_button.0_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -// 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 'package:flutter/cupertino.dart'; -import 'package:flutter_api_samples/cupertino/button/cupertino_button.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('Has 4 CupertinoButton variants', (WidgetTester tester) async { - await tester.pumpWidget( - const example.MyApp(), - ); - - expect(find.byType(CupertinoButton), findsNWidgets(4)); - expect(find.ancestor(of: find.text('Enabled'), matching: find.byType(CupertinoButton)), findsNWidgets(2)); - expect(find.ancestor(of: find.text('Disabled'), matching: find.byType(CupertinoButton)), findsNWidgets(2)); - }); -} diff --git a/examples/api/test/cupertino/date_picker/cupertino_date_picker.0_test.dart b/examples/api/test/cupertino/date_picker/cupertino_date_picker.0_test.dart deleted file mode 100644 index af9a22bee121b..0000000000000 --- a/examples/api/test/cupertino/date_picker/cupertino_date_picker.0_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -// 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 'package:flutter_api_samples/cupertino/date_picker/cupertino_date_picker.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -const Offset _kRowOffset = Offset(0.0, -50.0); - -void main() { - testWidgets('Can change date, time and dateTime using CupertinoDatePicker', (WidgetTester tester) async { - await tester.pumpWidget( - const example.MyApp(), - ); - // Open the date picker. - await tester.tap(find.text('10-26-2016')); - await tester.pumpAndSettle(); - - // Drag month, day and year wheels to change the picked date. - await tester.drag(find.text('October'), _kRowOffset, touchSlopY: 0, warnIfMissed: false); // see top of file - await tester.drag(find.text('26'), _kRowOffset, touchSlopY: 0, warnIfMissed: false); // see top of file - await tester.drag(find.text('2016'), _kRowOffset, touchSlopY: 0, warnIfMissed: false); // see top of file - - await tester.pump(); - await tester.pump(const Duration(milliseconds: 500)); - - // Close the date picker. - await tester.tapAt(const Offset(1.0, 1.0)); - await tester.pumpAndSettle(); - - expect(find.text('12-28-2018'), findsOneWidget); - - // Open the time picker. - await tester.tap(find.text('22:35')); - await tester.pumpAndSettle(); - - // Drag hour and minute wheels to change the picked time. - await tester.drag(find.text('22'), const Offset(0.0, 50.0), touchSlopY: 0, warnIfMissed: false); // see top of file - await tester.drag(find.text('35'), const Offset(0.0, 50.0), touchSlopY: 0, warnIfMissed: false); // see top of file - - await tester.pump(); - await tester.pump(const Duration(milliseconds: 500)); - - // Close the time picker. - await tester.tapAt(const Offset(1.0, 1.0)); - await tester.pumpAndSettle(); - - expect(find.text('20:33'), findsOneWidget); - - // Open the dateTime picker. - await tester.tap(find.text('8-3-2016 17:45')); - await tester.pumpAndSettle(); - - // Drag hour and minute wheels to change the picked time. - await tester.drag(find.text('17'), const Offset(0.0, 50.0), touchSlopY: 0, warnIfMissed: false); // see top of file - await tester.drag(find.text('45'), const Offset(0.0, 50.0), touchSlopY: 0, warnIfMissed: false); // see top of file - - await tester.pump(); - await tester.pump(const Duration(milliseconds: 500)); - - // Close the dateTime picker. - await tester.tapAt(const Offset(1.0, 1.0)); - await tester.pumpAndSettle(); - - expect(find.text('8-3-2016 15:43'), findsOneWidget); - }); -} diff --git a/examples/api/test/material/ink/ink.image_clip.0_test.dart b/examples/api/test/material/ink/ink.image_clip.0_test.dart deleted file mode 100644 index 474fa09abc8b9..0000000000000 --- a/examples/api/test/material/ink/ink.image_clip.0_test.dart +++ /dev/null @@ -1,34 +0,0 @@ -// 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:typed_data'; - -import 'package:flutter/material.dart'; -import 'package:flutter_api_samples/material/ink/ink.image_clip.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - const List kTransparentImage = [ - 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, - 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, - 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, - 0x41, 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0D, - 0x0A, 0x2D, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, - ]; - - testWidgets('Ink ancestor material is not clipped', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: example.MyStatelessWidget( - image: MemoryImage(Uint8List.fromList(kTransparentImage)), - ), - ), - ), - ); - - final Finder inkMaterialFinder = find.ancestor(of: find.byType(Ink), matching: find.byType(Material)); - expect(find.ancestor(of: inkMaterialFinder, matching: find.byType(ClipRRect)), findsNothing); - }); -} diff --git a/examples/api/test/material/ink/ink.image_clip.1_test.dart b/examples/api/test/material/ink/ink.image_clip.1_test.dart deleted file mode 100644 index 0428c3603ae42..0000000000000 --- a/examples/api/test/material/ink/ink.image_clip.1_test.dart +++ /dev/null @@ -1,34 +0,0 @@ -// 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:typed_data'; - -import 'package:flutter/material.dart'; -import 'package:flutter_api_samples/material/ink/ink.image_clip.1.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - const List kTransparentImage = [ - 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, - 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, - 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, - 0x41, 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0D, - 0x0A, 0x2D, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, - ]; - - testWidgets('Ink ancestor material is clipped', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: example.MyStatelessWidget( - image: MemoryImage(Uint8List.fromList(kTransparentImage)), - ), - ), - ), - ); - - final Finder inkMaterialFinder = find.ancestor(of: find.byType(Ink), matching: find.byType(Material)); - expect(find.ancestor(of: inkMaterialFinder, matching: find.byType(ClipRRect)), findsOneWidget); - }); -} diff --git a/examples/api/test/material/input_decorator/input_decoration.floating_label_style_error.0_test.dart b/examples/api/test/material/input_decorator/input_decoration.floating_label_style_error.0_test.dart deleted file mode 100644 index 07cf30a649465..0000000000000 --- a/examples/api/test/material/input_decorator/input_decoration.floating_label_style_error.0_test.dart +++ /dev/null @@ -1,22 +0,0 @@ -// 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 'package:flutter/material.dart'; -import 'package:flutter_api_samples/material/input_decorator/input_decoration.floating_label_style_error.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('InputDecorator label uses errorColor', (WidgetTester tester) async { - await tester.pumpWidget( - const example.MyApp(), - ); - final Theme theme = tester.firstWidget(find.byType(Theme)); - - await tester.tap(find.byType(TextFormField)); - await tester.pumpAndSettle(); - - final AnimatedDefaultTextStyle label = tester.firstWidget(find.ancestor(of: find.text('Name'), matching: find.byType(AnimatedDefaultTextStyle))); - expect(label.style.color, theme.data.errorColor); - }); -} diff --git a/examples/api/test/material/input_decorator/input_decoration.label_style_error.0_test.dart b/examples/api/test/material/input_decorator/input_decoration.label_style_error.0_test.dart deleted file mode 100644 index 05fd39fccd59e..0000000000000 --- a/examples/api/test/material/input_decorator/input_decoration.label_style_error.0_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -// 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 'package:flutter/material.dart'; -import 'package:flutter_api_samples/material/input_decorator/input_decoration.label_style_error.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('InputDecorator label uses errorColor', (WidgetTester tester) async { - await tester.pumpWidget( - const example.MyApp(), - ); - final Theme theme = tester.firstWidget(find.byType(Theme)); - - final AnimatedDefaultTextStyle label = tester.firstWidget(find.ancestor(of: find.text('Name'), matching: find.byType(AnimatedDefaultTextStyle))); - expect(label.style.color, theme.data.errorColor); - }); -} diff --git a/examples/api/test/services/mouse_cursor/mouse_cursor.0_test.dart b/examples/api/test/services/mouse_cursor/mouse_cursor.0_test.dart deleted file mode 100644 index 902c0f272c481..0000000000000 --- a/examples/api/test/services/mouse_cursor/mouse_cursor.0_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// 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 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/services/mouse_cursor/mouse_cursor.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('Uses Text Cursor', (WidgetTester tester) async { - await tester.pumpWidget( - const example.MyApp(), - ); - - expect(find.byType(MouseRegion), findsNWidgets(2)); // There's one in the MaterialApp - final Finder mouseRegionFinder = find.ancestor(of: find.byType(Container), matching: find.byType(MouseRegion)); - expect(mouseRegionFinder, findsOneWidget); - expect((tester.widget(mouseRegionFinder) as MouseRegion).cursor, equals(SystemMouseCursors.text)); - }); -} diff --git a/examples/api/test/ui/text/font_feature.0_test.dart b/examples/api/test/ui/text/font_feature.0_test.dart deleted file mode 100644 index edd4db793ceb7..0000000000000 --- a/examples/api/test/ui/text/font_feature.0_test.dart +++ /dev/null @@ -1,29 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsNWidgets(9)); - expect((tester.widget(find.byType(Text).at(0)) as Text).style!.fontSize, equals(18.0)); - expect((tester.widget(find.byType(Text).at(1)) as Text).style!.fontFamily, equals('Cardo')); - expect((tester.widget(find.byType(Text).at(3)) as Text).style!.fontFeatures, - equals(const [FontFeature.oldstyleFigures()])); - expect((tester.widget(find.byType(Text).at(5)) as Text).style!.fontFeatures, - equals(const [FontFeature.alternativeFractions()])); - expect((tester.widget(find.byType(Text).at(8)) as Text).style!.fontFeatures, - equals([FontFeature.stylisticSet(1)])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_alternative.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_alternative.0_test.dart deleted file mode 100644 index 7f57a116ca0b9..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_alternative.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_alternative.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Raleway')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.alternative(1)])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_alternative_fractions.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_alternative_fractions.0_test.dart deleted file mode 100644 index 8c2c8007ca2cd..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_alternative_fractions.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_alternative_fractions.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Ubuntu Mono')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.alternativeFractions()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_case_sensitive_forms.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_case_sensitive_forms.0_test.dart deleted file mode 100644 index 81ad5ca59465c..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_case_sensitive_forms.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_case_sensitive_forms.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Piazzolla')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.caseSensitiveForms()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_character_variant.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_character_variant.0_test.dart deleted file mode 100644 index 018d0da8fabab..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_character_variant.0_test.dart +++ /dev/null @@ -1,29 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_character_variant.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Source Code Pro')); - expect( - (tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals([ - FontFeature.characterVariant(1), - FontFeature.characterVariant(2), - FontFeature.characterVariant(4), - ])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_contextual_alternates.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_contextual_alternates.0_test.dart deleted file mode 100644 index a692503b9bdb7..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_contextual_alternates.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_contextual_alternates.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Barriecito')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.contextualAlternates()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_denominator.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_denominator.0_test.dart deleted file mode 100644 index 3473cf0ea59fd..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_denominator.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_denominator.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Piazzolla')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.denominator()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_fractions.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_fractions.0_test.dart deleted file mode 100644 index ee02b18d46ec9..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_fractions.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_fractions.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Ubuntu Mono')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.fractions()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_historical_forms.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_historical_forms.0_test.dart deleted file mode 100644 index 58ec89276da2b..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_historical_forms.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_historical_forms.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Sorts Mill Goudy')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.historicalForms()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_historical_ligatures.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_historical_ligatures.0_test.dart deleted file mode 100644 index f60ac5704a4a5..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_historical_ligatures.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_historical_ligatures.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Sorts Mill Goudy')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.historicalForms(), FontFeature.historicalLigatures()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_lining_figures.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_lining_figures.0_test.dart deleted file mode 100644 index a29abfde1bc52..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_lining_figures.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_lining_figures.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Sorts Mill Goudy')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.liningFigures()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_locale_aware.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_locale_aware.0_test.dart deleted file mode 100644 index c8a4d66359929..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_locale_aware.0_test.dart +++ /dev/null @@ -1,23 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_locale_aware.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Noto Sans')); - expect((tester.widget(find.byType(Text).first) as Text).locale, equals(const Locale('zh', 'CN'))); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_notational_forms.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_notational_forms.0_test.dart deleted file mode 100644 index 8a9aa0d737406..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_notational_forms.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_notational_forms.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Gothic A1')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.notationalForms(3)])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_numerators.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_numerators.0_test.dart deleted file mode 100644 index 3fb41472f94e7..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_numerators.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_numerators.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Piazzolla')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.numerators()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_oldstyle_figures.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_oldstyle_figures.0_test.dart deleted file mode 100644 index ea775073f51ae..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_oldstyle_figures.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_oldstyle_figures.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Piazzolla')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.oldstyleFigures()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_ordinal_forms.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_ordinal_forms.0_test.dart deleted file mode 100644 index 25c926bf4a00b..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_ordinal_forms.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_ordinal_forms.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Piazzolla')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.ordinalForms()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_proportional_figures.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_proportional_figures.0_test.dart deleted file mode 100644 index fedcc2f85c84d..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_proportional_figures.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_proportional_figures.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Kufam')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.proportionalFigures()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_scientific_inferiors.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_scientific_inferiors.0_test.dart deleted file mode 100644 index b1c82600a5af7..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_scientific_inferiors.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_scientific_inferiors.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Piazzolla')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.scientificInferiors()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_slashed_zero.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_slashed_zero.0_test.dart deleted file mode 100644 index 7747067251af5..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_slashed_zero.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_slashed_zero.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Source Code Pro')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.slashedZero()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_stylistic_alternates.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_stylistic_alternates.0_test.dart deleted file mode 100644 index ab79d50c929cd..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_stylistic_alternates.0_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_stylistic_alternates.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Source Code Pro')); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.stylisticAlternates()])); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_stylistic_set.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_stylistic_set.0_test.dart deleted file mode 100644 index c2e0aae7e4240..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_stylistic_set.0_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_stylistic_set.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Source Code Pro')); - expect( - (tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals( - [ - FontFeature.stylisticSet(2), - FontFeature.stylisticSet(3), - FontFeature.stylisticSet(4), - ], - ), - ); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_stylistic_set.1_test.dart b/examples/api/test/ui/text/font_feature.font_feature_stylistic_set.1_test.dart deleted file mode 100644 index 200e35bf4ac3b..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_stylistic_set.1_test.dart +++ /dev/null @@ -1,31 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_stylistic_set.1.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Piazzolla')); - expect( - (tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals( - [ - FontFeature.stylisticSet(1), - FontFeature.stylisticSet(2), - ], - ), - ); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_subscripts.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_subscripts.0_test.dart deleted file mode 100644 index 80e7d21605e0e..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_subscripts.0_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_subscripts.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Piazzolla')); - expect( - (tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.subscripts()]), - ); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_superscripts.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_superscripts.0_test.dart deleted file mode 100644 index 951b60b70f9b9..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_superscripts.0_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_superscripts.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Sorts Mill Goudy')); - expect( - (tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.superscripts()]), - ); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_swash.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_swash.0_test.dart deleted file mode 100644 index 7ab5624efc94c..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_swash.0_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_swash.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('BioRhyme Expanded')); - expect( - (tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.swash()]), - ); - }); -} diff --git a/examples/api/test/ui/text/font_feature.font_feature_tabular_figures.0_test.dart b/examples/api/test/ui/text/font_feature.font_feature_tabular_figures.0_test.dart deleted file mode 100644 index 57888d4b2faf0..0000000000000 --- a/examples/api/test/ui/text/font_feature.font_feature_tabular_figures.0_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -// 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/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/ui/text/font_feature.font_feature_tabular_figures.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows font features', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: example.ExampleWidget(), - ), - ); - - expect(find.byType(Text), findsOneWidget); - expect((tester.widget(find.byType(Text).first) as Text).style!.fontFamily, equals('Piazzolla')); - expect( - (tester.widget(find.byType(Text).first) as Text).style!.fontFeatures, - equals(const [FontFeature.tabularFigures()]), - ); - }); -} diff --git a/examples/api/test/widgets/basic/custom_multi_child_layout.0_test.dart b/examples/api/test/widgets/basic/custom_multi_child_layout.0_test.dart deleted file mode 100644 index c762a58f402fe..0000000000000 --- a/examples/api/test/widgets/basic/custom_multi_child_layout.0_test.dart +++ /dev/null @@ -1,59 +0,0 @@ -// 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 'package:flutter/material.dart'; -import 'package:flutter_api_samples/widgets/basic/custom_multi_child_layout.0.dart' - as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('has four containers', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: Scaffold( - body: example.ExampleWidget(), - ), - ), - ); - final Finder containerFinder = find.byType(Container); - expect(containerFinder, findsNWidgets(4)); - }); - - testWidgets('containers are the same size', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: Scaffold( - body: example.ExampleWidget(), - ), - ), - ); - final Finder containerFinder = find.byType(Container); - const Size expectedSize = Size(100, 100); - for (int i = 0; i < 4; i += 1) { - expect(tester.getSize(containerFinder.at(i)), equals(expectedSize)); - } - expect(containerFinder, findsNWidgets(4)); - }); - - testWidgets('containers are offset', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: Scaffold( - body: example.ExampleWidget(), - ), - ), - ); - final Finder containerFinder = find.byType(Container); - Rect previousRect = tester.getRect(containerFinder.first); - for (int i = 1; i < 4; i += 1) { - expect( - tester.getRect(containerFinder.at(i)), - equals(previousRect.shift(const Offset(100, 70))), - reason: 'Rect $i not correct size', - ); - previousRect = tester.getRect(containerFinder.at(i)); - } - expect(containerFinder, findsNWidgets(4)); - }); -} diff --git a/examples/api/test/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0_test.dart b/examples/api/test/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0_test.dart deleted file mode 100644 index 150d9e57fd1a3..0000000000000 --- a/examples/api/test/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0_test.dart +++ /dev/null @@ -1,41 +0,0 @@ -// 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 'package:flutter/widgets.dart'; -import 'package:flutter_api_samples/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('shows two widgets arranged diagonally', (WidgetTester tester) async { - await tester.pumpWidget( - const example.ExampleWidget(), - ); - - expect(find.text('topLeft'), findsOneWidget); - expect(find.text('bottomRight'), findsOneWidget); - - expect( - tester.getBottomRight(findContainerWithText('topLeft')), - tester.getTopLeft(findContainerWithText('bottomRight')), - ); - - expect( - tester.getSize(findContainerWithText('topLeft')), - const Size(200, 100), - ); - expect( - tester.getSize(findContainerWithText('bottomRight')), - const Size(30, 60), - ); - - expect( - tester.getSize(find.byType(example.Diagonal)), - const Size(200 + 30, 100 + 60), - ); - }); -} - -Finder findContainerWithText(String text) { - return find.ancestor(of: find.text(text), matching: find.byType(Container)); -} diff --git a/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart b/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart deleted file mode 100644 index 1a0720df6d5cb..0000000000000 --- a/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// 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 'package:flutter_api_samples/widgets/will_pop_scope/will_pop_scope.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('pressing shouldPop button changes shouldPop', (WidgetTester tester) async { - await tester.pumpWidget( - const example.MyApp(), - ); - - final Finder buttonFinder = find.text('shouldPop: true'); - expect(buttonFinder, findsOneWidget); - await tester.tap(buttonFinder); - await tester.pump(); - expect(find.text('shouldPop: false'), findsOneWidget); - }); - testWidgets('pressing Push button pushes route', (WidgetTester tester) async { - await tester.pumpWidget( - const example.MyApp(), - ); - - final Finder buttonFinder = find.text('Push'); - expect(buttonFinder, findsOneWidget); - expect(find.byType(example.MyStatefulWidget), findsOneWidget); - await tester.tap(buttonFinder); - await tester.pumpAndSettle(); - expect(find.byType(example.MyStatefulWidget, skipOffstage: false), findsNWidgets(2)); - }); -} diff --git a/examples/flutter_view/android/project-app.lockfile b/examples/flutter_view/android/project-app.lockfile index 1df9ea94844e5..3034e7925066f 100644 --- a/examples/flutter_view/android/project-app.lockfile +++ b/examples/flutter_view/android/project-app.lockfile @@ -40,8 +40,6 @@ androidx.vectordrawable:vectordrawable-animated:1.1.0=debugAndroidTestCompileCla androidx.vectordrawable:vectordrawable:1.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -109,18 +107,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/examples/flutter_view/pubspec.yaml b/examples/flutter_view/pubspec.yaml index 696a60a74a02e..461ae2e2991aa 100644 --- a/examples/flutter_view/pubspec.yaml +++ b/examples/flutter_view/pubspec.yaml @@ -10,7 +10,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -20,4 +19,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: 41cc +# PUBSPEC CHECKSUM: d86f diff --git a/examples/hello_world/android/project-app.lockfile b/examples/hello_world/android/project-app.lockfile index b5b0b745c3536..0a88943553da0 100644 --- a/examples/hello_world/android/project-app.lockfile +++ b/examples/hello_world/android/project-app.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugCompi androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -89,18 +87,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 4a1713543146c..05ffe40ed632c 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -9,7 +9,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -19,11 +18,11 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -40,13 +39,14 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,13 +61,13 @@ dev_dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: e2ca +# PUBSPEC CHECKSUM: f832 diff --git a/examples/image_list/android/project-app.lockfile b/examples/image_list/android/project-app.lockfile index b5b0b745c3536..0a88943553da0 100644 --- a/examples/image_list/android/project-app.lockfile +++ b/examples/image_list/android/project-app.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugCompi androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -89,18 +87,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index 409bcf3a4e1ad..b1594e6b1cce4 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -12,11 +12,10 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: 1.0.4 + cupertino_icons: 1.0.3 characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,13 +35,13 @@ dev_dependencies: clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -55,4 +54,4 @@ flutter: assets: - images/coast.jpg -# PUBSPEC CHECKSUM: fa25 +# PUBSPEC CHECKSUM: b8bf diff --git a/examples/layers/android/project-app.lockfile b/examples/layers/android/project-app.lockfile index b5b0b745c3536..0a88943553da0 100644 --- a/examples/layers/android/project-app.lockfile +++ b/examples/layers/android/project-app.lockfile @@ -21,8 +21,6 @@ androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugCompi androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -89,18 +87,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index 90e4617dc5524..d4d60ab12c36e 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -9,7 +9,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -24,17 +23,17 @@ dev_dependencies: clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: assets: - services/data.json uses-material-design: true -# PUBSPEC CHECKSUM: e37e +# PUBSPEC CHECKSUM: 921a diff --git a/examples/platform_channel/android/project-app.lockfile b/examples/platform_channel/android/project-app.lockfile index 729cf23c9708b..a1e6595e494e9 100644 --- a/examples/platform_channel/android/project-app.lockfile +++ b/examples/platform_channel/android/project-app.lockfile @@ -25,8 +25,6 @@ androidx.test:runner:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRunt androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -100,18 +98,11 @@ org.hamcrest:hamcrest-integration:1.3=debugAndroidTestCompileClasspath,debugAndr org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index b8c9d7d0a202d..9c4aad74c900c 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -9,7 +9,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -19,11 +18,11 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -40,13 +39,14 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,9 +61,9 @@ dev_dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e2ca +# PUBSPEC CHECKSUM: f832 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 05fec8347f018..2668e6999cf8f 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -9,7 +9,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -19,11 +18,11 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -40,13 +39,14 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,9 +61,9 @@ dev_dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e2ca +# PUBSPEC CHECKSUM: f832 diff --git a/examples/platform_view/android/project-app.lockfile b/examples/platform_view/android/project-app.lockfile index 1df9ea94844e5..3034e7925066f 100644 --- a/examples/platform_view/android/project-app.lockfile +++ b/examples/platform_view/android/project-app.lockfile @@ -40,8 +40,6 @@ androidx.vectordrawable:vectordrawable-animated:1.1.0=debugAndroidTestCompileCla androidx.vectordrawable:vectordrawable:1.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -109,18 +107,11 @@ org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/examples/platform_view/pubspec.yaml b/examples/platform_view/pubspec.yaml index 2eb11d9f62e58..c78f2cf23385a 100644 --- a/examples/platform_view/pubspec.yaml +++ b/examples/platform_view/pubspec.yaml @@ -9,7 +9,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -20,4 +19,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: 41cc +# PUBSPEC CHECKSUM: d86f diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index cdc1510140979..ec3b9ab99da2e 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -9,7 +9,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -24,12 +23,12 @@ dev_dependencies: clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: e37e +# PUBSPEC CHECKSUM: 921a diff --git a/packages/flutter/lib/fix_data.yaml b/packages/flutter/lib/fix_data.yaml index 255e62085eb82..9a89ba51e68a9 100644 --- a/packages/flutter/lib/fix_data.yaml +++ b/packages/flutter/lib/fix_data.yaml @@ -14,149 +14,6 @@ version: 1 transforms: - # Changes made in https://github.com/flutter/flutter/pull/96115 - - title: "Migrate 'Icons.pie_chart_outlined' to 'Icons.pie_chart_outline'" - date: 2022-01-04 - element: - uris: [ 'material.dart' ] - field: 'pie_chart_outlined' - inClass: 'Icons' - changes: - - kind: 'rename' - newName: 'pie_chart_outline' - - # Changes made in https://github.com/flutter/flutter/pull/93427 - - title: "Remove 'primaryVariant' and 'secondaryVariant'" - date: 2021-11-19 - element: - uris: [ 'material.dart' ] - constructor: '' - inClass: 'ColorScheme' - changes: - - kind: 'removeParameter' - name: 'primaryVariant' - - kind: 'removeParameter' - name: 'secondaryVariant' - - # Changes made in https://github.com/flutter/flutter/pull/93427 - - title: "Remove 'primaryVariant' and 'secondaryVariant'" - date: 2021-11-19 - element: - uris: [ 'material.dart' ] - constructor: 'light' - inClass: 'ColorScheme' - changes: - - kind: 'removeParameter' - name: 'primaryVariant' - - kind: 'removeParameter' - name: 'secondaryVariant' - - # Changes made in https://github.com/flutter/flutter/pull/93427 - - title: "Remove 'primaryVariant' and 'secondaryVariant'" - date: 2021-11-19 - element: - uris: [ 'material.dart' ] - constructor: 'dark' - inClass: 'ColorScheme' - changes: - - kind: 'removeParameter' - name: 'primaryVariant' - - kind: 'removeParameter' - name: 'secondaryVariant' - - # Changes made in https://github.com/flutter/flutter/pull/93427 - - title: "Remove 'primaryVariant' and 'secondaryVariant'" - date: 2021-11-19 - element: - uris: [ 'material.dart' ] - constructor: 'highContrastLight' - inClass: 'ColorScheme' - changes: - - kind: 'removeParameter' - name: 'primaryVariant' - - kind: 'removeParameter' - name: 'secondaryVariant' - - # Changes made in https://github.com/flutter/flutter/pull/93427 - - title: "Remove 'primaryVariant' and 'secondaryVariant'" - date: 2021-11-19 - element: - uris: [ 'material.dart' ] - constructor: 'highContrastDark' - inClass: 'ColorScheme' - changes: - - kind: 'removeParameter' - name: 'primaryVariant' - - kind: 'removeParameter' - name: 'secondaryVariant' - - # Changes made in https://github.com/flutter/flutter/pull/93427 - - title: "Remove 'primaryVariant' and 'secondaryVariant'" - date: 2021-11-19 - element: - uris: [ 'material.dart' ] - method: 'copyWith' - inClass: 'ColorScheme' - changes: - - kind: 'removeParameter' - name: 'primaryVariant' - - kind: 'removeParameter' - name: 'secondaryVariant' - - # Changes made in https://github.com/flutter/flutter/pull/93427 - - title: "Migrate 'primaryVariant' to 'primaryContainer'" - date: 2021-11-19 - element: - uris: [ 'material.dart' ] - getter: 'primaryVariant' - inClass: 'ColorScheme' - changes: - - kind: 'rename' - newName: 'primaryContainer' - - # Changes made in https://github.com/flutter/flutter/pull/93427 - - title: "Migrate 'secondaryVariant' to 'secondaryContainer'" - date: 2021-11-19 - element: - uris: [ 'material.dart' ] - getter: 'secondaryVariant' - inClass: 'ColorScheme' - changes: - - kind: 'rename' - newName: 'secondaryContainer' - - # Changes made in https://github.com/flutter/flutter/pull/93396 - - title: "Remove 'primaryColorBrightness'" - date: 2021-11-11 - element: - uris: [ 'material.dart' ] - method: 'copyWith' - inClass: 'ThemeData' - changes: - - kind: 'removeParameter' - name: 'primaryColorBrightness' - - # Changes made in https://github.com/flutter/flutter/pull/93396 - - title: "Remove 'primaryColorBrightness'" - date: 2021-11-11 - element: - uris: [ 'material.dart' ] - constructor: 'raw' - inClass: 'ThemeData' - changes: - - kind: 'removeParameter' - name: 'primaryColorBrightness' - - # Changes made in https://github.com/flutter/flutter/pull/93396 - - title: "Remove 'primaryColorBrightness'" - date: 2021-11-11 - element: - uris: [ 'material.dart' ] - constructor: '' - inClass: 'ThemeData' - changes: - - kind: 'removeParameter' - name: 'primaryColorBrightness' # Changes made in https://github.com/flutter/flutter/pull/86198 - title: "Migrate to 'backgroundColor'" diff --git a/packages/flutter/lib/src/animation/listener_helpers.dart b/packages/flutter/lib/src/animation/listener_helpers.dart index ebf2943bd99a5..85b488a95a874 100644 --- a/packages/flutter/lib/src/animation/listener_helpers.dart +++ b/packages/flutter/lib/src/animation/listener_helpers.dart @@ -137,17 +137,17 @@ mixin AnimationLocalListenersMixin { @protected @pragma('vm:notify-debugger-on-exception') void notifyListeners() { - final List localListeners = List.of(_listeners); + final List localListeners = List.from(_listeners); for (final VoidCallback listener in localListeners) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty( + collector = () sync* { + yield DiagnosticsProperty( 'The $runtimeType notifying listeners was', this, style: DiagnosticsTreeStyle.errorProperty, - ), - ]; + ); + }; return true; }()); try { @@ -226,7 +226,7 @@ mixin AnimationLocalStatusListenersMixin { @protected @pragma('vm:notify-debugger-on-exception') void notifyStatusListeners(AnimationStatus status) { - final List localListeners = List.of(_statusListeners); + final List localListeners = List.from(_statusListeners); for (final AnimationStatusListener listener in localListeners) { try { if (_statusListeners.contains(listener)) @@ -234,13 +234,13 @@ mixin AnimationLocalStatusListenersMixin { } catch (exception, stack) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty( + collector = () sync* { + yield DiagnosticsProperty( 'The $runtimeType notifying status listeners was', this, style: DiagnosticsTreeStyle.errorProperty, - ), - ]; + ); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( diff --git a/packages/flutter/lib/src/cupertino/activity_indicator.dart b/packages/flutter/lib/src/cupertino/activity_indicator.dart index 263271058f746..2efd97a1072a6 100644 --- a/packages/flutter/lib/src/cupertino/activity_indicator.dart +++ b/packages/flutter/lib/src/cupertino/activity_indicator.dart @@ -27,7 +27,6 @@ class CupertinoActivityIndicator extends StatefulWidget { /// Creates an iOS-style activity indicator that spins clockwise. const CupertinoActivityIndicator({ Key? key, - this.color, this.animating = true, this.radius = _kDefaultIndicatorRadius, }) : assert(animating != null), @@ -44,7 +43,6 @@ class CupertinoActivityIndicator extends StatefulWidget { /// to 1.0. const CupertinoActivityIndicator.partiallyRevealed({ Key? key, - this.color, this.radius = _kDefaultIndicatorRadius, this.progress = 1.0, }) : assert(radius != null), @@ -55,11 +53,6 @@ class CupertinoActivityIndicator extends StatefulWidget { animating = false, super(key: key); - /// Color of the activity indicator. - /// - /// Defaults to color extracted from native iOS. - final Color? color; - /// Whether the activity indicator is running its animation. /// /// Defaults to true. @@ -124,7 +117,8 @@ class _CupertinoActivityIndicatorState extends State child: CustomPaint( painter: _CupertinoActivityIndicatorPainter( position: _controller, - activeColor: widget.color ?? CupertinoDynamicColor.resolve(_kActiveTickColor, context), + activeColor: + CupertinoDynamicColor.resolve(_kActiveTickColor, context), radius: widget.radius, progress: widget.progress, ), diff --git a/packages/flutter/lib/src/cupertino/app.dart b/packages/flutter/lib/src/cupertino/app.dart index 5c9210a4d9b36..b305e75c54211 100644 --- a/packages/flutter/lib/src/cupertino/app.dart +++ b/packages/flutter/lib/src/cupertino/app.dart @@ -487,12 +487,10 @@ class _CupertinoAppState extends State { // of a particular LocalizationsDelegate.type is loaded so the // localizationsDelegate parameter can be used to override // _CupertinoLocalizationsDelegate. - Iterable> get _localizationsDelegates { - return >[ - if (widget.localizationsDelegates != null) - ...widget.localizationsDelegates!, - DefaultCupertinoLocalizations.delegate, - ]; + Iterable> get _localizationsDelegates sync* { + if (widget.localizationsDelegates != null) + yield* widget.localizationsDelegates!; + yield DefaultCupertinoLocalizations.delegate; } Widget _inspectorSelectButtonBuilder(BuildContext context, VoidCallback onPressed) { diff --git a/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart b/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart index 47d357531fd1e..cd01a9bb12161 100644 --- a/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart +++ b/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart @@ -65,7 +65,6 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { this.activeColor, this.inactiveColor = _kDefaultTabBarInactiveColor, this.iconSize = 30.0, - this.height = _kTabBarHeight, this.border = const Border( top: BorderSide( color: _kDefaultTabBarBorderColor, @@ -80,7 +79,6 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { assert(currentIndex != null), assert(0 <= currentIndex && currentIndex < items.length), assert(iconSize != null), - assert(height != null && height >= 0.0), assert(inactiveColor != null), super(key: key); @@ -131,18 +129,13 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { /// Must not be null. final double iconSize; - /// The height of the [CupertinoTabBar]. - /// - /// Defaults to 50.0. Must not be null. - final double height; - /// The border of the [CupertinoTabBar]. /// /// The default value is a one physical pixel top border with grey color. final Border? border; @override - Size get preferredSize => Size.fromHeight(height); + Size get preferredSize => const Size.fromHeight(_kTabBarHeight); /// Indicates whether the tab bar is fully opaque or can have contents behind /// it show through it. @@ -185,7 +178,7 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { color: backgroundColor, ), child: SizedBox( - height: height + bottomPadding, + height: _kTabBarHeight + bottomPadding, child: IconTheme.merge( // Default with the inactive state. data: IconThemeData(color: inactive, size: iconSize), child: DefaultTextStyle( // Default with the inactive state. @@ -261,6 +254,7 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { Expanded( child: Center(child: active ? item.activeIcon : item.icon), ), + if (item.title != null) item.title!, if (item.label != null) Text(item.label!), ]; } @@ -292,7 +286,6 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { Color? activeColor, Color? inactiveColor, double? iconSize, - double? height, Border? border, int? currentIndex, ValueChanged? onTap, @@ -304,7 +297,6 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { activeColor: activeColor ?? this.activeColor, inactiveColor: inactiveColor ?? this.inactiveColor, iconSize: iconSize ?? this.iconSize, - height: height ?? this.height, border: border ?? this.border, currentIndex: currentIndex ?? this.currentIndex, onTap: onTap ?? this.onTap, diff --git a/packages/flutter/lib/src/cupertino/button.dart b/packages/flutter/lib/src/cupertino/button.dart index 57e3139fa9faf..10a6dbdd600fa 100644 --- a/packages/flutter/lib/src/cupertino/button.dart +++ b/packages/flutter/lib/src/cupertino/button.dart @@ -26,13 +26,6 @@ const EdgeInsets _kBackgroundButtonPadding = EdgeInsets.symmetric( /// [EdgeInsets.zero], should be used to prevent clipping larger [child] /// widgets. /// -/// {@tool dartpad} -/// This sample shows produces an enabled and disabled [CupertinoButton] and -/// [CupertinoButton.filled]. -/// -/// ** See code in examples/api/lib/cupertino/button/cupertino_button.0.dart ** -/// {@end-tool} -/// /// See also: /// /// * diff --git a/packages/flutter/lib/src/cupertino/context_menu.dart b/packages/flutter/lib/src/cupertino/context_menu.dart index e5bc3e2ee56fc..caf0e82c94342 100644 --- a/packages/flutter/lib/src/cupertino/context_menu.dart +++ b/packages/flutter/lib/src/cupertino/context_menu.dart @@ -9,17 +9,10 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; -import 'colors.dart'; - // The scale of the child at the time that the CupertinoContextMenu opens. // This value was eyeballed from a physical device running iOS 13.1.2. const double _kOpenScale = 1.1; -const Color _borderColor = CupertinoDynamicColor.withBrightness( - color: Color(0xFFA9A9AF), - darkColor: Color(0xFF57585A), -); - typedef _DismissCallback = void Function( BuildContext context, double scale, @@ -1158,8 +1151,8 @@ class _ContextMenuSheet extends StatelessWidget { // Get the children, whose order depends on orientation and // contextMenuLocation. - List getChildren(BuildContext context) { - final Widget menu = Flexible( + List get children { + final Flexible menu = Flexible( fit: FlexFit.tight, flex: 2, child: IntrinsicHeight( @@ -1167,22 +1160,7 @@ class _ContextMenuSheet extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(13.0)), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - actions.first, - for (Widget action in actions.skip(1)) - DecoratedBox( - decoration: BoxDecoration( - border: Border( - top: BorderSide( - color: CupertinoDynamicColor.resolve(_borderColor, context), - width: 0.5, - ) - ), - ), - position: DecorationPosition.foreground, - child: action, - ), - ], + children: actions, ), ), ), @@ -1217,7 +1195,7 @@ class _ContextMenuSheet extends StatelessWidget { Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, - children: getChildren(context), + children: children, ); } } diff --git a/packages/flutter/lib/src/cupertino/context_menu_action.dart b/packages/flutter/lib/src/cupertino/context_menu_action.dart index c0dae6b8dc426..3be99045b0eb0 100644 --- a/packages/flutter/lib/src/cupertino/context_menu_action.dart +++ b/packages/flutter/lib/src/cupertino/context_menu_action.dart @@ -49,14 +49,8 @@ class CupertinoContextMenuAction extends StatefulWidget { } class _CupertinoContextMenuActionState extends State { - static const Color _kBackgroundColor = CupertinoDynamicColor.withBrightness( - color: Color(0xFFEEEEEE), - darkColor: Color(0xFF212122), - ); - static const Color _kBackgroundColorPressed = CupertinoDynamicColor.withBrightness( - color: Color(0xFFDDDDDD), - darkColor: Color(0xFF3F3F40), - ); + static const Color _kBackgroundColor = Color(0xFFEEEEEE); + static const Color _kBackgroundColorPressed = Color(0xFFDDDDDD); static const double _kButtonHeight = 56.0; static const TextStyle _kActionSheetActionStyle = TextStyle( fontFamily: '.SF UI Text', @@ -99,11 +93,10 @@ class _CupertinoContextMenuActionState extends State color: CupertinoColors.destructiveRed, ); } - return _kActionSheetActionStyle.copyWith( - color: CupertinoDynamicColor.resolve(CupertinoColors.label, context) - ); + return _kActionSheetActionStyle; } + @override Widget build(BuildContext context) { return GestureDetector( @@ -121,9 +114,10 @@ class _CupertinoContextMenuActionState extends State button: true, child: Container( decoration: BoxDecoration( - color: _isPressed - ? CupertinoDynamicColor.resolve(_kBackgroundColorPressed, context) - : CupertinoDynamicColor.resolve(_kBackgroundColor, context), + color: _isPressed ? _kBackgroundColorPressed : _kBackgroundColor, + border: const Border( + bottom: BorderSide(color: _kBackgroundColorPressed), + ), ), padding: const EdgeInsets.symmetric( vertical: 16.0, diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart index 9c1eae809620e..eaadaf83033e2 100644 --- a/packages/flutter/lib/src/cupertino/date_picker.dart +++ b/packages/flutter/lib/src/cupertino/date_picker.dart @@ -202,16 +202,6 @@ enum _PickerColumnType { /// full screen width. Content texts are shown with /// [CupertinoTextThemeData.dateTimePickerTextStyle]. /// -/// {@tool dartpad} -/// This sample shows how to implement CupertinoDatePicker with different picker modes. -/// We can provide intiial dateTime value for the picker to display. When user changes -/// the drag the date or time wheels, the picker will call onDateTimeChanged callback. -/// -/// CupertinoDatePicker can be displayed directly on a screen or in a popup. -/// -/// ** See code in examples/api/lib/cupertino/date_picker/cupertino_date_picker.0.dart ** -/// {@end-tool} -/// /// See also: /// /// * [CupertinoTimerPicker], the class that implements the iOS-style timer picker. diff --git a/packages/flutter/lib/src/cupertino/desktop_text_selection.dart b/packages/flutter/lib/src/cupertino/desktop_text_selection.dart index 73530d4a1aee8..6b1f89b45b67f 100644 --- a/packages/flutter/lib/src/cupertino/desktop_text_selection.dart +++ b/packages/flutter/lib/src/cupertino/desktop_text_selection.dart @@ -245,6 +245,7 @@ class _CupertinoDesktopTextSelectionToolbar extends StatelessWidget { Key? key, required this.anchor, required this.children, + this.toolbarBuilder = _defaultToolbarBuilder, }) : assert(children.length > 0), super(key: key); @@ -259,6 +260,12 @@ class _CupertinoDesktopTextSelectionToolbar extends StatelessWidget { /// Mac-style text selection toolbar text button. final List children; + /// {@macro flutter.material.TextSelectionToolbar.toolbarBuilder} + /// + /// The given anchor and isAbove can be used to position an arrow, as in the + /// default Cupertino toolbar. + final ToolbarBuilder toolbarBuilder; + // Builds a toolbar just like the default Mac toolbar, with the right color // background, padding, and rounded corners. static Widget _defaultToolbarBuilder(BuildContext context, Widget child) { @@ -301,7 +308,7 @@ class _CupertinoDesktopTextSelectionToolbar extends StatelessWidget { delegate: DesktopTextSelectionToolbarLayoutDelegate( anchor: anchor - localAdjustment, ), - child: _defaultToolbarBuilder(context, Column( + child: toolbarBuilder(context, Column( mainAxisSize: MainAxisSize.min, children: children, )), diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index b66f729c1bd64..32076a4c5f27e 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -1675,7 +1675,11 @@ class _ActionButtonParentDataWidget // ParentData applied to individual action buttons that report whether or not // that button is currently pressed by the user. class _ActionButtonParentData extends MultiChildLayoutParentData { - bool isPressed = false; + _ActionButtonParentData({ + this.isPressed = false, + }); + + bool isPressed; } /// A button typically used in a [CupertinoAlertDialog]. @@ -2046,18 +2050,16 @@ class _RenderCupertinoDialogActions extends RenderBox markNeedsPaint(); } - Iterable get _pressedButtons { - final List boxes = []; + Iterable get _pressedButtons sync* { RenderBox? currentChild = firstChild; while (currentChild != null) { assert(currentChild.parentData is _ActionButtonParentData); final _ActionButtonParentData parentData = currentChild.parentData! as _ActionButtonParentData; if (parentData.isPressed) { - boxes.add(currentChild); + yield currentChild; } currentChild = childAfter(currentChild); } - return boxes; } bool get _isButtonPressed { diff --git a/packages/flutter/lib/src/cupertino/icons.dart b/packages/flutter/lib/src/cupertino/icons.dart index d214511b3a382..270c1269d6480 100644 --- a/packages/flutter/lib/src/cupertino/icons.dart +++ b/packages/flutter/lib/src/cupertino/icons.dart @@ -21,40 +21,11 @@ import 'package:flutter/widgets.dart'; /// cupertino_icons: ^1.0.0 /// ``` /// -/// {@tool snippet} +/// [![icon gallery preview](https://raw.githubusercontent.com/flutter/cupertino_icons/master/gallery_preview_1.0.0.png)](https://flutter.github.io/cupertino_icons) /// -/// This example shows how to create a [Row] of Cupertino [Icon]s in different colors and -/// sizes. The first [Icon] uses a [Icon.semanticLabel] to announce in accessibility -/// modes like VoiceOver. +/// For versions 1.0.0 and above (available only on Flutter SDK versions 1.22+), see the [Cupertino Icons Gallery](https://flutter.github.io/cupertino_icons). /// -/// ![The following code snippet would generate a row of icons consisting of a pink heart, a green bell, and a blue umbrella, each progressively bigger than the last.](https://flutter.github.io/assets-for-api-docs/assets/cupertino/cupertino_icon.png) -/// -/// ```dart -/// Row( -/// mainAxisAlignment: MainAxisAlignment.spaceAround, -/// children: const [ -/// Icon( -/// CupertinoIcons.heart_fill, -/// color: Colors.pink, -/// size: 24.0, -/// semanticLabel: 'Text to announce in accessibility modes', -/// ), -/// Icon( -/// CupertinoIcons.bell_fill, -/// color: Colors.green, -/// size: 30.0, -/// ), -/// Icon( -/// CupertinoIcons.umbrella_fill, -/// color: Colors.blue, -/// size: 36.0, -/// ), -/// ], -/// ) -/// ``` -/// {@end-tool} -/// -/// For versions 0.1.3 and below, see this [glyph map](https://raw.githubusercontent.com/flutter/packages/master/third_party/packages/cupertino_icons/map.png). +/// For versions 0.1.3 and below, see this [glyph map](https://raw.githubusercontent.com/flutter/cupertino_icons/master/map.png). /// /// See also: /// diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index 983fe61c91f8e..faffbfd9a0c16 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -25,19 +25,6 @@ const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds. // user releases a page mid swipe. const int _kMaxPageBackAnimationTime = 300; // Milliseconds. -/// Barrier color used for a barrier visible during transitions for Cupertino -/// page routes. -/// -/// This barrier color is only used for full-screen page routes with -/// `fullscreenDialog: false`. -/// -/// By default, `fullscreenDialog` Cupertino route transitions have no -/// `barrierColor`, and [CupertinoDialogRoute]s and [CupertinoModalPopupRoute]s -/// have a `barrierColor` defined by [kCupertinoModalBarrierColor]. -/// -/// A relatively rigorous eyeball estimation. -const Color _kCupertinoPageTransitionBarrierColor = Color(0x18000000); - /// Barrier color for a Cupertino modal barrier. /// /// Extracted from https://developer.apple.com/design/resources/. @@ -139,7 +126,7 @@ mixin CupertinoRouteTransitionMixin on PageRoute { Duration get transitionDuration => const Duration(milliseconds: 400); @override - Color? get barrierColor => fullscreenDialog ? null : _kCupertinoPageTransitionBarrierColor; + Color? get barrierColor => null; @override String? get barrierLabel => null; @@ -804,6 +791,8 @@ class _CupertinoEdgeShadowDecoration extends Decoration { end: const _CupertinoEdgeShadowDecoration._( // Eyeballed gradient used to mimic a drop shadow on the start side only. [ + Color(0x38000000), + Color(0x12000000), Color(0x04000000), Color(0x00000000), ], diff --git a/packages/flutter/lib/src/cupertino/scrollbar.dart b/packages/flutter/lib/src/cupertino/scrollbar.dart index 30dfa519ada75..7e468fbd97e87 100644 --- a/packages/flutter/lib/src/cupertino/scrollbar.dart +++ b/packages/flutter/lib/src/cupertino/scrollbar.dart @@ -32,8 +32,6 @@ const double _kScrollbarCrossAxisMargin = 3.0; /// To add a scrollbar to a [ScrollView], simply wrap the scroll view widget in /// a [CupertinoScrollbar] widget. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=DbkIQSvwnZc} -/// /// {@macro flutter.widgets.Scrollbar} /// /// When dragging a [CupertinoScrollbar] thumb, the thickness and radius will diff --git a/packages/flutter/lib/src/cupertino/tab_view.dart b/packages/flutter/lib/src/cupertino/tab_view.dart index 6da4c2bec0058..955d94033e7ba 100644 --- a/packages/flutter/lib/src/cupertino/tab_view.dart +++ b/packages/flutter/lib/src/cupertino/tab_view.dart @@ -159,7 +159,7 @@ class _CupertinoTabViewState extends State { void _updateObservers() { _navigatorObservers = - List.of(widget.navigatorObservers) + List.from(widget.navigatorObservers) ..add(_heroController); } diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index ec74f6b701895..2631716cf3f67 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -177,8 +177,6 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe /// rounded rectangle border around the text field. If you set the [decoration] /// property to null, the decoration will be removed entirely. /// -/// {@macro flutter.material.textfield.wantKeepAlive} -/// /// Remember to call [TextEditingController.dispose] when it is no longer /// needed. This will ensure we discard any resources used by the object. /// @@ -290,7 +288,7 @@ class CupertinoTextField extends StatefulWidget { this.keyboardAppearance, this.scrollPadding = const EdgeInsets.all(20.0), this.dragStartBehavior = DragStartBehavior.start, - bool? enableInteractiveSelection, + this.enableInteractiveSelection = true, this.selectionControls, this.onTap, this.scrollController, @@ -344,31 +342,17 @@ class CupertinoTextField extends StatefulWidget { assert(enableIMEPersonalizedLearning != null), assert(contentCommitMimeTypes != null), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), - enableInteractiveSelection = enableInteractiveSelection ?? (!readOnly || !obscureText), - toolbarOptions = toolbarOptions ?? - (obscureText - ? (readOnly - // No point in even offering "Select All" in a read-only obscured - // field. - ? const ToolbarOptions() - // Writable, but obscured. - : const ToolbarOptions( - selectAll: true, - paste: true, - )) - : (readOnly - // Read-only, not obscured. - ? const ToolbarOptions( - selectAll: true, - copy: true, - ) - // Writable, not obscured. - : const ToolbarOptions( - copy: true, - cut: true, - selectAll: true, - paste: true, - ))), + toolbarOptions = toolbarOptions ?? (obscureText ? + const ToolbarOptions( + selectAll: true, + paste: true, + ) : + const ToolbarOptions( + copy: true, + cut: true, + selectAll: true, + paste: true, + )), super(key: key); /// Creates a borderless iOS-style text field. @@ -464,7 +448,7 @@ class CupertinoTextField extends StatefulWidget { this.keyboardAppearance, this.scrollPadding = const EdgeInsets.all(20.0), this.dragStartBehavior = DragStartBehavior.start, - bool? enableInteractiveSelection, + this.enableInteractiveSelection = true, this.selectionControls, this.onTap, this.scrollController, @@ -519,31 +503,17 @@ class CupertinoTextField extends StatefulWidget { assert(enableIMEPersonalizedLearning != null), assert(contentCommitMimeTypes!= null), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), - enableInteractiveSelection = enableInteractiveSelection ?? (!readOnly || !obscureText), - toolbarOptions = toolbarOptions ?? - (obscureText - ? (readOnly - // No point in even offering "Select All" in a read-only obscured - // field. - ? const ToolbarOptions() - // Writable, but obscured. - : const ToolbarOptions( - selectAll: true, - paste: true, - )) - : (readOnly - // Read-only, not obscured. - ? const ToolbarOptions( - selectAll: true, - copy: true, - ) - // Writable, not obscured. - : const ToolbarOptions( - copy: true, - cut: true, - selectAll: true, - paste: true, - ))), + toolbarOptions = toolbarOptions ?? (obscureText ? + const ToolbarOptions( + selectAll: true, + paste: true, + ) : + const ToolbarOptions( + copy: true, + cut: true, + selectAll: true, + paste: true, + )), super(key: key); /// Controls the text being edited. @@ -1007,7 +977,6 @@ class _CupertinoTextFieldState extends State with Restoratio _createLocalController(); } _effectiveFocusNode.canRequestFocus = widget.enabled ?? true; - _effectiveFocusNode.addListener(_handleFocusChanged); } @override @@ -1095,30 +1064,15 @@ class _CupertinoTextFieldState extends State with Restoratio } void _handleSelectionChanged(TextSelection selection, SelectionChangedCause? cause) { + if (cause == SelectionChangedCause.longPress) { + _editableText.bringIntoView(selection.base); + } final bool willShowSelectionHandles = _shouldShowSelectionHandles(cause); if (willShowSelectionHandles != _showSelectionHandles) { setState(() { _showSelectionHandles = willShowSelectionHandles; }); } - - switch (defaultTargetPlatform) { - case TargetPlatform.iOS: - case TargetPlatform.macOS: - if (cause == SelectionChangedCause.longPress - || cause == SelectionChangedCause.drag) { - _editableText.bringIntoView(selection.extent); - } - return; - case TargetPlatform.linux: - case TargetPlatform.windows: - case TargetPlatform.fuchsia: - case TargetPlatform.android: - if (cause == SelectionChangedCause.drag) { - _editableText.bringIntoView(selection.extent); - } - return; - } } @override @@ -1285,14 +1239,15 @@ class _CupertinoTextFieldState extends State with Restoratio case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.linux: + case TargetPlatform.windows: textSelectionControls ??= cupertinoTextSelectionControls; break; case TargetPlatform.macOS: - case TargetPlatform.windows: textSelectionControls ??= cupertinoDesktopTextSelectionControls; handleDidGainAccessibilityFocus = () { - // Automatically activate the TextField when it receives accessibility focus. + // macOS automatically activated the TextField when it receives + // accessibility focus. if (!_effectiveFocusNode.hasFocus && _effectiveFocusNode.canRequestFocus) { _effectiveFocusNode.requestFocus(); } diff --git a/packages/flutter/lib/src/foundation/assertions.dart b/packages/flutter/lib/src/foundation/assertions.dart index a6c8c417823b5..827188c2a63ab 100644 --- a/packages/flutter/lib/src/foundation/assertions.dart +++ b/packages/flutter/lib/src/foundation/assertions.dart @@ -248,7 +248,6 @@ abstract class _ErrorDiagnostic extends DiagnosticsProperty> { /// problem that was detected. /// * [ErrorHint], which provides specific, non-obvious advice that may be /// applicable. -/// * [ErrorSpacer], which renders as a blank line. /// * [FlutterError], which is the most common place to use an /// [ErrorDescription]. class ErrorDescription extends _ErrorDiagnostic { @@ -324,7 +323,6 @@ class ErrorSummary extends _ErrorDiagnostic { /// * [ErrorDescription], which provides an explanation of the problem and its /// cause, any information that may help track down the problem, background /// information, etc. -/// * [ErrorSpacer], which renders as a blank line. /// * [FlutterError], which is the most common place to use an [ErrorHint]. class ErrorHint extends _ErrorDiagnostic { /// A lint enforces that this constructor can only be called with a string @@ -518,52 +516,14 @@ class FlutterErrorDetails with Diagnosticable { /// This won't be called if [stack] is null. final IterableFilter? stackFilter; - /// A callback which will provide information that could help with debugging - /// the problem. + /// A callback which, when called with a [StringBuffer] will write to that buffer + /// information that could help with debugging the problem. /// - /// Information collector callbacks can be expensive, so the generated - /// information should be cached by the caller, rather than the callback being - /// called multiple times. + /// Information collector callbacks can be expensive, so the generated information + /// should be cached, rather than the callback being called multiple times. /// - /// The callback is expected to return an iterable of [DiagnosticsNode] objects, - /// typically implemented using `sync*` and `yield`. - /// - /// {@tool snippet} - /// In this example, the information collector returns two pieces of information, - /// one broadly-applicable statement regarding how the error happened, and one - /// giving a specific piece of information that may be useful in some cases but - /// may also be irrelevant most of the time (an argument to the method). - /// - /// ```dart - /// void climbElevator(int pid) { - /// try { - /// // ... - /// } catch (error, stack) { - /// FlutterError.reportError(FlutterErrorDetails( - /// exception: error, - /// stack: stack, - /// informationCollector: () => [ - /// ErrorDescription('This happened while climbing the space elevator.'), - /// ErrorHint('The process ID is: $pid'), - /// ], - /// )); - /// } - /// } - /// ``` - /// {@end-tool} - /// - /// The following classes may be of particular use: - /// - /// * [ErrorDescription], for information that is broadly applicable to the - /// situation being described. - /// * [ErrorHint], for specific information that may not always be applicable - /// but can be helpful in certain situations. - /// * [DiagnosticsStackTrace], for reporting stack traces. - /// * [ErrorSpacer], for adding spaces (a blank line) between other items. - /// - /// For objects that implement [Diagnosticable] one may consider providing - /// additional information by yielding the output of the object's - /// [Diagnosticable.toDiagnosticsNode] method. + /// The text written to the information argument may contain newlines but should + /// not end with a newline. final InformationCollector? informationCollector; /// Whether this error should be ignored by the default error reporting diff --git a/packages/flutter/lib/src/foundation/basic_types.dart b/packages/flutter/lib/src/foundation/basic_types.dart index 09dfbf948bba8..ac04f7baf33b2 100644 --- a/packages/flutter/lib/src/foundation/basic_types.dart +++ b/packages/flutter/lib/src/foundation/basic_types.dart @@ -113,7 +113,7 @@ class CachingIterable extends IterableBase { /// once. If you have an [Iterable], you can pass its [iterator] /// field as the argument to this constructor. /// - /// You can this with an existing `sync*` function as follows: + /// You can use a `sync*` function with this as follows: /// /// ```dart /// Iterable range(int start, int end) sync* { @@ -125,10 +125,6 @@ class CachingIterable extends IterableBase { /// print(i.length); // walks the list /// print(i.length); // efficient /// ``` - /// - /// Beware that this will eagerly evaluate the `range` iterable, and because - /// of that it would be better to just implement `range` as something that - /// returns a `List` to begin with if possible. CachingIterable(this._prefillIterator); final Iterator _prefillIterator; @@ -183,7 +179,7 @@ class CachingIterable extends IterableBase { @override List toList({ bool growable = true }) { _precacheEntireList(); - return List.of(_results, growable: growable); + return List.from(_results, growable: growable); } void _precacheEntireList() { diff --git a/packages/flutter/lib/src/foundation/bitfield.dart b/packages/flutter/lib/src/foundation/bitfield.dart index 5cb5383a24236..e0b07a8032e17 100644 --- a/packages/flutter/lib/src/foundation/bitfield.dart +++ b/packages/flutter/lib/src/foundation/bitfield.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import '_bitfield_io.dart' - if (dart.library.html) '_bitfield_web.dart' as bitfield; + if (dart.library.html) '_bitfield_web.dart' as _bitfield; /// The largest SMI value. /// @@ -11,7 +11,7 @@ import '_bitfield_io.dart' /// /// When compiling to JavaScript, this value is not supported since it is /// larger than the maximum safe 32bit integer. -const int kMaxUnsignedSMI = bitfield.kMaxUnsignedSMI; +const int kMaxUnsignedSMI = _bitfield.kMaxUnsignedSMI; /// A BitField over an enum (or other class whose values implement "index"). /// Only the first 62 values of the enum can be used as indices. @@ -21,7 +21,7 @@ abstract class BitField { /// Creates a bit field of all zeros. /// /// The given length must be at most 62. - factory BitField(int length) = bitfield.BitField; + factory BitField(int length) = _bitfield.BitField; /// Creates a bit field filled with a particular value. /// @@ -29,7 +29,7 @@ abstract class BitField { /// the bits are filled with zeros. /// /// The given length must be at most 62. - factory BitField.filled(int length, bool value) = bitfield.BitField.filled; + factory BitField.filled(int length, bool value) = _bitfield.BitField.filled; /// Returns whether the bit with the given index is set to one. bool operator [](T index); diff --git a/packages/flutter/lib/src/foundation/change_notifier.dart b/packages/flutter/lib/src/foundation/change_notifier.dart index a910f03e713e6..095054ba95e6f 100644 --- a/packages/flutter/lib/src/foundation/change_notifier.dart +++ b/packages/flutter/lib/src/foundation/change_notifier.dart @@ -312,13 +312,13 @@ class ChangeNotifier implements Listenable { stack: stack, library: 'foundation library', context: ErrorDescription('while dispatching notifications for $runtimeType'), - informationCollector: () => [ - DiagnosticsProperty( + informationCollector: () sync* { + yield DiagnosticsProperty( 'The $runtimeType sending notification was', this, style: DiagnosticsTreeStyle.errorProperty, - ), - ], + ); + }, )); } } diff --git a/packages/flutter/lib/src/foundation/debug.dart b/packages/flutter/lib/src/foundation/debug.dart index 55969f16e3026..66251f29c45cd 100644 --- a/packages/flutter/lib/src/foundation/debug.dart +++ b/packages/flutter/lib/src/foundation/debug.dart @@ -35,18 +35,6 @@ bool debugAssertAllFoundationVarsUnset(String reason, { DebugPrintCallback debug /// Boolean value indicating whether [debugInstrumentAction] will instrument /// actions in debug builds. -/// -/// The framework does not use [debugInstrumentAction] internally, so this -/// does not enable any additional instrumentation for the framework itself. -/// -/// See also: -/// -/// * [debugProfileBuildsEnabled], which enables additional tracing of builds -/// in [Widget]s. -/// * [debugProfileLayoutsEnabled], which enables additional tracing of layout -/// events in [RenderObject]s. -/// * [debugProfilePaintsEnabled], which enables additional tracing of paint -/// events in [RenderObject]s. bool debugInstrumentationEnabled = false; /// Runs the specified [action], timing how long the action takes in debug @@ -88,9 +76,6 @@ Future debugInstrumentAction(String description, Future Function() acti /// /// Generally these indicate landmark events such as the build phase or layout. /// -/// [DiagnosticsNode.toTimelineArguments] includes these properties in its -/// result. -/// /// See also: /// /// * [dart:developer.Timeline.startSync], which typically takes this value as diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart index c18f627d69a30..c6b1e0c6a14b8 100644 --- a/packages/flutter/lib/src/foundation/diagnostics.dart +++ b/packages/flutter/lib/src/foundation/diagnostics.dart @@ -870,12 +870,12 @@ class _PrefixedStringBuilder { /// /// This method wraps a sequence of text where only some spans of text can be /// used as wrap boundaries. - static Iterable _wordWrapLine(String message, List wrapRanges, int width, { int startOffset = 0, int otherLineOffset = 0}) { + static Iterable _wordWrapLine(String message, List wrapRanges, int width, { int startOffset = 0, int otherLineOffset = 0}) sync* { if (message.length + startOffset < width) { // Nothing to do. The line doesn't wrap. - return [message]; + yield message; + return; } - final List wrappedLine = []; int startForLengthCalculations = -startOffset; bool addPrefix = false; int index = 0; @@ -920,10 +920,10 @@ class _PrefixedStringBuilder { lastWordEnd = index; } final String line = message.substring(start, lastWordEnd); - wrappedLine.add(line); + yield line; addPrefix = true; if (lastWordEnd >= message.length) - return wrappedLine; + return; // just yielded a line if (lastWordEnd == index) { // we broke at current position @@ -1265,7 +1265,7 @@ class TextTreeRenderer { // we should not place a separator between the name and the value. // Essentially in this case the properties are treated a bit like a value. if ((properties.isNotEmpty || children.isNotEmpty || node.emptyBodyDescription != null) && - (node.showSeparator || description.isNotEmpty)) { + (node.showSeparator || description?.isNotEmpty == true)) { builder.write(config.afterDescriptionIfBody); } @@ -1474,7 +1474,7 @@ abstract class DiagnosticsNode { /// `parentConfiguration` specifies how the parent is rendered as text art. /// For example, if the parent does not line break between properties, the /// description of a property should also be a single line if possible. - String toDescription({ TextTreeConfiguration? parentConfiguration }); + String? toDescription({ TextTreeConfiguration? parentConfiguration }); /// Whether to show a separator between [name] and description. /// @@ -1544,44 +1544,6 @@ abstract class DiagnosticsNode { String get _separator => showSeparator ? ':' : ''; - /// Converts the properties ([getProperties]) of this node to a form useful - /// for [Timeline] event arguments (as in [Timeline.startSync]). - /// - /// The properties specified by [timelineArgumentsIndicatingLandmarkEvent] are - /// included in the result. - /// - /// Children ([getChildren]) are omitted. - /// - /// This method is only valid in debug builds. In profile builds, this method - /// throws an exception. In release builds, it returns a copy of - /// [timelineArgumentsIndicatingLandmarkEvent] with no arguments added. - /// - /// See also: - /// - /// * [toJsonMap], which converts this node to a structured form intended for - /// data exchange (e.g. with an IDE). - Map toTimelineArguments() { - final Map result = Map.of(timelineArgumentsIndicatingLandmarkEvent); - if (!kReleaseMode) { - // We don't throw in release builds, to avoid hurting users. We also don't do anything useful. - if (kProfileMode) { - throw FlutterError( - // Parts of this string are searched for verbatim by a test in dev/bots/test.dart. - '$DiagnosticsNode.toTimelineArguments used in non-debug build.\n' - 'The $DiagnosticsNode.toTimelineArguments API is expensive and causes timeline traces ' - 'to be non-representative. As such, it should not be used in profile builds. However, ' - 'this application is compiled in profile mode and yet still invoked the method.' - ); - } - for (final DiagnosticsNode property in getProperties()) { - if (property.name != null) { - result[property.name!] = property.toDescription(parentConfiguration: singleLineTextConfiguration); - } - } - } - return result; - } - /// Serialize the node to a JSON map according to the configuration provided /// in the [DiagnosticsSerializationDelegate]. /// @@ -1606,13 +1568,13 @@ abstract class DiagnosticsNode { if (!showSeparator) 'showSeparator': showSeparator, if (level != DiagnosticLevel.info) - 'level': level.name, + 'level': describeEnum(level), if (showName == false) 'showName': showName, if (emptyBodyDescription != null) 'emptyBodyDescription': emptyBodyDescription, if (style != DiagnosticsTreeStyle.sparse) - 'style': style!.name, + 'style': describeEnum(style!), if (allowTruncate) 'allowTruncate': allowTruncate, if (hasChildren) @@ -1693,7 +1655,7 @@ abstract class DiagnosticsNode { if (_isSingleLine(style)) { result = toStringDeep(parentConfiguration: parentConfiguration, minLevel: minLevel); } else { - final String description = toDescription(parentConfiguration: parentConfiguration); + final String description = toDescription(parentConfiguration: parentConfiguration)!; if (name == null || name!.isEmpty || !showName) { result = description; @@ -2341,12 +2303,6 @@ class IterableProperty extends DiagnosticsProperty> { /// The enum value is displayed with the class name stripped. For example: /// [HitTestBehavior.deferToChild] is shown as `deferToChild`. /// -/// This class can be used with classes that appear like enums but are not -/// "real" enums, so long as their `toString` implementation, in debug mode, -/// returns a string consisting of the class name followed by the value name. It -/// can also be used with nullable properties; the null value is represented as -/// `null`. -/// /// See also: /// /// * [DiagnosticsProperty] which documents named parameters common to all @@ -2590,10 +2546,12 @@ class FlagsSummary extends DiagnosticsProperty> { // // For a null value, it is omitted unless `includeEmpty` is true and // [ifEntryNull] contains a corresponding description. - Iterable _formattedValues() { - return value.entries - .where((MapEntry entry) => entry.value != null) - .map((MapEntry entry) => entry.key); + Iterable _formattedValues() sync* { + for (final MapEntry entry in value.entries) { + if (entry.value != null) { + yield entry.key; + } + } } } @@ -2744,7 +2702,7 @@ class DiagnosticsProperty extends DiagnosticsNode { if (exception != null) json['exception'] = exception.toString(); json['propertyType'] = propertyType.toString(); - json['defaultLevel'] = _defaultLevel.name; + json['defaultLevel'] = describeEnum(_defaultLevel); if (value is Diagnosticable || value is DiagnosticsNode) json['isDiagnosticableValue'] = true; if (v is num) @@ -3058,19 +3016,11 @@ String shortHash(Object? object) { /// * [Object.runtimeType], the [Type] of an object. String describeIdentity(Object? object) => '${objectRuntimeType(object, '')}#${shortHash(object)}'; +// This method exists as a workaround for https://github.com/dart-lang/sdk/issues/30021 /// Returns a short description of an enum value. /// /// Strips off the enum class name from the `enumEntry.toString()`. /// -/// For real enums, this is redundant with calling the `name` getter on the enum -/// value (see [EnumName.name]), a feature that was added to Dart 2.15. -/// -/// This function can also be used with classes whose `toString` return a value -/// in the same form as an enum (the class name, a dot, then the value name). -/// For example, it's used with [SemanticsAction], which is written to appear to -/// be an enum but is actually a bespoke class so that the index values can be -/// set as powers of two instead of as sequential integers. -/// /// {@tool snippet} /// /// ```dart @@ -3081,13 +3031,10 @@ String describeIdentity(Object? object) => '${objectRuntimeType(object, ' children = const[], List properties = const [], - }) : _description = description ?? '', + }) : _description = description, _children = children, _properties = properties, super( @@ -3611,7 +3558,7 @@ class DiagnosticsBlock extends DiagnosticsNode { @override final DiagnosticLevel level; - final String _description; + final String? _description; @override final Object? value; @@ -3626,7 +3573,7 @@ class DiagnosticsBlock extends DiagnosticsNode { List getProperties() => _properties; @override - String toDescription({TextTreeConfiguration? parentConfiguration}) => _description; + String? toDescription({TextTreeConfiguration? parentConfiguration}) => _description; } /// A delegate that configures how a hierarchy of [DiagnosticsNode]s should be diff --git a/packages/flutter/lib/src/foundation/isolates.dart b/packages/flutter/lib/src/foundation/isolates.dart index 8a1c151037809..8ecdd4786e14c 100644 --- a/packages/flutter/lib/src/foundation/isolates.dart +++ b/packages/flutter/lib/src/foundation/isolates.dart @@ -5,7 +5,7 @@ import 'dart:async'; import '_isolates_io.dart' - if (dart.library.html) '_isolates_web.dart' as isolates; + if (dart.library.html) '_isolates_web.dart' as _isolates; /// Signature for the callback passed to [compute]. /// @@ -26,11 +26,9 @@ typedef ComputeCallback = FutureOr Function(Q message); /// few milliseconds, consider [SchedulerBinding.scheduleTask] instead. /// /// {@template flutter.foundation.compute.types} -/// The [compute] method accepts the following parameters: +/// `Q` is the type of the message that kicks off the computation. /// -/// * `Q` is the type of the message that kicks off the computation. -/// -/// * `R` is the type of the value returned. +/// `R` is the type of the value returned. /// {@endtemplate} /// /// The `callback` argument must be a top-level function, not a closure or an @@ -46,13 +44,9 @@ typedef ComputeCallback = FutureOr Function(Q message); /// [Timeline]. This is useful when profiling an application. typedef ComputeImpl = Future Function(ComputeCallback callback, Q message, { String? debugLabel }); -/// A function that spawns an isolate and runs a callback on that isolate. This -/// method should be used to execute parallel tasks that reduce the risk of -/// skipping frames. -/// -/// {@youtube 560 315 https://www.youtube.com/watch?v=5AxWC49ZMzs} +/// A function that spawns an isolate and runs a callback on that isolate. /// /// See also: /// /// * [ComputeImpl], for function parameters and usage details. -const ComputeImpl compute = isolates.compute; +const ComputeImpl compute = _isolates.compute; diff --git a/packages/flutter/lib/src/foundation/licenses.dart b/packages/flutter/lib/src/foundation/licenses.dart index 47c072ec47bdd..7983ba3add478 100644 --- a/packages/flutter/lib/src/foundation/licenses.dart +++ b/packages/flutter/lib/src/foundation/licenses.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. -import 'dart:async'; - import 'package:meta/meta.dart' show visibleForTesting; /// Signature for callbacks passed to [LicenseRegistry.addLicense]. @@ -72,8 +70,8 @@ enum _LicenseEntryWithLineBreaksParserState { /// /// ```dart /// void initMyLibrary() { -/// LicenseRegistry.addLicense(() => Stream.value( -/// const LicenseEntryWithLineBreaks(['my_library'], ''' +/// LicenseRegistry.addLicense(() async* { +/// yield const LicenseEntryWithLineBreaks(['my_library'], ''' /// Copyright 2016 The Sample Authors. All rights reserved. /// /// Redistribution and use in source and binary forms, with or without @@ -100,9 +98,8 @@ enum _LicenseEntryWithLineBreaksParserState { /// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY /// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT /// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -/// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', -/// ), -/// )); +/// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'''); +/// }); /// } /// ``` /// {@end-tool} @@ -142,7 +139,7 @@ class LicenseEntryWithLineBreaks extends LicenseEntry { final String text; @override - Iterable get paragraphs { + Iterable get paragraphs sync* { int lineStart = 0; int currentPosition = 0; int lastLineIndent = 0; @@ -150,7 +147,6 @@ class LicenseEntryWithLineBreaks extends LicenseEntry { int? currentParagraphIndentation; _LicenseEntryWithLineBreaksParserState state = _LicenseEntryWithLineBreaksParserState.beforeParagraph; final List lines = []; - final List result = []; void addLine() { assert(lineStart < currentPosition); @@ -186,7 +182,7 @@ class LicenseEntryWithLineBreaks extends LicenseEntry { case '\n': case '\f': if (lines.isNotEmpty) { - result.add(getParagraph()); + yield getParagraph(); } if (text[currentPosition] == '\r' && currentPosition < text.length - 1 && text[currentPosition + 1] == '\n') { @@ -210,7 +206,7 @@ class LicenseEntryWithLineBreaks extends LicenseEntry { startParagraph: default: if (lines.isNotEmpty && currentLineIndent > lastLineIndent) { - result.add(getParagraph()); + yield getParagraph(); currentParagraphIndentation = null; } // The following is a wild heuristic for guessing the indentation level. @@ -235,7 +231,7 @@ class LicenseEntryWithLineBreaks extends LicenseEntry { break; case '\f': addLine(); - result.add(getParagraph()); + yield getParagraph(); lastLineIndent = 0; currentLineIndent = 0; currentParagraphIndentation = null; @@ -252,15 +248,14 @@ class LicenseEntryWithLineBreaks extends LicenseEntry { switch (state) { case _LicenseEntryWithLineBreaksParserState.beforeParagraph: if (lines.isNotEmpty) { - result.add(getParagraph()); + yield getParagraph(); } break; case _LicenseEntryWithLineBreaksParserState.inParagraph: addLine(); - result.add(getParagraph()); + yield getParagraph(); break; } - return result; } } @@ -312,19 +307,11 @@ class LicenseRegistry { /// Returns the licenses that have been registered. /// /// Generating the list of licenses is expensive. - static Stream get licenses { + static Stream get licenses async* { if (_collectors == null) - return const Stream.empty(); - - late final StreamController controller; - controller = StreamController( - onListen: () async { - for (final LicenseEntryCollector collector in _collectors!) - await controller.addStream(collector()); - await controller.close(); - }, - ); - return controller.stream; + return; + for (final LicenseEntryCollector collector in _collectors!) + yield* collector(); } /// Resets the internal state of [LicenseRegistry]. Intended for use in diff --git a/packages/flutter/lib/src/foundation/platform.dart b/packages/flutter/lib/src/foundation/platform.dart index bff47ff3d9561..9dd1eca5a6a7d 100644 --- a/packages/flutter/lib/src/foundation/platform.dart +++ b/packages/flutter/lib/src/foundation/platform.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import '_platform_io.dart' - if (dart.library.html) '_platform_web.dart' as platform; + if (dart.library.html) '_platform_web.dart' as _platform; /// The [TargetPlatform] that matches the platform on which the framework is /// currently executing. @@ -36,7 +36,7 @@ import '_platform_io.dart' // that would mean we'd be stuck with that platform forever emulating the other, // and we'd never be able to introduce dedicated behavior for that platform // (since doing so would be a big breaking change). -TargetPlatform get defaultTargetPlatform => platform.defaultTargetPlatform; +TargetPlatform get defaultTargetPlatform => _platform.defaultTargetPlatform; /// The platform that user interaction should adapt to target. /// diff --git a/packages/flutter/lib/src/foundation/print.dart b/packages/flutter/lib/src/foundation/print.dart index f9d3f89cb459d..b12f4902cc314 100644 --- a/packages/flutter/lib/src/foundation/print.dart +++ b/packages/flutter/lib/src/foundation/print.dart @@ -113,11 +113,11 @@ enum _WordWrapParseMode { inSpace, inWord, atBreak } /// and so forth. It is only intended for formatting error messages. /// /// The default [debugPrint] implementation uses this for its line wrapping. -Iterable debugWordWrap(String message, int width, { String wrapIndent = '' }) { +Iterable debugWordWrap(String message, int width, { String wrapIndent = '' }) sync* { if (message.length < width || message.trimLeft()[0] == '#') { - return [message]; + yield message; + return; } - final List wrapped = []; final Match prefixMatch = _indentPattern.matchAsPrefix(message)!; final String prefix = wrapIndent + ' ' * prefixMatch.group(0)!.length; int start = 0; @@ -149,13 +149,13 @@ Iterable debugWordWrap(String message, int width, { String wrapIndent = lastWordEnd = index; } if (addPrefix) { - wrapped.add(prefix + message.substring(start, lastWordEnd)); + yield prefix + message.substring(start, lastWordEnd); } else { - wrapped.add(message.substring(start, lastWordEnd)); + yield message.substring(start, lastWordEnd); addPrefix = true; } if (lastWordEnd >= message.length) - return wrapped; + return; // just yielded a line if (lastWordEnd == index) { // we broke at current position diff --git a/packages/flutter/lib/src/gestures/binding.dart b/packages/flutter/lib/src/gestures/binding.dart index 38fc388fdbfa9..241eb10538297 100644 --- a/packages/flutter/lib/src/gestures/binding.dart +++ b/packages/flutter/lib/src/gestures/binding.dart @@ -407,9 +407,9 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H library: 'gesture library', context: ErrorDescription('while dispatching a non-hit-tested pointer event'), event: event, - informationCollector: () => [ - DiagnosticsProperty('Event', event, style: DiagnosticsTreeStyle.errorProperty), - ], + informationCollector: () sync* { + yield DiagnosticsProperty('Event', event, style: DiagnosticsTreeStyle.errorProperty); + }, )); } return; @@ -425,10 +425,10 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H context: ErrorDescription('while dispatching a pointer event'), event: event, hitTestEntry: entry, - informationCollector: () => [ - DiagnosticsProperty('Event', event, style: DiagnosticsTreeStyle.errorProperty), - DiagnosticsProperty('Target', entry.target, style: DiagnosticsTreeStyle.errorProperty), - ], + informationCollector: () sync* { + yield DiagnosticsProperty('Event', event, style: DiagnosticsTreeStyle.errorProperty); + yield DiagnosticsProperty('Target', entry.target, style: DiagnosticsTreeStyle.errorProperty); + }, )); } } diff --git a/packages/flutter/lib/src/gestures/converter.dart b/packages/flutter/lib/src/gestures/converter.dart index 561c75320e40e..5eb673d71435a 100644 --- a/packages/flutter/lib/src/gestures/converter.dart +++ b/packages/flutter/lib/src/gestures/converter.dart @@ -44,188 +44,197 @@ class PointerEventConverter { /// [dart:ui.FlutterView.devicePixelRatio]) is used to convert the incoming data /// from physical coordinates to logical pixels. See the discussion at /// [PointerEvent] for more details on the [PointerEvent] coordinate space. - static Iterable expand(Iterable data, double devicePixelRatio) { - return data - .where((ui.PointerData datum) => datum.signalKind != ui.PointerSignalKind.unknown) - .map((ui.PointerData datum) { - final Offset position = Offset(datum.physicalX, datum.physicalY) / devicePixelRatio; - assert(position != null); - final Offset delta = Offset(datum.physicalDeltaX, datum.physicalDeltaY) / devicePixelRatio; - final double radiusMinor = _toLogicalPixels(datum.radiusMinor, devicePixelRatio); - final double radiusMajor = _toLogicalPixels(datum.radiusMajor, devicePixelRatio); - final double radiusMin = _toLogicalPixels(datum.radiusMin, devicePixelRatio); - final double radiusMax = _toLogicalPixels(datum.radiusMax, devicePixelRatio); - final Duration timeStamp = datum.timeStamp; - final PointerDeviceKind kind = datum.kind; - assert(datum.change != null); - switch (datum.signalKind ?? ui.PointerSignalKind.none) { - case ui.PointerSignalKind.none: - switch (datum.change) { - case ui.PointerChange.add: - return PointerAddedEvent( - timeStamp: timeStamp, - kind: kind, - device: datum.device, - position: position, - obscured: datum.obscured, - pressureMin: datum.pressureMin, - pressureMax: datum.pressureMax, - distance: datum.distance, - distanceMax: datum.distanceMax, - radiusMin: radiusMin, - radiusMax: radiusMax, - orientation: datum.orientation, - tilt: datum.tilt, - embedderId: datum.embedderId, - ); - case ui.PointerChange.hover: - return PointerHoverEvent( - timeStamp: timeStamp, - kind: kind, - device: datum.device, - position: position, - delta: delta, - buttons: datum.buttons, - obscured: datum.obscured, - pressureMin: datum.pressureMin, - pressureMax: datum.pressureMax, - distance: datum.distance, - distanceMax: datum.distanceMax, - size: datum.size, - radiusMajor: radiusMajor, - radiusMinor: radiusMinor, - radiusMin: radiusMin, - radiusMax: radiusMax, - orientation: datum.orientation, - tilt: datum.tilt, - synthesized: datum.synthesized, - embedderId: datum.embedderId, - ); - case ui.PointerChange.down: - return PointerDownEvent( - timeStamp: timeStamp, - pointer: datum.pointerIdentifier, - kind: kind, - device: datum.device, - position: position, - buttons: _synthesiseDownButtons(datum.buttons, kind), - obscured: datum.obscured, - pressure: datum.pressure, - pressureMin: datum.pressureMin, - pressureMax: datum.pressureMax, - distanceMax: datum.distanceMax, - size: datum.size, - radiusMajor: radiusMajor, - radiusMinor: radiusMinor, - radiusMin: radiusMin, - radiusMax: radiusMax, - orientation: datum.orientation, - tilt: datum.tilt, - embedderId: datum.embedderId, - ); - case ui.PointerChange.move: - return PointerMoveEvent( - timeStamp: timeStamp, - pointer: datum.pointerIdentifier, - kind: kind, - device: datum.device, - position: position, - delta: delta, - buttons: _synthesiseDownButtons(datum.buttons, kind), - obscured: datum.obscured, - pressure: datum.pressure, - pressureMin: datum.pressureMin, - pressureMax: datum.pressureMax, - distanceMax: datum.distanceMax, - size: datum.size, - radiusMajor: radiusMajor, - radiusMinor: radiusMinor, - radiusMin: radiusMin, - radiusMax: radiusMax, - orientation: datum.orientation, - tilt: datum.tilt, - platformData: datum.platformData, - synthesized: datum.synthesized, - embedderId: datum.embedderId, - ); - case ui.PointerChange.up: - return PointerUpEvent( - timeStamp: timeStamp, - pointer: datum.pointerIdentifier, - kind: kind, - device: datum.device, - position: position, - buttons: datum.buttons, - obscured: datum.obscured, - pressure: datum.pressure, - pressureMin: datum.pressureMin, - pressureMax: datum.pressureMax, - distance: datum.distance, - distanceMax: datum.distanceMax, - size: datum.size, - radiusMajor: radiusMajor, - radiusMinor: radiusMinor, - radiusMin: radiusMin, - radiusMax: radiusMax, - orientation: datum.orientation, - tilt: datum.tilt, - embedderId: datum.embedderId, - ); - case ui.PointerChange.cancel: - return PointerCancelEvent( - timeStamp: timeStamp, - pointer: datum.pointerIdentifier, - kind: kind, - device: datum.device, - position: position, - buttons: datum.buttons, - obscured: datum.obscured, - pressureMin: datum.pressureMin, - pressureMax: datum.pressureMax, - distance: datum.distance, - distanceMax: datum.distanceMax, - size: datum.size, - radiusMajor: radiusMajor, - radiusMinor: radiusMinor, - radiusMin: radiusMin, - radiusMax: radiusMax, - orientation: datum.orientation, - tilt: datum.tilt, - embedderId: datum.embedderId, - ); - case ui.PointerChange.remove: - return PointerRemovedEvent( - timeStamp: timeStamp, - kind: kind, - device: datum.device, - position: position, - obscured: datum.obscured, - pressureMin: datum.pressureMin, - pressureMax: datum.pressureMax, - distanceMax: datum.distanceMax, - radiusMin: radiusMin, - radiusMax: radiusMax, - embedderId: datum.embedderId, - ); - } - case ui.PointerSignalKind.scroll: - final Offset scrollDelta = - Offset(datum.scrollDeltaX, datum.scrollDeltaY) / devicePixelRatio; - return PointerScrollEvent( - timeStamp: timeStamp, - kind: kind, - device: datum.device, - position: position, - scrollDelta: scrollDelta, - embedderId: datum.embedderId, - ); - case ui.PointerSignalKind.unknown: - // This branch should already have 'unknown' filtered out, but - // we don't want to return anything or miss if someone adds a new - // enumeration to PointerSignalKind. - throw StateError('Unreachable'); - } - }); + static Iterable expand(Iterable data, double devicePixelRatio) sync* { + for (final ui.PointerData datum in data) { + final Offset position = Offset(datum.physicalX, datum.physicalY) / devicePixelRatio; + assert(position != null); + final Offset delta = Offset(datum.physicalDeltaX, datum.physicalDeltaY) / devicePixelRatio; + final double radiusMinor = _toLogicalPixels(datum.radiusMinor, devicePixelRatio); + final double radiusMajor = _toLogicalPixels(datum.radiusMajor, devicePixelRatio); + final double radiusMin = _toLogicalPixels(datum.radiusMin, devicePixelRatio); + final double radiusMax = _toLogicalPixels(datum.radiusMax, devicePixelRatio); + final Duration timeStamp = datum.timeStamp; + final PointerDeviceKind kind = datum.kind; + assert(datum.change != null); + if (datum.signalKind == null || datum.signalKind == ui.PointerSignalKind.none) { + switch (datum.change) { + case ui.PointerChange.add: + yield PointerAddedEvent( + timeStamp: timeStamp, + kind: kind, + device: datum.device, + position: position, + obscured: datum.obscured, + pressureMin: datum.pressureMin, + pressureMax: datum.pressureMax, + distance: datum.distance, + distanceMax: datum.distanceMax, + radiusMin: radiusMin, + radiusMax: radiusMax, + orientation: datum.orientation, + tilt: datum.tilt, + embedderId: datum.embedderId, + ); + break; + case ui.PointerChange.hover: + yield PointerHoverEvent( + timeStamp: timeStamp, + kind: kind, + device: datum.device, + position: position, + delta: delta, + buttons: datum.buttons, + obscured: datum.obscured, + pressureMin: datum.pressureMin, + pressureMax: datum.pressureMax, + distance: datum.distance, + distanceMax: datum.distanceMax, + size: datum.size, + radiusMajor: radiusMajor, + radiusMinor: radiusMinor, + radiusMin: radiusMin, + radiusMax: radiusMax, + orientation: datum.orientation, + tilt: datum.tilt, + synthesized: datum.synthesized, + embedderId: datum.embedderId, + ); + break; + case ui.PointerChange.down: + yield PointerDownEvent( + timeStamp: timeStamp, + pointer: datum.pointerIdentifier, + kind: kind, + device: datum.device, + position: position, + buttons: _synthesiseDownButtons(datum.buttons, kind), + obscured: datum.obscured, + pressure: datum.pressure, + pressureMin: datum.pressureMin, + pressureMax: datum.pressureMax, + distanceMax: datum.distanceMax, + size: datum.size, + radiusMajor: radiusMajor, + radiusMinor: radiusMinor, + radiusMin: radiusMin, + radiusMax: radiusMax, + orientation: datum.orientation, + tilt: datum.tilt, + embedderId: datum.embedderId, + ); + break; + case ui.PointerChange.move: + yield PointerMoveEvent( + timeStamp: timeStamp, + pointer: datum.pointerIdentifier, + kind: kind, + device: datum.device, + position: position, + delta: delta, + buttons: _synthesiseDownButtons(datum.buttons, kind), + obscured: datum.obscured, + pressure: datum.pressure, + pressureMin: datum.pressureMin, + pressureMax: datum.pressureMax, + distanceMax: datum.distanceMax, + size: datum.size, + radiusMajor: radiusMajor, + radiusMinor: radiusMinor, + radiusMin: radiusMin, + radiusMax: radiusMax, + orientation: datum.orientation, + tilt: datum.tilt, + platformData: datum.platformData, + synthesized: datum.synthesized, + embedderId: datum.embedderId, + ); + break; + case ui.PointerChange.up: + yield PointerUpEvent( + timeStamp: timeStamp, + pointer: datum.pointerIdentifier, + kind: kind, + device: datum.device, + position: position, + buttons: datum.buttons, + obscured: datum.obscured, + pressure: datum.pressure, + pressureMin: datum.pressureMin, + pressureMax: datum.pressureMax, + distance: datum.distance, + distanceMax: datum.distanceMax, + size: datum.size, + radiusMajor: radiusMajor, + radiusMinor: radiusMinor, + radiusMin: radiusMin, + radiusMax: radiusMax, + orientation: datum.orientation, + tilt: datum.tilt, + embedderId: datum.embedderId, + ); + break; + case ui.PointerChange.cancel: + yield PointerCancelEvent( + timeStamp: timeStamp, + pointer: datum.pointerIdentifier, + kind: kind, + device: datum.device, + position: position, + buttons: datum.buttons, + obscured: datum.obscured, + pressureMin: datum.pressureMin, + pressureMax: datum.pressureMax, + distance: datum.distance, + distanceMax: datum.distanceMax, + size: datum.size, + radiusMajor: radiusMajor, + radiusMinor: radiusMinor, + radiusMin: radiusMin, + radiusMax: radiusMax, + orientation: datum.orientation, + tilt: datum.tilt, + embedderId: datum.embedderId, + ); + break; + case ui.PointerChange.remove: + yield PointerRemovedEvent( + timeStamp: timeStamp, + kind: kind, + device: datum.device, + position: position, + obscured: datum.obscured, + pressureMin: datum.pressureMin, + pressureMax: datum.pressureMax, + distanceMax: datum.distanceMax, + radiusMin: radiusMin, + radiusMax: radiusMax, + embedderId: datum.embedderId, + ); + break; + } + } else { + switch (datum.signalKind!) { + case ui.PointerSignalKind.scroll: + final Offset scrollDelta = + Offset(datum.scrollDeltaX, datum.scrollDeltaY) / devicePixelRatio; + yield PointerScrollEvent( + timeStamp: timeStamp, + kind: kind, + device: datum.device, + position: position, + scrollDelta: scrollDelta, + embedderId: datum.embedderId, + ); + break; + case ui.PointerSignalKind.none: + assert(false); // This branch should already have 'none' filtered out. + break; + case ui.PointerSignalKind.unknown: + // Ignore unknown signals. + break; + } + } + } } static double _toLogicalPixels(double physicalPixels, double devicePixelRatio) => physicalPixels / devicePixelRatio; diff --git a/packages/flutter/lib/src/gestures/monodrag.dart b/packages/flutter/lib/src/gestures/monodrag.dart index 6385e881ad91e..a3aaeb3bf2ccc 100644 --- a/packages/flutter/lib/src/gestures/monodrag.dart +++ b/packages/flutter/lib/src/gestures/monodrag.dart @@ -614,13 +614,7 @@ class HorizontalDragGestureRecognizer extends DragGestureRecognizer { /// some time has passed. class PanGestureRecognizer extends DragGestureRecognizer { /// Create a gesture recognizer for tracking movement on a plane. - PanGestureRecognizer({ - Object? debugOwner, - Set? supportedDevices, - }) : super( - debugOwner: debugOwner, - supportedDevices: supportedDevices, - ); + PanGestureRecognizer({ Object? debugOwner }) : super(debugOwner: debugOwner); @override bool isFlingGesture(VelocityEstimate estimate, PointerDeviceKind kind) { diff --git a/packages/flutter/lib/src/gestures/multitap.dart b/packages/flutter/lib/src/gestures/multitap.dart index f19377e3b303f..b210c8bece95c 100644 --- a/packages/flutter/lib/src/gestures/multitap.dart +++ b/packages/flutter/lib/src/gestures/multitap.dart @@ -583,7 +583,7 @@ class MultiTapGestureRecognizer extends GestureRecognizer { @override void dispose() { - final List<_TapGesture> localGestures = List<_TapGesture>.of(_gestureMap.values); + final List<_TapGesture> localGestures = List<_TapGesture>.from(_gestureMap.values); for (final _TapGesture gesture in localGestures) gesture.cancel(); // Rejection of each gesture should cause it to be removed from our map diff --git a/packages/flutter/lib/src/gestures/pointer_router.dart b/packages/flutter/lib/src/gestures/pointer_router.dart index beb36df18adbe..0b8c17b72350e 100644 --- a/packages/flutter/lib/src/gestures/pointer_router.dart +++ b/packages/flutter/lib/src/gestures/pointer_router.dart @@ -95,11 +95,11 @@ class PointerRouter { } catch (exception, stack) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty('router', this, level: DiagnosticLevel.debug), - DiagnosticsProperty('route', route, level: DiagnosticLevel.debug), - DiagnosticsProperty('event', event, level: DiagnosticLevel.debug), - ]; + collector = () sync* { + yield DiagnosticsProperty('router', this, level: DiagnosticLevel.debug); + yield DiagnosticsProperty('route', route, level: DiagnosticLevel.debug); + yield DiagnosticsProperty('event', event, level: DiagnosticLevel.debug); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( @@ -118,12 +118,12 @@ class PointerRouter { /// PointerRouter object. void route(PointerEvent event) { final Map? routes = _routeMap[event.pointer]; - final Map copiedGlobalRoutes = Map.of(_globalRoutes); + final Map copiedGlobalRoutes = Map.from(_globalRoutes); if (routes != null) { _dispatchEventToRoutes( event, routes, - Map.of(routes), + Map.from(routes), ); } _dispatchEventToRoutes(event, _globalRoutes, copiedGlobalRoutes); diff --git a/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart b/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart index a79af56551143..8d162c36e036a 100644 --- a/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart +++ b/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart @@ -89,9 +89,9 @@ class PointerSignalResolver { } catch (exception, stack) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty('Event', event, style: DiagnosticsTreeStyle.errorProperty), - ]; + collector = () sync* { + yield DiagnosticsProperty('Event', event, style: DiagnosticsTreeStyle.errorProperty); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( diff --git a/packages/flutter/lib/src/gestures/recognizer.dart b/packages/flutter/lib/src/gestures/recognizer.dart index 3c061867de5b9..b94f760673bfe 100644 --- a/packages/flutter/lib/src/gestures/recognizer.dart +++ b/packages/flutter/lib/src/gestures/recognizer.dart @@ -199,10 +199,10 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT } catch (exception, stack) { InformationCollector? collector; assert(() { - collector = () => [ - StringProperty('Handler', name), - DiagnosticsProperty('Recognizer', this, style: DiagnosticsTreeStyle.errorProperty), - ]; + collector = () sync* { + yield StringProperty('Handler', name); + yield DiagnosticsProperty('Recognizer', this, style: DiagnosticsTreeStyle.errorProperty); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( @@ -300,7 +300,7 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer { @protected @mustCallSuper void resolve(GestureDisposition disposition) { - final List localEntries = List.of(_entries.values); + final List localEntries = List.from(_entries.values); _entries.clear(); for (final GestureArenaEntry entry in localEntries) entry.resolve(disposition); diff --git a/packages/flutter/lib/src/gestures/tap.dart b/packages/flutter/lib/src/gestures/tap.dart index 4df877f8b74e5..8209fa404fff6 100644 --- a/packages/flutter/lib/src/gestures/tap.dart +++ b/packages/flutter/lib/src/gestures/tap.dart @@ -136,10 +136,8 @@ typedef GestureTapCancelCallback = void Function(); /// any buttons. abstract class BaseTapGestureRecognizer extends PrimaryPointerGestureRecognizer { /// Creates a tap gesture recognizer. - /// - /// {@macro flutter.gestures.GestureRecognizer.supportedDevices} - BaseTapGestureRecognizer({ Object? debugOwner, Set? supportedDevices }) - : super(deadline: kPressTimeout , debugOwner: debugOwner, supportedDevices: supportedDevices); + BaseTapGestureRecognizer({ Object? debugOwner }) + : super(deadline: kPressTimeout , debugOwner: debugOwner); bool _sentTapDown = false; bool _wonArenaForPrimaryPointer = false; @@ -348,10 +346,7 @@ abstract class BaseTapGestureRecognizer extends PrimaryPointerGestureRecognizer /// * [MultiTapGestureRecognizer] class TapGestureRecognizer extends BaseTapGestureRecognizer { /// Creates a tap gesture recognizer. - /// - /// {@macro flutter.gestures.GestureRecognizer.supportedDevices} - TapGestureRecognizer({ Object? debugOwner, Set? supportedDevices }) - : super(debugOwner: debugOwner, supportedDevices: supportedDevices); + TapGestureRecognizer({ Object? debugOwner }) : super(debugOwner: debugOwner); /// A pointer has contacted the screen at a particular location with a primary /// button, which might be the start of a tap. diff --git a/packages/flutter/lib/src/gestures/team.dart b/packages/flutter/lib/src/gestures/team.dart index ea124b016a9fe..e2eee5573a8b2 100644 --- a/packages/flutter/lib/src/gestures/team.dart +++ b/packages/flutter/lib/src/gestures/team.dart @@ -114,13 +114,11 @@ class _CombiningGestureArenaMember extends GestureArenaMember { /// [AndroidView] uses a team with a captain to decide which gestures are /// forwarded to the native view. For example if we want to forward taps and /// vertical scrolls to a native Android view, [TapGestureRecognizer]s and -/// [VerticalDragGestureRecognizer] are added to a team with a captain (the -/// captain is set to be a gesture recognizer that never explicitly claims the -/// gesture). -/// -/// The captain allows [AndroidView] to know when any gestures in the team has -/// been recognized (or all other arena members are out), once the captain wins -/// the gesture is forwarded to the Android view. +/// [VerticalDragGestureRecognizer] are added to a team with a captain(the captain is set to be a +/// gesture recognizer that never explicitly claims the gesture). +/// The captain allows [AndroidView] to know when any gestures in the team has been +/// recognized (or all other arena members are out), once the captain wins the +/// gesture is forwarded to the Android view. /// /// To assign a gesture recognizer to a team, set /// [OneSequenceGestureRecognizer.team] to an instance of [GestureArenaTeam]. diff --git a/packages/flutter/lib/src/material/about.dart b/packages/flutter/lib/src/material/about.dart index 847a469313788..e796cf9ad6b2d 100644 --- a/packages/flutter/lib/src/material/about.dart +++ b/packages/flutter/lib/src/material/about.dart @@ -16,6 +16,7 @@ import 'constants.dart'; import 'debug.dart'; import 'dialog.dart'; import 'divider.dart'; +import 'floating_action_button.dart'; import 'floating_action_button_location.dart'; import 'ink_decoration.dart'; import 'list_tile.dart'; @@ -920,14 +921,12 @@ class _PackageLicensePageTitle extends StatelessWidget { @override Widget build(BuildContext context) { - final Color? color = Theme.of(context).appBarTheme.foregroundColor; - return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: theme.headline6?.copyWith(color: color)), - Text(subtitle, style: theme.subtitle2?.copyWith(color: color)), + Text(title, style: theme.headline6), + Text(subtitle, style: theme.subtitle2), ], ); } @@ -984,6 +983,9 @@ enum _ActionLevel { /// Indicates the master view app bar in the lateral UI. view, + + /// Indicates the master page app bar in the nested UI. + composite, } /// Describes which layout will be used by [_MasterDetailFlow]. @@ -1017,9 +1019,20 @@ class _MasterDetailFlow extends StatefulWidget { Key? key, required this.detailPageBuilder, required this.masterViewBuilder, + this.actionBuilder, this.automaticallyImplyLeading = true, + this.breakpoint, + this.centerTitle, + this.detailPageFABGutterWidth, this.detailPageFABlessGutterWidth, this.displayMode = _LayoutMode.auto, + this.flexibleSpace, + this.floatingActionButton, + this.floatingActionButtonLocation, + this.floatingActionButtonMasterPageLocation, + this.leading, + this.masterPageBuilder, + this.masterViewWidth, this.title, }) : assert(masterViewBuilder != null), assert(automaticallyImplyLeading != null), @@ -1033,6 +1046,13 @@ class _MasterDetailFlow extends StatefulWidget { /// builds the master view inside a [Scaffold] with an [AppBar]. final _MasterViewBuilder masterViewBuilder; + /// Builder for the master page for nested navigation. + /// + /// This builder is usually a wrapper around the [masterViewBuilder] builder to provide the + /// extra UI required to make a page. However, this builder is optional, and the master page + /// can be built using the master view builder and the configuration for the lateral UI's app bar. + final _MasterViewBuilder? masterPageBuilder; + /// Builder for the detail page. /// /// If scrollController == null, the page is intended for nested navigation. The lateral detail @@ -1041,22 +1061,74 @@ class _MasterDetailFlow extends StatefulWidget { /// page is scrollable. final _DetailPageBuilder detailPageBuilder; + /// Override the width of the master view in the lateral UI. + final double? masterViewWidth; + + /// Override the width of the floating action button gutter in the lateral UI. + final double? detailPageFABGutterWidth; + /// Override the width of the gutter when there is no floating action button. final double? detailPageFABlessGutterWidth; + /// Add a floating action button to the lateral UI. If no [masterPageBuilder] is supplied, this + /// floating action button is also used on the nested master page. + /// + /// See [Scaffold.floatingActionButton]. + final FloatingActionButton? floatingActionButton; + /// The title for the lateral UI [AppBar]. /// /// See [AppBar.title]. final Widget? title; + /// A widget to display before the title for the lateral UI [AppBar]. + /// + /// See [AppBar.leading]. + final Widget? leading; + /// Override the framework from determining whether to show a leading widget or not. /// /// See [AppBar.automaticallyImplyLeading]. final bool automaticallyImplyLeading; + /// Override the framework from determining whether to display the title in the center of the + /// app bar or not. + /// + /// See [AppBar.centerTitle]. + final bool? centerTitle; + + /// See [AppBar.flexibleSpace]. + final Widget? flexibleSpace; + + /// Build actions for the lateral UI, and potentially the master page in the nested UI. + /// + /// If level is [_ActionLevel.top] then the actions are for + /// the entire lateral UI page. If level is [_ActionLevel.view] the actions + /// are for the master + /// view toolbar. Finally, if the [AppBar] for the master page for the nested UI is being built + /// by [_MasterDetailFlow], then [_ActionLevel.composite] indicates the + /// actions are for the + /// nested master page. + final _ActionBuilder? actionBuilder; + + /// Determine where the floating action button will go. + /// + /// If null, [FloatingActionButtonLocation.endTop] is used. + /// + /// Also see [Scaffold.floatingActionButtonLocation]. + final FloatingActionButtonLocation? floatingActionButtonLocation; + + /// Determine where the floating action button will go on the master page. + /// + /// See [Scaffold.floatingActionButtonLocation]. + final FloatingActionButtonLocation? floatingActionButtonMasterPageLocation; + /// Forces display mode and style. final _LayoutMode displayMode; + /// Width at which layout changes from nested to lateral. + final double? breakpoint; + @override _MasterDetailFlowState createState() => _MasterDetailFlowState(); @@ -1150,7 +1222,7 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp case _LayoutMode.auto: return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { final double availableWidth = constraints.maxWidth; - if (availableWidth >= _materialWideDisplayThreshold) { + if (availableWidth >= (widget.breakpoint ?? _materialWideDisplayThreshold)) { return _lateralUI(context); } else { return _nestedUI(context); @@ -1203,13 +1275,21 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp MaterialPageRoute _masterPageRoute(BuildContext context) { return MaterialPageRoute( builder: (BuildContext c) => BlockSemantics( - child: _MasterPage( - leading: widget.automaticallyImplyLeading && Navigator.of(context).canPop() + child: widget.masterPageBuilder != null + ? widget.masterPageBuilder!(c, false) + : _MasterPage( + leading: widget.leading ?? + (widget.automaticallyImplyLeading && Navigator.of(context).canPop() ? BackButton(onPressed: () => Navigator.of(context).pop()) - : null, + : null), title: widget.title, + centerTitle: widget.centerTitle, + flexibleSpace: widget.flexibleSpace, automaticallyImplyLeading: widget.automaticallyImplyLeading, + floatingActionButton: widget.floatingActionButton, + floatingActionButtonLocation: widget.floatingActionButtonMasterPageLocation, masterViewBuilder: widget.masterViewBuilder, + actionBuilder: widget.actionBuilder, ), ), ); @@ -1232,13 +1312,19 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp Widget _lateralUI(BuildContext context) { _builtLayout = _LayoutMode.lateral; return _MasterDetailScaffold( - actionBuilder: (_, __) => const[], + actionBuilder: widget.actionBuilder ?? (_, __) => const[], automaticallyImplyLeading: widget.automaticallyImplyLeading, + centerTitle: widget.centerTitle, detailPageBuilder: (BuildContext context, Object? args, ScrollController? scrollController) => widget.detailPageBuilder(context, args ?? _cachedDetailArguments, scrollController), + floatingActionButton: widget.floatingActionButton, detailPageFABlessGutterWidth: widget.detailPageFABlessGutterWidth, + detailPageFABGutterWidth: widget.detailPageFABGutterWidth, + floatingActionButtonLocation: widget.floatingActionButtonLocation, initialArguments: _cachedDetailArguments, + leading: widget.leading, masterViewBuilder: (BuildContext context, bool isLateral) => widget.masterViewBuilder(context, isLateral), + masterViewWidth: widget.masterViewWidth, title: widget.title, ); } @@ -1249,6 +1335,11 @@ class _MasterPage extends StatelessWidget { Key? key, this.leading, this.title, + this.actionBuilder, + this.centerTitle, + this.flexibleSpace, + this.floatingActionButton, + this.floatingActionButtonLocation, this.masterViewBuilder, required this.automaticallyImplyLeading, }) : super(key: key); @@ -1257,6 +1348,11 @@ class _MasterPage extends StatelessWidget { final Widget? title; final Widget? leading; final bool automaticallyImplyLeading; + final bool? centerTitle; + final Widget? flexibleSpace; + final _ActionBuilder? actionBuilder; + final FloatingActionButton? floatingActionButton; + final FloatingActionButtonLocation? floatingActionButtonLocation; @override Widget build(BuildContext context) { @@ -1264,10 +1360,16 @@ class _MasterPage extends StatelessWidget { appBar: AppBar( title: title, leading: leading, - actions: const [], + actions: actionBuilder == null + ? const [] + : actionBuilder!(context, _ActionLevel.composite), + centerTitle: centerTitle, + flexibleSpace: flexibleSpace, automaticallyImplyLeading: automaticallyImplyLeading, ), body: masterViewBuilder!(context, false), + floatingActionButton: floatingActionButton, + floatingActionButtonLocation: floatingActionButtonLocation, ); } @@ -1284,10 +1386,16 @@ class _MasterDetailScaffold extends StatefulWidget { required this.detailPageBuilder, required this.masterViewBuilder, this.actionBuilder, + this.floatingActionButton, + this.floatingActionButtonLocation, this.initialArguments, + this.leading, this.title, required this.automaticallyImplyLeading, + this.centerTitle, this.detailPageFABlessGutterWidth, + this.detailPageFABGutterWidth, + this.masterViewWidth, }) : assert(detailPageBuilder != null), assert(masterViewBuilder != null), super(key: key); @@ -1301,10 +1409,16 @@ class _MasterDetailScaffold extends StatefulWidget { /// lateral page is scrollable. final _DetailPageBuilder detailPageBuilder; final _ActionBuilder? actionBuilder; + final FloatingActionButton? floatingActionButton; + final FloatingActionButtonLocation? floatingActionButtonLocation; final Object? initialArguments; + final Widget? leading; final Widget? title; final bool automaticallyImplyLeading; + final bool? centerTitle; final double? detailPageFABlessGutterWidth; + final double? detailPageFABGutterWidth; + final double? masterViewWidth; @override _MasterDetailScaffoldState createState() => _MasterDetailScaffoldState(); @@ -1323,9 +1437,9 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold> void initState() { super.initState(); detailPageFABlessGutterWidth = widget.detailPageFABlessGutterWidth ?? _kDetailPageFABlessGutterWidth; - detailPageFABGutterWidth = _kDetailPageFABGutterWidth; - masterViewWidth = _kMasterViewWidth; - floatingActionButtonLocation = FloatingActionButtonLocation.endTop; + detailPageFABGutterWidth = widget.detailPageFABGutterWidth ?? _kDetailPageFABGutterWidth; + masterViewWidth = widget.masterViewWidth ?? _kMasterViewWidth; + floatingActionButtonLocation = widget.floatingActionButtonLocation ?? FloatingActionButtonLocation.endTop; } @override @@ -1351,7 +1465,9 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold> appBar: AppBar( title: widget.title, actions: widget.actionBuilder!(context, _ActionLevel.top), + leading: widget.leading, automaticallyImplyLeading: widget.automaticallyImplyLeading, + centerTitle: widget.centerTitle, bottom: PreferredSize( preferredSize: const Size.fromHeight(kToolbarHeight), child: Row( @@ -1376,13 +1492,16 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold> ), ), body: _masterPanel(context), + floatingActionButton: widget.floatingActionButton, ), // Detail view stacked above main scaffold and master view. SafeArea( child: Padding( padding: EdgeInsetsDirectional.only( start: masterViewWidth - _kCardElevation, - end: detailPageFABlessGutterWidth, + end: widget.floatingActionButton == null + ? detailPageFABlessGutterWidth + : detailPageFABGutterWidth, ), child: ValueListenableBuilder( valueListenable: _detailArguments, @@ -1422,7 +1541,9 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold> appBar: AppBar( title: widget.title, actions: widget.actionBuilder!(context, _ActionLevel.top), + leading: widget.leading, automaticallyImplyLeading: widget.automaticallyImplyLeading, + centerTitle: widget.centerTitle, ), body: widget.masterViewBuilder(context, true), ) diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart index acc572928c265..e26a49a0cd1b9 100644 --- a/packages/flutter/lib/src/material/app.dart +++ b/packages/flutter/lib/src/material/app.dart @@ -797,13 +797,11 @@ class _MaterialAppState extends State { // of a particular LocalizationsDelegate.type is loaded so the // localizationsDelegate parameter can be used to override // _MaterialLocalizationsDelegate. - Iterable> get _localizationsDelegates { - return >[ - if (widget.localizationsDelegates != null) - ...widget.localizationsDelegates!, - DefaultMaterialLocalizations.delegate, - DefaultCupertinoLocalizations.delegate, - ]; + Iterable> get _localizationsDelegates sync* { + if (widget.localizationsDelegates != null) + yield* widget.localizationsDelegates!; + yield DefaultMaterialLocalizations.delegate; + yield DefaultCupertinoLocalizations.delegate; } Widget _inspectorSelectButtonBuilder(BuildContext context, VoidCallback onPressed) { diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index 086095c70bb0d..2248976880732 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -1047,7 +1047,7 @@ class _AppBarState extends State { ? _systemOverlayStyleForBrightness( widget.brightness ?? appBarTheme.brightness - ?? ThemeData.estimateBrightnessForColor(backgroundColor), + ?? theme.primaryColorBrightness, ) : widget.systemOverlayStyle ?? appBarTheme.systemOverlayStyle diff --git a/packages/flutter/lib/src/material/bottom_navigation_bar.dart b/packages/flutter/lib/src/material/bottom_navigation_bar.dart index c40ccbb5234d3..7f0999fd14b64 100644 --- a/packages/flutter/lib/src/material/bottom_navigation_bar.dart +++ b/packages/flutter/lib/src/material/bottom_navigation_bar.dart @@ -185,8 +185,9 @@ class BottomNavigationBar extends StatefulWidget { }) : assert(items != null), assert(items.length >= 2), assert( + items.every((BottomNavigationBarItem item) => item.title != null) || items.every((BottomNavigationBarItem item) => item.label != null), - 'Every item must have a non-null label', + 'Every item must have a non-null title or label', ), assert(0 <= currentIndex && currentIndex < items.length), assert(elevation == null || elevation >= 0.0), @@ -246,13 +247,13 @@ class BottomNavigationBar extends StatefulWidget { final double iconSize; /// The color of the selected [BottomNavigationBarItem.icon] and - /// [BottomNavigationBarItem.label]. + /// [BottomNavigationBarItem.title]. /// /// If null then the [ThemeData.primaryColor] is used. final Color? selectedItemColor; /// The color of the unselected [BottomNavigationBarItem.icon] and - /// [BottomNavigationBarItem.label]s. + /// [BottomNavigationBarItem.title]s. /// /// If null then the [ThemeData.unselectedWidgetColor]'s color is used. final Color? unselectedItemColor; @@ -691,7 +692,7 @@ class _Label extends StatelessWidget { ), ), alignment: Alignment.bottomCenter, - child: Text(item.label!), + child: item.title ?? Text(item.label!), ), ); diff --git a/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart b/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart index df0dd804841a2..2aadba725bd9f 100644 --- a/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart +++ b/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart @@ -78,13 +78,13 @@ class BottomNavigationBarThemeData with Diagnosticable { final IconThemeData? unselectedIconTheme; /// The color of the selected [BottomNavigationBarItem.icon] and - /// [BottomNavigationBarItem.label]. + /// [BottomNavigationBarItem.title]. /// /// See [BottomNavigationBar.selectedItemColor]. final Color? selectedItemColor; /// The color of the unselected [BottomNavigationBarItem.icon] and - /// [BottomNavigationBarItem.label]s. + /// [BottomNavigationBarItem.title]s. /// /// See [BottomNavigationBar.unselectedItemColor]. final Color? unselectedItemColor; diff --git a/packages/flutter/lib/src/material/bottom_sheet.dart b/packages/flutter/lib/src/material/bottom_sheet.dart index 6607b751d5b3b..9f0cf6659a61c 100644 --- a/packages/flutter/lib/src/material/bottom_sheet.dart +++ b/packages/flutter/lib/src/material/bottom_sheet.dart @@ -508,7 +508,7 @@ class _ModalBottomSheetRoute extends PopupRoute { _animationController = transitionAnimationController; willDisposeAnimationController = false; } else { - _animationController = BottomSheet.createAnimationController(navigator!); + _animationController = BottomSheet.createAnimationController(navigator!.overlay!); } return _animationController!; } @@ -722,9 +722,6 @@ Future showModalBottomSheet({ /// persistent bottom sheets (see the documentation for these on [BottomSheet] /// for more details). /// -/// The [enableDrag] parameter specifies whether the bottom sheet can be -/// dragged up and down and dismissed by swiping downwards. -/// /// To rebuild the bottom sheet (e.g. if it is stateful), call /// [PersistentBottomSheetController.setState] on the controller returned by /// this method. @@ -762,7 +759,6 @@ PersistentBottomSheetController showBottomSheet({ ShapeBorder? shape, Clip? clipBehavior, BoxConstraints? constraints, - bool? enableDrag, AnimationController? transitionAnimationController, }) { assert(context != null); @@ -776,7 +772,6 @@ PersistentBottomSheetController showBottomSheet({ shape: shape, clipBehavior: clipBehavior, constraints: constraints, - enableDrag: enableDrag, transitionAnimationController: transitionAnimationController, ); } diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index c926df87400f9..6fac69d0c0123 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -1224,7 +1224,6 @@ class _YearPickerState extends State { child: Center( child: Semantics( selected: isSelected, - button: true, child: Text(year.toString(), style: itemStyle), ), ), diff --git a/packages/flutter/lib/src/material/checkbox.dart b/packages/flutter/lib/src/material/checkbox.dart index c1d21f0d5afe6..075974ede2599 100644 --- a/packages/flutter/lib/src/material/checkbox.dart +++ b/packages/flutter/lib/src/material/checkbox.dart @@ -161,25 +161,6 @@ class Checkbox extends StatefulWidget { /// * [MaterialState.hovered]. /// * [MaterialState.focused]. /// * [MaterialState.disabled]. - /// - /// {@tool snippet} - /// This example resolves the [fillColor] based on the current [MaterialState] - /// of the [Checkbox], providing a different [Color] when it is - /// [MaterialState.disabled]. - /// - /// ```dart - /// Checkbox( - /// value: true, - /// onChanged: (_){}, - /// fillColor: MaterialStateProperty.resolveWith((states) { - /// if (states.contains(MaterialState.disabled)) { - /// return Colors.orange.withOpacity(.32); - /// } - /// return Colors.orange; - /// }) - /// ) - /// ``` - /// {@end-tool} /// {@endtemplate} /// /// If null, then the value of [activeColor] is used in the selected @@ -320,9 +301,8 @@ class Checkbox extends StatefulWidget { /// compatibility. /// {@endtemplate} /// - /// If this property is null, then [CheckboxThemeData.side] of - /// [ThemeData.checkboxTheme] is used. If that is also null, then the side - /// will be width 2. + /// If this property is null then [CheckboxThemeData.side] of [ThemeData.checkboxTheme] + /// is used. If that's null then the side will be width 2. final BorderSide? side; /// The width of a checkbox widget. diff --git a/packages/flutter/lib/src/material/checkbox_list_tile.dart b/packages/flutter/lib/src/material/checkbox_list_tile.dart index 990b63c7ac4b0..0290fd076fdb6 100644 --- a/packages/flutter/lib/src/material/checkbox_list_tile.dart +++ b/packages/flutter/lib/src/material/checkbox_list_tile.dart @@ -138,7 +138,6 @@ class CheckboxListTile extends StatelessWidget { this.tristate = false, this.shape, this.selectedTileColor, - this.side, this.visualDensity, this.focusNode, this.enableFeedback, @@ -259,15 +258,6 @@ class CheckboxListTile extends StatelessWidget { /// If non-null, defines the background color when [CheckboxListTile.selected] is true. final Color? selectedTileColor; - /// {@macro flutter.material.checkbox.side} - /// - /// The given value is passed directly to [Checkbox.side]. - /// - /// If this property is null, then [CheckboxThemeData.side] of - /// [ThemeData.checkboxTheme] is used. If that is also null, then the side - /// will be width 2. - final BorderSide? side; - /// Defines how compact the list tile's layout will be. /// /// {@macro flutter.material.themedata.visualDensity} @@ -308,7 +298,6 @@ class CheckboxListTile extends StatelessWidget { materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, autofocus: autofocus, tristate: tristate, - side: side, ); Widget? leading, trailing; switch (controlAffinity) { diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index 0a85fa313fe34..296adb6b26f90 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -76,8 +76,7 @@ abstract class ChipAttributes { /// The style to be applied to the chip's label. /// - /// The default label style is [TextTheme.bodyText1] from the overall - /// theme's [ThemeData.textTheme]. + /// If null, the value of the [ChipTheme]'s [ChipThemeData.labelStyle] is used. // /// This only has an effect on widgets that respect the [DefaultTextStyle], /// such as [Text]. @@ -226,15 +225,8 @@ abstract class DeletableChipAttributes { /// {@end-tool} VoidCallback? get onDeleted; - /// Used to define the delete icon's color with an [IconTheme] that - /// contains the icon. - /// - /// The default is `Color(0xde000000)` - /// (slightly transparent black) for light themes, and `Color(0xdeffffff)` - /// (slightly transparent white) for dark themes. - /// - /// The delete icon appears if [DeletableChipAttributes.onDeleted] is - /// non-null. + /// The [Color] for the delete icon. The default is based on the ambient + /// [IconThemeData.color]. Color? get deleteIconColor; /// Whether to use a tooltip on the chip's delete button showing the @@ -431,8 +423,7 @@ abstract class DisabledChipAttributes { /// Defaults to true. Cannot be null. bool get isEnabled; - /// The color used for the chip's background to indicate that it is not - /// enabled. + /// Color to be used for the chip's background indicating that it is disabled. /// /// The chip is disabled when [isEnabled] is false, or all three of /// [SelectableChipAttributes.onSelected], [TappableChipAttributes.onPressed], @@ -1076,9 +1067,9 @@ class ChoiceChip extends StatelessWidget /// ]; /// final List _filters = []; /// -/// Iterable get actorWidgets { -/// return _cast.map((ActorFilterEntry actor) { -/// return Padding( +/// Iterable get actorWidgets sync* { +/// for (final ActorFilterEntry actor in _cast) { +/// yield Padding( /// padding: const EdgeInsets.all(4.0), /// child: FilterChip( /// avatar: CircleAvatar(child: Text(actor.initials)), @@ -1097,7 +1088,7 @@ class ChoiceChip extends StatelessWidget /// }, /// ), /// ); -/// }); +/// } /// } /// /// @override @@ -1717,35 +1708,25 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid widget.onPressed?.call(); } - OutlinedBorder _getShape(ThemeData theme, ChipThemeData chipTheme, ChipThemeData chipDefaults) { + OutlinedBorder _getShape(ChipThemeData theme) { final BorderSide? resolvedSide = MaterialStateProperty.resolveAs(widget.side, materialStates) - ?? MaterialStateProperty.resolveAs(chipTheme.side, materialStates) - ?? MaterialStateProperty.resolveAs(chipDefaults.side, materialStates); + ?? MaterialStateProperty.resolveAs(theme.side, materialStates); final OutlinedBorder resolvedShape = MaterialStateProperty.resolveAs(widget.shape, materialStates) - ?? MaterialStateProperty.resolveAs(chipTheme.shape, materialStates) - ?? MaterialStateProperty.resolveAs(chipDefaults.shape, materialStates) + ?? MaterialStateProperty.resolveAs(theme.shape, materialStates) ?? const StadiumBorder(); return resolvedShape.copyWith(side: resolvedSide); } /// Picks between three different colors, depending upon the state of two /// different animations. - Color? _getBackgroundColor(ThemeData theme, ChipThemeData chipTheme, ChipThemeData chipDefaults) { + Color? getBackgroundColor(ChipThemeData theme) { final ColorTween backgroundTween = ColorTween( - begin: widget.disabledColor - ?? chipTheme.disabledColor - ?? theme.disabledColor, - end: widget.backgroundColor - ?? chipTheme.backgroundColor - ?? theme.chipTheme.backgroundColor - ?? chipDefaults.backgroundColor, + begin: widget.disabledColor ?? theme.disabledColor, + end: widget.backgroundColor ?? theme.backgroundColor, ); final ColorTween selectTween = ColorTween( begin: backgroundTween.evaluate(enableController), - end: widget.selectedColor - ?? chipTheme.selectedColor - ?? theme.chipTheme.selectedColor - ?? chipDefaults.selectedColor, + end: widget.selectedColor ?? theme.selectedColor, ); return selectTween.evaluate(selectionFade); } @@ -1807,7 +1788,6 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid BuildContext context, ThemeData theme, ChipThemeData chipTheme, - ChipThemeData chipDefaults, ) { if (!hasDeleteButton) { return null; @@ -1816,9 +1796,7 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid container: true, button: true, child: _wrapWithTooltip( - tooltip: widget.useDeleteButtonTooltip - ? widget.deleteButtonTooltipMessage ?? MaterialLocalizations.of(context).deleteButtonTooltip - : null, + tooltip: widget.useDeleteButtonTooltip ? widget.deleteButtonTooltipMessage ?? MaterialLocalizations.of(context).deleteButtonTooltip : null, enabled: widget.onDeleted != null, child: InkWell( // Radius should be slightly less than the full size of the chip. @@ -1828,10 +1806,7 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid onTap: widget.isEnabled ? widget.onDeleted : null, child: IconTheme( data: theme.iconTheme.copyWith( - color: widget.deleteIconColor - ?? chipTheme.deleteIconColor - ?? theme.chipTheme.deleteIconColor - ?? chipDefaults.deleteIconColor, + color: widget.deleteIconColor ?? chipTheme.deleteIconColor, ), child: widget.deleteIcon, ), @@ -1863,53 +1838,19 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid final ThemeData theme = Theme.of(context); final ChipThemeData chipTheme = ChipTheme.of(context); - final Brightness brightness = chipTheme.brightness ?? theme.brightness; - final ChipThemeData chipDefaults = ChipThemeData.fromDefaults( - brightness: brightness, - secondaryColor: brightness == Brightness.dark ? Colors.tealAccent[200]! : theme.primaryColor, - labelStyle: theme.textTheme.bodyText1!, - ); final TextDirection? textDirection = Directionality.maybeOf(context); - final OutlinedBorder resolvedShape = _getShape(theme, chipTheme, chipDefaults); - - final double elevation = widget.elevation - ?? chipTheme.elevation - ?? theme.chipTheme.elevation - ?? _defaultElevation; - final double pressElevation = widget.pressElevation - ?? chipTheme.pressElevation - ?? theme.chipTheme.pressElevation - ?? _defaultPressElevation; - final Color shadowColor = widget.shadowColor - ?? chipTheme.shadowColor - ?? theme.chipTheme.shadowColor - ?? _defaultShadowColor; - final Color selectedShadowColor = widget.selectedShadowColor - ?? chipTheme.selectedShadowColor - ?? theme.chipTheme.selectedShadowColor - ?? _defaultShadowColor; - final Color? checkmarkColor = widget.checkmarkColor - ?? chipTheme.checkmarkColor - ?? theme.chipTheme.checkmarkColor; - final bool showCheckmark = widget.showCheckmark - ?? chipTheme.showCheckmark - ?? theme.chipTheme.showCheckmark - ?? true; - final EdgeInsetsGeometry padding = widget.padding - ?? chipTheme.padding - ?? theme.chipTheme.padding - ?? chipDefaults.padding!; - final TextStyle labelStyle = chipTheme.labelStyle - ?? theme.chipTheme.labelStyle - ?? chipDefaults.labelStyle!; - final EdgeInsetsGeometry labelPadding = widget.labelPadding - ?? chipTheme.labelPadding - ?? theme.chipTheme.labelPadding - ?? _defaultLabelPadding; - - final TextStyle effectiveLabelStyle = labelStyle.merge(widget.labelStyle); + final OutlinedBorder resolvedShape = _getShape(chipTheme); + final double elevation = widget.elevation ?? chipTheme.elevation ?? _defaultElevation; + final double pressElevation = widget.pressElevation ?? chipTheme.pressElevation ?? _defaultPressElevation; + final Color shadowColor = widget.shadowColor ?? chipTheme.shadowColor ?? _defaultShadowColor; + final Color selectedShadowColor = widget.selectedShadowColor ?? chipTheme.selectedShadowColor ?? _defaultShadowColor; + final Color? checkmarkColor = widget.checkmarkColor ?? chipTheme.checkmarkColor; + final bool showCheckmark = widget.showCheckmark ?? chipTheme.showCheckmark ?? true; + + final TextStyle effectiveLabelStyle = chipTheme.labelStyle.merge(widget.labelStyle); final Color? resolvedLabelColor = MaterialStateProperty.resolveAs(effectiveLabelStyle.color, materialStates); final TextStyle resolvedLabelStyle = effectiveLabelStyle.copyWith(color: resolvedLabelColor); + final EdgeInsetsGeometry labelPadding = widget.labelPadding ?? chipTheme.labelPadding ?? _defaultLabelPadding; Widget result = Material( elevation: isTapping ? pressElevation : elevation, @@ -1933,7 +1874,7 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid return Container( decoration: ShapeDecoration( shape: resolvedShape, - color: _getBackgroundColor(theme, chipTheme, chipDefaults), + color: getBackgroundColor(chipTheme), ), child: child, ); @@ -1959,10 +1900,10 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid deleteIcon: AnimatedSwitcher( duration: _kDrawerDuration, switchInCurve: Curves.fastOutSlowIn, - child: _buildDeleteIcon(context, theme, chipTheme, chipDefaults), + child: _buildDeleteIcon(context, theme, chipTheme), ), - brightness: brightness, - padding: padding.resolve(textDirection), + brightness: chipTheme.brightness, + padding: (widget.padding ?? chipTheme.padding).resolve(textDirection), visualDensity: widget.visualDensity ?? theme.visualDensity, labelPadding: labelPadding.resolve(textDirection), showAvatar: hasAvatar, @@ -2060,7 +2001,7 @@ class _RenderChipRedirectingHitDetection extends RenderConstrainedBox { } } -class _ChipRenderWidget extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin<_ChipSlot> { +class _ChipRenderWidget extends RenderObjectWidget { const _ChipRenderWidget({ Key? key, required this.theme, @@ -2084,19 +2025,7 @@ class _ChipRenderWidget extends RenderObjectWidget with SlottedMultiChildRenderO final ShapeBorder? avatarBorder; @override - Iterable<_ChipSlot> get slots => _ChipSlot.values; - - @override - Widget? childForSlot(_ChipSlot slot) { - switch (slot) { - case _ChipSlot.label: - return theme.label; - case _ChipSlot.avatar: - return theme.avatar; - case _ChipSlot.deleteIcon: - return theme.deleteIcon; - } - } + _RenderChipElement createElement() => _RenderChipElement(this); @override void updateRenderObject(BuildContext context, _RenderChip renderObject) { @@ -2113,7 +2042,7 @@ class _ChipRenderWidget extends RenderObjectWidget with SlottedMultiChildRenderO } @override - SlottedContainerRenderObjectMixin<_ChipSlot> createRenderObject(BuildContext context) { + RenderObject createRenderObject(BuildContext context) { return _RenderChip( theme: theme, textDirection: Directionality.of(context), @@ -2134,6 +2063,105 @@ enum _ChipSlot { deleteIcon, } +class _RenderChipElement extends RenderObjectElement { + _RenderChipElement(_ChipRenderWidget chip) : super(chip); + + final Map<_ChipSlot, Element> slotToChild = <_ChipSlot, Element>{}; + + @override + _ChipRenderWidget get widget => super.widget as _ChipRenderWidget; + + @override + _RenderChip get renderObject => super.renderObject as _RenderChip; + + @override + void visitChildren(ElementVisitor visitor) { + slotToChild.values.forEach(visitor); + } + + @override + void forgetChild(Element child) { + assert(slotToChild.containsValue(child)); + assert(child.slot is _ChipSlot); + assert(slotToChild.containsKey(child.slot)); + slotToChild.remove(child.slot); + super.forgetChild(child); + } + + void _mountChild(Widget widget, _ChipSlot slot) { + final Element? oldChild = slotToChild[slot]; + final Element? newChild = updateChild(oldChild, widget, slot); + if (oldChild != null) { + slotToChild.remove(slot); + } + if (newChild != null) { + slotToChild[slot] = newChild; + } + } + + @override + void mount(Element? parent, Object? newSlot) { + super.mount(parent, newSlot); + _mountChild(widget.theme.avatar, _ChipSlot.avatar); + _mountChild(widget.theme.deleteIcon, _ChipSlot.deleteIcon); + _mountChild(widget.theme.label, _ChipSlot.label); + } + + void _updateChild(Widget widget, _ChipSlot slot) { + final Element? oldChild = slotToChild[slot]; + final Element? newChild = updateChild(oldChild, widget, slot); + if (oldChild != null) { + slotToChild.remove(slot); + } + if (newChild != null) { + slotToChild[slot] = newChild; + } + } + + @override + void update(_ChipRenderWidget newWidget) { + super.update(newWidget); + assert(widget == newWidget); + _updateChild(widget.theme.label, _ChipSlot.label); + _updateChild(widget.theme.avatar, _ChipSlot.avatar); + _updateChild(widget.theme.deleteIcon, _ChipSlot.deleteIcon); + } + + void _updateRenderObject(RenderObject? child, _ChipSlot slot) { + switch (slot) { + case _ChipSlot.avatar: + renderObject.avatar = child as RenderBox?; + break; + case _ChipSlot.label: + renderObject.label = child as RenderBox?; + break; + case _ChipSlot.deleteIcon: + renderObject.deleteIcon = child as RenderBox?; + break; + } + } + + @override + void insertRenderObjectChild(RenderObject child, _ChipSlot slot) { + assert(child is RenderBox); + _updateRenderObject(child, slot); + assert(renderObject.children.keys.contains(slot)); + } + + @override + void removeRenderObjectChild(RenderObject child, _ChipSlot slot) { + assert(child is RenderBox); + assert(renderObject.children[slot] == child); + _updateRenderObject(null, slot); + assert(!renderObject.children.keys.contains(slot)); + } + + @override + void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) { + assert(false, 'not reachable'); + } +} + @immutable class _ChipRenderTheme { const _ChipRenderTheme({ @@ -2200,7 +2228,7 @@ class _ChipRenderTheme { } } -class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_ChipSlot> { +class _RenderChip extends RenderBox { _RenderChip({ required _ChipRenderTheme theme, required TextDirection textDirection, @@ -2221,6 +2249,8 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip enableAnimation.addListener(markNeedsPaint); } + final Map<_ChipSlot, RenderBox> children = <_ChipSlot, RenderBox>{}; + bool? value; bool? isEnabled; late Rect _deleteButtonRect; @@ -2231,9 +2261,35 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip Animation enableAnimation; ShapeBorder? avatarBorder; - RenderBox? get avatar => childForSlot(_ChipSlot.avatar); - RenderBox? get deleteIcon => childForSlot(_ChipSlot.deleteIcon); - RenderBox? get label => childForSlot(_ChipSlot.label); + RenderBox? _updateChild(RenderBox? oldChild, RenderBox? newChild, _ChipSlot slot) { + if (oldChild != null) { + dropChild(oldChild); + children.remove(slot); + } + if (newChild != null) { + children[slot] = newChild; + adoptChild(newChild); + } + return newChild; + } + + RenderBox? _avatar; + RenderBox? get avatar => _avatar; + set avatar(RenderBox? value) { + _avatar = _updateChild(_avatar, value, _ChipSlot.avatar); + } + + RenderBox? _deleteIcon; + RenderBox? get deleteIcon => _deleteIcon; + set deleteIcon(RenderBox? value) { + _deleteIcon = _updateChild(_deleteIcon, value, _ChipSlot.deleteIcon); + } + + RenderBox? _label; + RenderBox? get label => _label; + set label(RenderBox? value) { + _label = _updateChild(_label, value, _ChipSlot.label); + } _ChipRenderTheme get theme => _theme; _ChipRenderTheme _theme; @@ -2256,21 +2312,62 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip } // The returned list is ordered for hit testing. - @override - Iterable get children { - return [ - if (avatar != null) - avatar!, - if (label != null) - label!, - if (deleteIcon != null) - deleteIcon!, - ]; + Iterable get _children sync* { + if (avatar != null) { + yield avatar!; + } + if (label != null) { + yield label!; + } + if (deleteIcon != null) { + yield deleteIcon!; + } } bool get isDrawingCheckmark => theme.showCheckmark && !checkmarkAnimation.isDismissed; bool get deleteIconShowing => !deleteDrawerAnimation.isDismissed; + @override + void attach(PipelineOwner owner) { + super.attach(owner); + for (final RenderBox child in _children) { + child.attach(owner); + } + } + + @override + void detach() { + super.detach(); + for (final RenderBox child in _children) { + child.detach(); + } + } + + @override + void redepthChildren() { + _children.forEach(redepthChild); + } + + @override + void visitChildren(RenderObjectVisitor visitor) { + _children.forEach(visitor); + } + + @override + List debugDescribeChildren() { + final List value = []; + void add(RenderBox? child, String name) { + if (child != null) { + value.add(child.toDiagnosticsNode(name: name)); + } + } + + add(avatar, 'avatar'); + add(label, 'label'); + add(deleteIcon, 'deleteIcon'); + return value; + } + @override bool get sizedByParent => false; @@ -2475,7 +2572,6 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip overallSize.width + theme.padding.horizontal, overallSize.height + theme.padding.vertical, ); - return _ChipSizes( size: constraints.constrain(paddedSize), overall: overallSize, diff --git a/packages/flutter/lib/src/material/chip_theme.dart b/packages/flutter/lib/src/material/chip_theme.dart index f12ecd2712af2..de4796fadf544 100644 --- a/packages/flutter/lib/src/material/chip_theme.dart +++ b/packages/flutter/lib/src/material/chip_theme.dart @@ -179,25 +179,32 @@ class ChipThemeData with Diagnosticable { /// This will rarely be used directly. It is used by [lerp] to /// create intermediate themes based on two themes. const ChipThemeData({ - this.backgroundColor, + required this.backgroundColor, this.deleteIconColor, - this.disabledColor, - this.selectedColor, - this.secondarySelectedColor, + required this.disabledColor, + required this.selectedColor, + required this.secondarySelectedColor, this.shadowColor, this.selectedShadowColor, this.showCheckmark, this.checkmarkColor, this.labelPadding, - this.padding, + required this.padding, this.side, this.shape, - this.labelStyle, - this.secondaryLabelStyle, - this.brightness, + required this.labelStyle, + required this.secondaryLabelStyle, + required this.brightness, this.elevation, this.pressElevation, - }); + }) : assert(backgroundColor != null), + assert(disabledColor != null), + assert(selectedColor != null), + assert(secondarySelectedColor != null), + assert(padding != null), + assert(labelStyle != null), + assert(secondaryLabelStyle != null), + assert(brightness != null); /// Generates a ChipThemeData from a brightness, a primary color, and a text /// style. @@ -260,87 +267,91 @@ class ChipThemeData with Diagnosticable { padding: padding, labelStyle: labelStyle, secondaryLabelStyle: secondaryLabelStyle, - brightness: brightness, + brightness: brightness!, ); } - /// Overrides the default for [ChipAttributes.backgroundColor] - /// which is used for unselected, enabled chip backgrounds. + /// Color to be used for the unselected, enabled chip's background. /// - /// This property applies to [ActionChip], [Chip], [ChoiceChip], - /// [FilterChip], [InputChip], [RawChip]. - final Color? backgroundColor; + /// The default is light grey. + final Color backgroundColor; - /// Overrides the default for [DeletableChipAttributes.deleteIconColor]. + /// The [Color] for the delete icon. The default is Color(0xde000000) + /// (slightly transparent black) for light themes, and Color(0xdeffffff) + /// (slightly transparent white) for dark themes. /// - /// This property applies to [Chip], [InputChip], [RawChip]. + /// May be set to null, in which case the ambient [IconThemeData.color] is used. final Color? deleteIconColor; - /// Overrides the default for - /// [DisabledChipAttributes.disabledColor], the background color - /// which indicates that the chip is not enabled. + /// Color to be used for the chip's background indicating that it is disabled. /// - /// This property applies to [ChoiceChip], [FilterChip], - /// [InputChip], [RawChip]. - final Color? disabledColor; + /// The chip is disabled when [DisabledChipAttributes.isEnabled] is false, or + /// all three of [SelectableChipAttributes.onSelected], + /// [TappableChipAttributes.onPressed], and + /// [DeletableChipAttributes.onDeleted] are null. + /// + /// It defaults to [Colors.black38]. + final Color disabledColor; - /// Overrides the default for - /// [SelectableChipAttributes.selectedColor], the background color - /// that indicates that the chip is selected. + /// Color to be used for the chip's background, indicating that it is + /// selected. /// - /// This property applies to [ChoiceChip], [FilterChip], - /// [InputChip], [RawChip]. - final Color? selectedColor; + /// The chip is selected when [SelectableChipAttributes.selected] is true. + final Color selectedColor; - /// Overrides the default for [ChoiceChip.selectedColor], the - /// background color that indicates that the chip is selected. - final Color? secondarySelectedColor; + /// An alternate color to be used for the chip's background, indicating that + /// it is selected. For example, this color is used by [ChoiceChip] when the + /// choice is selected. + /// + /// The chip is selected when [SelectableChipAttributes.selected] is true. + final Color secondarySelectedColor; - /// Overrides the default for [ChipAttributes.shadowColor], the - /// Color of the chip's shadow when its elevation is greater than 0. + /// Color of the chip's shadow when the elevation is greater than 0. + /// + /// If null, the chip defaults to [Colors.black]. + /// + /// See also: /// - /// This property applies to [ActionChip], [Chip], [ChoiceChip], - /// [FilterChip], [InputChip], [RawChip]. + /// * [selectedShadowColor] final Color? shadowColor; - /// Overrides the default for - /// [SelectableChipAttributes.selectedShadowColor], the Color of the - /// chip's shadow when its elevation is greater than 0 and the chip - /// is selected. + /// Color of the chip's shadow when the elevation is greater than 0 and the + /// chip is selected. + /// + /// If null, the chip defaults to [Colors.black]. + /// + /// See also: /// - /// This property applies to [ChoiceChip], [FilterChip], - /// [InputChip], [RawChip]. + /// * [shadowColor] final Color? selectedShadowColor; - /// Overrides the default for - /// [CheckmarkableChipAttributes.showCheckmark], which indicates if - /// a check mark should be shown. + /// Whether or not to show a check mark when [SelectableChipAttributes.selected] is true. /// - /// This property applies to [FilterChip], [InputChip], [RawChip]. + /// For instance, the [ChoiceChip] sets this to false so that it can be + /// selected without showing the check mark. + /// + /// Defaults to true. final bool? showCheckmark; - /// Overrides the default for - /// [CheckmarkableChipAttributes.checkmarkColor]. + /// Color of the chip's check mark when a check mark is visible. /// - /// This property applies to [FilterChip], [InputChip], [RawChip]. + /// This will override the color set by the platform's brightness setting. final Color? checkmarkColor; - /// Overrides the default for [ChipAttributes.labelPadding], - /// the padding around the chip's label widget. + /// The padding around the [Chip.label] widget. /// - /// This property applies to [ActionChip], [Chip], [ChoiceChip], - /// [FilterChip], [InputChip], [RawChip]. + /// By default, this is 4 logical pixels at the beginning and the end of the + /// label, and zero on top and bottom. final EdgeInsetsGeometry? labelPadding; - /// Overrides the default for [ChipAttributes.padding], - /// the padding between the contents of the chip and the outside [shape]. + /// The padding between the contents of the chip and the outside [shape]. /// - /// This property applies to [ActionChip], [Chip], [ChoiceChip], - /// [FilterChip], [InputChip], [RawChip]. - final EdgeInsetsGeometry? padding; + /// Defaults to 4 logical pixels on all sides. + final EdgeInsetsGeometry padding; - /// Overrides the default for [ChipAttributes.side], - /// the color and weight of the chip's outline. + /// The color and weight of the chip's outline. + /// + /// If null, the chip defaults to the border side of [shape]. /// /// This value is combined with [shape] to create a shape decorated with an /// outline. If it is a [MaterialStateBorderSide], @@ -352,13 +363,11 @@ class ChipThemeData with Diagnosticable { /// * [MaterialState.hovered]. /// * [MaterialState.focused]. /// * [MaterialState.pressed]. - /// - /// This property applies to [ActionChip], [Chip], [ChoiceChip], - /// [FilterChip], [InputChip], [RawChip]. final BorderSide? side; - /// Overrides the default for [ChipAttributes.shape], - /// the shape of border to draw around the chip. + /// The border to draw around the chip. + /// + /// If null, the chip defaults to a [StadiumBorder]. /// /// This shape is combined with [side] to create a shape decorated with an /// outline. If it is a [MaterialStateOutlinedBorder], @@ -370,45 +379,34 @@ class ChipThemeData with Diagnosticable { /// * [MaterialState.hovered]. /// * [MaterialState.focused]. /// * [MaterialState.pressed]. - /// - /// This property applies to [ActionChip], [Chip], [ChoiceChip], - /// [FilterChip], [InputChip], [RawChip]. final OutlinedBorder? shape; - /// Overrides the default for [ChipAttributes.labelStyle], - /// the style of the [DefaultTextStyle] that contains the - /// chip's label. + /// The style to be applied to the chip's label. /// /// This only has an effect on label widgets that respect the /// [DefaultTextStyle], such as [Text]. - /// - /// This property applies to [ActionChip], [Chip], - /// [FilterChip], [InputChip], [RawChip]. - final TextStyle? labelStyle; + final TextStyle labelStyle; - /// Overrides the default for [ChoiceChip.labelStyle], - /// the style of the [DefaultTextStyle] that contains the - /// chip's label. + /// An alternate style to be applied to the chip's label. For example, this + /// style is applied to the text of a selected [ChoiceChip]. /// /// This only has an effect on label widgets that respect the /// [DefaultTextStyle], such as [Text]. - final TextStyle? secondaryLabelStyle; + final TextStyle secondaryLabelStyle; - /// Overrides the default value for all chips which affects various base - /// material color choices in the chip rendering. - final Brightness? brightness; + /// The brightness setting for this theme. + /// + /// This affects various base material color choices in the chip rendering. + final Brightness brightness; - /// Overrides the default for [ChipAttributes.elevation], - /// the elevation of the chip's [Material]. + /// The elevation to be applied to the chip. /// - /// This property applies to [ActionChip], [Chip], [ChoiceChip], - /// [FilterChip], [InputChip], [RawChip]. + /// If null, the chip defaults to 0. final double? elevation; - /// Overrides the default for [TappableChipAttributes.pressElevation], - /// the elevation of the chip's [Material] during a "press" or tap down. + /// The elevation to be applied to the chip during the press motion. /// - /// This property applies to [ActionChip], [InputChip], [RawChip]. + /// If null, the chip defaults to 8. final double? pressElevation; /// Creates a copy of this object but with the given fields replaced with the @@ -463,20 +461,20 @@ class ChipThemeData with Diagnosticable { if (a == null && b == null) return null; return ChipThemeData( - backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), + backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t)!, deleteIconColor: Color.lerp(a?.deleteIconColor, b?.deleteIconColor, t), - disabledColor: Color.lerp(a?.disabledColor, b?.disabledColor, t), - selectedColor: Color.lerp(a?.selectedColor, b?.selectedColor, t), - secondarySelectedColor: Color.lerp(a?.secondarySelectedColor, b?.secondarySelectedColor, t), + disabledColor: Color.lerp(a?.disabledColor, b?.disabledColor, t)!, + selectedColor: Color.lerp(a?.selectedColor, b?.selectedColor, t)!, + secondarySelectedColor: Color.lerp(a?.secondarySelectedColor, b?.secondarySelectedColor, t)!, shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t), selectedShadowColor: Color.lerp(a?.selectedShadowColor, b?.selectedShadowColor, t), checkmarkColor: Color.lerp(a?.checkmarkColor, b?.checkmarkColor, t), labelPadding: EdgeInsetsGeometry.lerp(a?.labelPadding, b?.labelPadding, t), - padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t), + padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t)!, side: _lerpSides(a?.side, b?.side, t), shape: _lerpShapes(a?.shape, b?.shape, t), - labelStyle: TextStyle.lerp(a?.labelStyle, b?.labelStyle, t), - secondaryLabelStyle: TextStyle.lerp(a?.secondaryLabelStyle, b?.secondaryLabelStyle, t), + labelStyle: TextStyle.lerp(a?.labelStyle, b?.labelStyle, t)!, + secondaryLabelStyle: TextStyle.lerp(a?.secondaryLabelStyle, b?.secondaryLabelStyle, t)!, brightness: t < 0.5 ? a?.brightness ?? Brightness.light : b?.brightness ?? Brightness.light, elevation: lerpDouble(a?.elevation, b?.elevation, t), pressElevation: lerpDouble(a?.pressElevation, b?.pressElevation, t), @@ -555,22 +553,28 @@ class ChipThemeData with Diagnosticable { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null)); - properties.add(ColorProperty('deleteIconColor', deleteIconColor, defaultValue: null)); - properties.add(ColorProperty('disabledColor', disabledColor, defaultValue: null)); - properties.add(ColorProperty('selectedColor', selectedColor, defaultValue: null)); - properties.add(ColorProperty('secondarySelectedColor', secondarySelectedColor, defaultValue: null)); - properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null)); - properties.add(ColorProperty('selectedShadowColor', selectedShadowColor, defaultValue: null)); - properties.add(ColorProperty('checkMarkColor', checkmarkColor, defaultValue: null)); - properties.add(DiagnosticsProperty('labelPadding', labelPadding, defaultValue: null)); - properties.add(DiagnosticsProperty('padding', padding, defaultValue: null)); - properties.add(DiagnosticsProperty('side', side, defaultValue: null)); - properties.add(DiagnosticsProperty('shape', shape, defaultValue: null)); - properties.add(DiagnosticsProperty('labelStyle', labelStyle, defaultValue: null)); - properties.add(DiagnosticsProperty('secondaryLabelStyle', secondaryLabelStyle, defaultValue: null)); - properties.add(EnumProperty('brightness', brightness, defaultValue: null)); - properties.add(DoubleProperty('elevation', elevation, defaultValue: null)); - properties.add(DoubleProperty('pressElevation', pressElevation, defaultValue: null)); + final ThemeData defaultTheme = ThemeData.fallback(); + final ChipThemeData defaultData = ChipThemeData.fromDefaults( + secondaryColor: defaultTheme.primaryColor, + brightness: defaultTheme.brightness, + labelStyle: defaultTheme.textTheme.bodyText1!, + ); + properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: defaultData.backgroundColor)); + properties.add(ColorProperty('deleteIconColor', deleteIconColor, defaultValue: defaultData.deleteIconColor)); + properties.add(ColorProperty('disabledColor', disabledColor, defaultValue: defaultData.disabledColor)); + properties.add(ColorProperty('selectedColor', selectedColor, defaultValue: defaultData.selectedColor)); + properties.add(ColorProperty('secondarySelectedColor', secondarySelectedColor, defaultValue: defaultData.secondarySelectedColor)); + properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: defaultData.shadowColor)); + properties.add(ColorProperty('selectedShadowColor', selectedShadowColor, defaultValue: defaultData.selectedShadowColor)); + properties.add(ColorProperty('checkMarkColor', checkmarkColor, defaultValue: defaultData.checkmarkColor)); + properties.add(DiagnosticsProperty('labelPadding', labelPadding, defaultValue: defaultData.labelPadding)); + properties.add(DiagnosticsProperty('padding', padding, defaultValue: defaultData.padding)); + properties.add(DiagnosticsProperty('side', side, defaultValue: defaultData.side)); + properties.add(DiagnosticsProperty('shape', shape, defaultValue: defaultData.shape)); + properties.add(DiagnosticsProperty('labelStyle', labelStyle, defaultValue: defaultData.labelStyle)); + properties.add(DiagnosticsProperty('secondaryLabelStyle', secondaryLabelStyle, defaultValue: defaultData.secondaryLabelStyle)); + properties.add(EnumProperty('brightness', brightness, defaultValue: defaultData.brightness)); + properties.add(DoubleProperty('elevation', elevation, defaultValue: defaultData.elevation)); + properties.add(DoubleProperty('pressElevation', pressElevation, defaultValue: defaultData.pressElevation)); } } diff --git a/packages/flutter/lib/src/material/color_scheme.dart b/packages/flutter/lib/src/material/color_scheme.dart index 051364aec1eb7..399c2442eaa2d 100644 --- a/packages/flutter/lib/src/material/color_scheme.dart +++ b/packages/flutter/lib/src/material/color_scheme.dart @@ -4,528 +4,167 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:material_color_utilities/material_color_utilities.dart'; import 'colors.dart'; import 'theme_data.dart'; -/// A set of 25 colors based on the -/// [Material spec](https://m3.material.io/styles/color/the-color-system/color-roles) +/// A set of twelve colors based on the +/// [Material spec](https://material.io/design/color/the-color-system.html) /// that can be used to configure the color properties of most components. /// -/// The main accent color groups in the scheme are [primary], [secondary], -/// and [tertiary]. -/// -/// * Primary colors are used for key components across the UI, such as the FAB, -/// prominent buttons, and active states. -/// -/// * Secondary colors are used for less prominent components in the UI, such as -/// filter chips, while expanding the opportunity for color expression. -/// -/// * Tertiary colors are used for contrasting accents that can be used to -/// balance primary and secondary colors or bring heightened attention to -/// an element, such as an input field. The tertiary colors are left -/// for makers to use at their discretion and are intended to support -/// broader color expression in products. -/// -/// The remaining colors of the scheme are comprised of neutral colors used for -/// backgrounds and surfaces, as well as specific colors for errors, dividers -/// and shadows. -/// -/// Many of the colors have matching 'on' colors, which are used for drawing -/// content on top of the matching color. For example, if something is using -/// [primary] for a background color, [onPrimary] would be used to paint text -/// and icons on top of it. For this reason, the 'on' colors should have a -/// contrast ratio with their matching colors of at least 4.5:1 in order to -/// be readable. -/// -/// The [Theme] has a color scheme, [ThemeData.colorScheme], which can either be -/// passed in as a parameter to the constructor or by using 'brightness' and -/// 'colorSchemeSeed' parameters (which are used to generate a scheme with -/// [ColorScheme.fromSeed]). +/// The [Theme] has a color scheme, [ThemeData.colorScheme], which is constructed +/// with [ColorScheme.fromSwatch]. @immutable class ColorScheme with Diagnosticable { - /// Create a ColorScheme instance from the given colors. - /// - /// [ColorScheme.fromSeed] can be used as a simpler way to create a full - /// color scheme derived from a single seed color. - /// - /// For the color parameters that are nullable, it is still recommended - /// that applications provide values for them. They are only nullable due - /// to backwards compatibility concerns. - /// - /// If a color is not provided, the closest fallback color from the given - /// colors will be used for it (e.g. [primaryContainer] will default - /// to [primary]). Material Design 3 makes use of these colors for many - /// component defaults, so for the best results the application should - /// supply colors for all the parameters. An easy way to ensure this is to - /// use [ColorScheme.fromSeed] to generate a full set of colors. - /// - /// During the migration to Material Design 3, if an app's - /// [ThemeData.useMaterial3] is false, then components will only - /// use the following colors for defaults: - /// - /// * [primary] - /// * [onPrimary] - /// * [secondary] - /// * [onSecondary] - /// * [error] - /// * [onError] - /// * [background] - /// * [onBackground] - /// * [surface] - /// * [onSurface] + /// Create a ColorScheme instance. const ColorScheme({ - required this.brightness, required this.primary, - required this.onPrimary, - Color? primaryContainer, - Color? onPrimaryContainer, + required this.primaryVariant, required this.secondary, - required this.onSecondary, - Color? secondaryContainer, - Color? onSecondaryContainer, - Color? tertiary, - Color? onTertiary, - Color? tertiaryContainer, - Color? onTertiaryContainer, - required this.error, - required this.onError, - Color? errorContainer, - Color? onErrorContainer, - required this.background, - required this.onBackground, + required this.secondaryVariant, required this.surface, + required this.background, + required this.error, + required this.onPrimary, + required this.onSecondary, required this.onSurface, - Color? surfaceVariant, - Color? onSurfaceVariant, - Color? outline, - Color? shadow, - Color? inverseSurface, - Color? onInverseSurface, - Color? inversePrimary, - @Deprecated( - 'Use primary or primaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? primaryVariant, - @Deprecated( - 'Use secondary or secondaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? secondaryVariant, - }) : assert(brightness != null), - assert(primary != null), - assert(onPrimary != null), + required this.onBackground, + required this.onError, + required this.brightness, + }) : assert(primary != null), + assert(primaryVariant != null), assert(secondary != null), - assert(onSecondary != null), - assert(error != null), - assert(onError != null), - assert(background != null), - assert(onBackground != null), + assert(secondaryVariant != null), assert(surface != null), + assert(background != null), + assert(error != null), + assert(onPrimary != null), + assert(onSecondary != null), assert(onSurface != null), - _primaryContainer = primaryContainer, - _onPrimaryContainer = onPrimaryContainer, - _secondaryContainer = secondaryContainer, - _onSecondaryContainer = onSecondaryContainer, - _tertiary = tertiary, - _onTertiary = onTertiary, - _tertiaryContainer = tertiaryContainer, - _onTertiaryContainer = onTertiaryContainer, - _errorContainer = errorContainer, - _onErrorContainer = onErrorContainer, - _surfaceVariant = surfaceVariant, - _onSurfaceVariant = onSurfaceVariant, - _outline = outline, - _shadow = shadow, - _inverseSurface = inverseSurface, - _onInverseSurface = onInverseSurface, - _inversePrimary = inversePrimary, - _primaryVariant = primaryVariant, - _secondaryVariant = secondaryVariant; - - /// Generate a [ColorScheme] derived from the given `seedColor`. - /// - /// Using the seedColor as a starting point, a set of tonal palettes are - /// constructed. These tonal palettes are based on the Material 3 Color - /// system and provide all the needed colors for a [ColorScheme]. These - /// colors are designed to work well together and meet contrast - /// requirements for accessibility. - /// - /// If any of the optional color parameters are non-null they will be - /// used in place of the generated colors for that field in the resulting - /// color scheme. This allows apps to override specific colors for their - /// needs. - /// - /// Given the nature of the algorithm, the seedColor may not wind up as - /// one of the ColorScheme colors. - /// - /// See also: - /// - /// * , the - /// Material 3 Color system specification. - /// * , the package - /// used to generate the tonal palettes needed for the scheme. - factory ColorScheme.fromSeed({ - required Color seedColor, - Brightness brightness = Brightness.light, - Color? primary, - Color? onPrimary, - Color? primaryContainer, - Color? onPrimaryContainer, - Color? secondary, - Color? onSecondary, - Color? secondaryContainer, - Color? onSecondaryContainer, - Color? tertiary, - Color? onTertiary, - Color? tertiaryContainer, - Color? onTertiaryContainer, - Color? error, - Color? onError, - Color? errorContainer, - Color? onErrorContainer, - Color? outline, - Color? background, - Color? onBackground, - Color? surface, - Color? onSurface, - Color? surfaceVariant, - Color? onSurfaceVariant, - Color? inverseSurface, - Color? onInverseSurface, - Color? inversePrimary, - Color? shadow, - }) { - final Scheme scheme; - switch (brightness) { - case Brightness.light: - scheme = Scheme.light(seedColor.value); - break; - case Brightness.dark: - scheme = Scheme.dark(seedColor.value); - break; - } - return ColorScheme( - primary: primary ?? Color(scheme.primary), - onPrimary: onPrimary ?? Color(scheme.onPrimary), - primaryContainer: primaryContainer ?? Color(scheme.primaryContainer), - onPrimaryContainer: onPrimaryContainer ?? Color(scheme.onPrimaryContainer), - secondary: secondary ?? Color(scheme.secondary), - onSecondary: onSecondary ?? Color(scheme.onSecondary), - secondaryContainer: secondaryContainer ?? Color(scheme.secondaryContainer), - onSecondaryContainer: onSecondaryContainer ?? Color(scheme.onSecondaryContainer), - tertiary: tertiary ?? Color(scheme.tertiary), - onTertiary: onTertiary ?? Color(scheme.onTertiary), - tertiaryContainer: tertiaryContainer ?? Color(scheme.tertiaryContainer), - onTertiaryContainer: onTertiaryContainer ?? Color(scheme.onTertiaryContainer), - error: error ?? Color(scheme.error), - onError: onError ?? Color(scheme.onError), - errorContainer: errorContainer ?? Color(scheme.errorContainer), - onErrorContainer: onErrorContainer ?? Color(scheme.onErrorContainer), - outline: outline ?? Color(scheme.outline), - background: background ?? Color(scheme.background), - onBackground: onBackground ?? Color(scheme.onBackground), - surface: surface ?? Color(scheme.surface), - onSurface: onSurface ?? Color(scheme.onSurface), - surfaceVariant: surfaceVariant ?? Color(scheme.surfaceVariant), - onSurfaceVariant: onSurfaceVariant ?? Color(scheme.onSurfaceVariant), - inverseSurface: inverseSurface ?? Color(scheme.inverseSurface), - onInverseSurface: onInverseSurface ?? Color(scheme.inverseOnSurface), - inversePrimary: inversePrimary ?? Color(scheme.inversePrimary), - shadow: shadow ?? Color(scheme.shadow), - brightness: brightness, - ); - } + assert(onBackground != null), + assert(onError != null), + assert(brightness != null); /// Create a ColorScheme based on a purple primary color that matches the /// [baseline Material color scheme](https://material.io/design/color/the-color-system.html#color-theme-creation). const ColorScheme.light({ - this.brightness = Brightness.light, this.primary = const Color(0xff6200ee), - this.onPrimary = Colors.white, - Color? primaryContainer, - Color? onPrimaryContainer, + this.primaryVariant = const Color(0xff3700b3), this.secondary = const Color(0xff03dac6), - this.onSecondary = Colors.black, - Color? secondaryContainer, - Color? onSecondaryContainer, - Color? tertiary, - Color? onTertiary, - Color? tertiaryContainer, - Color? onTertiaryContainer, - this.error = const Color(0xffb00020), - this.onError = Colors.white, - Color? errorContainer, - Color? onErrorContainer, - this.background = Colors.white, - this.onBackground = Colors.black, + this.secondaryVariant = const Color(0xff018786), this.surface = Colors.white, + this.background = Colors.white, + this.error = const Color(0xffb00020), + this.onPrimary = Colors.white, + this.onSecondary = Colors.black, this.onSurface = Colors.black, - Color? surfaceVariant, - Color? onSurfaceVariant, - Color? outline, - Color? shadow, - Color? inverseSurface, - Color? onInverseSurface, - Color? inversePrimary, - @Deprecated( - 'Use primary or primaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? primaryVariant = const Color(0xff3700b3), - @Deprecated( - 'Use secondary or secondaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? secondaryVariant = const Color(0xff018786), - }) : assert(brightness != null), - assert(primary != null), - assert(onPrimary != null), + this.onBackground = Colors.black, + this.onError = Colors.white, + this.brightness = Brightness.light, + }) : assert(primary != null), + assert(primaryVariant != null), assert(secondary != null), - assert(onSecondary != null), - assert(error != null), - assert(onError != null), - assert(background != null), - assert(onBackground != null), + assert(secondaryVariant != null), assert(surface != null), + assert(background != null), + assert(error != null), + assert(onPrimary != null), + assert(onSecondary != null), assert(onSurface != null), - _primaryContainer = primaryContainer, - _onPrimaryContainer = onPrimaryContainer, - _secondaryContainer = secondaryContainer, - _onSecondaryContainer = onSecondaryContainer, - _tertiary = tertiary, - _onTertiary = onTertiary, - _tertiaryContainer = tertiaryContainer, - _onTertiaryContainer = onTertiaryContainer, - _errorContainer = errorContainer, - _onErrorContainer = onErrorContainer, - _surfaceVariant = surfaceVariant, - _onSurfaceVariant = onSurfaceVariant, - _outline = outline, - _shadow = shadow, - _inverseSurface = inverseSurface, - _onInverseSurface = onInverseSurface, - _inversePrimary = inversePrimary, - _primaryVariant = primaryVariant, - _secondaryVariant = secondaryVariant; + assert(onBackground != null), + assert(onError != null), + assert(brightness != null); /// Create the recommended dark color scheme that matches the /// [baseline Material color scheme](https://material.io/design/color/dark-theme.html#ui-application). const ColorScheme.dark({ - this.brightness = Brightness.dark, this.primary = const Color(0xffbb86fc), - this.onPrimary = Colors.black, - Color? primaryContainer, - Color? onPrimaryContainer, + this.primaryVariant = const Color(0xff3700B3), this.secondary = const Color(0xff03dac6), - this.onSecondary = Colors.black, - Color? secondaryContainer, - Color? onSecondaryContainer, - Color? tertiary, - Color? onTertiary, - Color? tertiaryContainer, - Color? onTertiaryContainer, - this.error = const Color(0xffcf6679), - this.onError = Colors.black, - Color? errorContainer, - Color? onErrorContainer, - this.background = const Color(0xff121212), - this.onBackground = Colors.white, + this.secondaryVariant = const Color(0xff03dac6), this.surface = const Color(0xff121212), + this.background = const Color(0xff121212), + this.error = const Color(0xffcf6679), + this.onPrimary = Colors.black, + this.onSecondary = Colors.black, this.onSurface = Colors.white, - Color? surfaceVariant, - Color? onSurfaceVariant, - Color? outline, - Color? shadow, - Color? inverseSurface, - Color? onInverseSurface, - Color? inversePrimary, - @Deprecated( - 'Use primary or primaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? primaryVariant = const Color(0xff3700B3), - @Deprecated( - 'Use secondary or secondaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? secondaryVariant = const Color(0xff03dac6), - }) : assert(brightness != null), - assert(primary != null), - assert(onPrimary != null), + this.onBackground = Colors.white, + this.onError = Colors.black, + this.brightness = Brightness.dark, + }) : assert(primary != null), + assert(primaryVariant != null), assert(secondary != null), - assert(onSecondary != null), - assert(error != null), - assert(onError != null), - assert(background != null), - assert(onBackground != null), + assert(secondaryVariant != null), assert(surface != null), + assert(background != null), + assert(error != null), + assert(onPrimary != null), + assert(onSecondary != null), assert(onSurface != null), - _primaryContainer = primaryContainer, - _onPrimaryContainer = onPrimaryContainer, - _secondaryContainer = secondaryContainer, - _onSecondaryContainer = onSecondaryContainer, - _tertiary = tertiary, - _onTertiary = onTertiary, - _tertiaryContainer = tertiaryContainer, - _onTertiaryContainer = onTertiaryContainer, - _errorContainer = errorContainer, - _onErrorContainer = onErrorContainer, - _surfaceVariant = surfaceVariant, - _onSurfaceVariant = onSurfaceVariant, - _outline = outline, - _shadow = shadow, - _inverseSurface = inverseSurface, - _onInverseSurface = onInverseSurface, - _inversePrimary = inversePrimary, - _primaryVariant = primaryVariant, - _secondaryVariant = secondaryVariant; + assert(onBackground != null), + assert(onError != null), + assert(brightness != null); + /// Create a high contrast ColorScheme based on a purple primary color that /// matches the [baseline Material color scheme](https://material.io/design/color/the-color-system.html#color-theme-creation). const ColorScheme.highContrastLight({ - this.brightness = Brightness.light, this.primary = const Color(0xff0000ba), - this.onPrimary = Colors.white, - Color? primaryContainer, - Color? onPrimaryContainer, + this.primaryVariant = const Color(0xff000088), this.secondary = const Color(0xff66fff9), - this.onSecondary = Colors.black, - Color? secondaryContainer, - Color? onSecondaryContainer, - Color? tertiary, - Color? onTertiary, - Color? tertiaryContainer, - Color? onTertiaryContainer, - this.error = const Color(0xff790000), - this.onError = Colors.white, - Color? errorContainer, - Color? onErrorContainer, - this.background = Colors.white, - this.onBackground = Colors.black, + this.secondaryVariant = const Color(0xff018786), this.surface = Colors.white, + this.background = Colors.white, + this.error = const Color(0xff790000), + this.onPrimary = Colors.white, + this.onSecondary = Colors.black, this.onSurface = Colors.black, - Color? surfaceVariant, - Color? onSurfaceVariant, - Color? outline, - Color? shadow, - Color? inverseSurface, - Color? onInverseSurface, - Color? inversePrimary, - @Deprecated( - 'Use primary or primaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? primaryVariant = const Color(0xff000088), - @Deprecated( - 'Use secondary or secondaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? secondaryVariant = const Color(0xff018786), - }) : assert(brightness != null), - assert(primary != null), - assert(onPrimary != null), - assert(secondary != null), - assert(onSecondary != null), - assert(error != null), - assert(onError != null), - assert(background != null), - assert(onBackground != null), - assert(surface != null), - assert(onSurface != null), - _primaryContainer = primaryContainer, - _onPrimaryContainer = onPrimaryContainer, - _secondaryContainer = secondaryContainer, - _onSecondaryContainer = onSecondaryContainer, - _tertiary = tertiary, - _onTertiary = onTertiary, - _tertiaryContainer = tertiaryContainer, - _onTertiaryContainer = onTertiaryContainer, - _errorContainer = errorContainer, - _onErrorContainer = onErrorContainer, - _surfaceVariant = surfaceVariant, - _onSurfaceVariant = onSurfaceVariant, - _outline = outline, - _shadow = shadow, - _inverseSurface = inverseSurface, - _onInverseSurface = onInverseSurface, - _inversePrimary = inversePrimary, - _primaryVariant = primaryVariant, - _secondaryVariant = secondaryVariant; + this.onBackground = Colors.black, + this.onError = Colors.white, + this.brightness = Brightness.light, + }) : assert(primary != null), + assert(primaryVariant != null), + assert(secondary != null), + assert(secondaryVariant != null), + assert(surface != null), + assert(background != null), + assert(error != null), + assert(onPrimary != null), + assert(onSecondary != null), + assert(onSurface != null), + assert(onBackground != null), + assert(onError != null), + assert(brightness != null); /// Create a high contrast ColorScheme based on the dark /// [baseline Material color scheme](https://material.io/design/color/dark-theme.html#ui-application). const ColorScheme.highContrastDark({ - this.brightness = Brightness.dark, this.primary = const Color(0xffefb7ff), - this.onPrimary = Colors.black, - Color? primaryContainer, - Color? onPrimaryContainer, + this.primaryVariant = const Color(0xffbe9eff), this.secondary = const Color(0xff66fff9), - this.onSecondary = Colors.black, - Color? secondaryContainer, - Color? onSecondaryContainer, - Color? tertiary, - Color? onTertiary, - Color? tertiaryContainer, - Color? onTertiaryContainer, - this.error = const Color(0xff9b374d), - this.onError = Colors.black, - Color? errorContainer, - Color? onErrorContainer, - this.background = const Color(0xff121212), - this.onBackground = Colors.white, + this.secondaryVariant = const Color(0xff66fff9), this.surface = const Color(0xff121212), + this.background = const Color(0xff121212), + this.error = const Color(0xff9b374d), + this.onPrimary = Colors.black, + this.onSecondary = Colors.black, this.onSurface = Colors.white, - Color? surfaceVariant, - Color? onSurfaceVariant, - Color? outline, - Color? shadow, - Color? inverseSurface, - Color? onInverseSurface, - Color? inversePrimary, - @Deprecated( - 'Use primary or primaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? primaryVariant = const Color(0xffbe9eff), - @Deprecated( - 'Use secondary or secondaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? secondaryVariant = const Color(0xff66fff9), - }) : assert(brightness != null), - assert(primary != null), - assert(onPrimary != null), - assert(secondary != null), - assert(onSecondary != null), - assert(error != null), - assert(onError != null), - assert(background != null), - assert(onBackground != null), - assert(surface != null), - assert(onSurface != null), - _primaryContainer = primaryContainer, - _onPrimaryContainer = onPrimaryContainer, - _secondaryContainer = secondaryContainer, - _onSecondaryContainer = onSecondaryContainer, - _tertiary = tertiary, - _onTertiary = onTertiary, - _tertiaryContainer = tertiaryContainer, - _onTertiaryContainer = onTertiaryContainer, - _errorContainer = errorContainer, - _onErrorContainer = onErrorContainer, - _surfaceVariant = surfaceVariant, - _onSurfaceVariant = onSurfaceVariant, - _outline = outline, - _shadow = shadow, - _inverseSurface = inverseSurface, - _onInverseSurface = onInverseSurface, - _inversePrimary = inversePrimary, - _primaryVariant = primaryVariant, - _secondaryVariant = secondaryVariant; + this.onBackground = Colors.white, + this.onError = Colors.black, + this.brightness = Brightness.dark, + }) : assert(primary != null), + assert(primaryVariant != null), + assert(secondary != null), + assert(secondaryVariant != null), + assert(surface != null), + assert(background != null), + assert(error != null), + assert(onPrimary != null), + assert(onSecondary != null), + assert(onSurface != null), + assert(onBackground != null), + assert(onError != null), + assert(brightness != null); /// Create a color scheme from a [MaterialColor] swatch. /// @@ -567,258 +206,98 @@ class ColorScheme with Diagnosticable { static Brightness _brightnessFor(Color color) => ThemeData.estimateBrightnessForColor(color); - /// The overall brightness of this color scheme. - final Brightness brightness; - /// The color displayed most frequently across your app’s screens and components. final Color primary; - /// A color that's clearly legible when drawn on [primary]. - /// - /// To ensure that an app is accessible, a contrast ratio between - /// [primary] and [onPrimary] of at least 4.5:1 is recommended. See - /// . - final Color onPrimary; - - final Color? _primaryContainer; - /// A color used for elements needing less emphasis than [primary]. - Color get primaryContainer => _primaryContainer ?? primary; - - final Color? _onPrimaryContainer; - /// A color that's clearly legible when drawn on [primaryContainer]. - /// - /// To ensure that an app is accessible, a contrast ratio between - /// [primaryContainer] and [onPrimaryContainer] of at least 4.5:1 - /// is recommended. See - /// . - Color get onPrimaryContainer => _onPrimaryContainer ?? onPrimary; + /// A darker version of the primary color. + final Color primaryVariant; - /// An accent color used for less prominent components in the UI, such as - /// filter chips, while expanding the opportunity for color expression. + /// An accent color that, when used sparingly, calls attention to parts + /// of your app. final Color secondary; - /// A color that's clearly legible when drawn on [secondary]. - /// - /// To ensure that an app is accessible, a contrast ratio between - /// [secondary] and [onSecondary] of at least 4.5:1 is recommended. See - /// . - final Color onSecondary; - - final Color? _secondaryContainer; - /// A color used for elements needing less emphasis than [secondary]. - Color get secondaryContainer => _secondaryContainer ?? secondary; - - final Color? _onSecondaryContainer; - /// A color that's clearly legible when drawn on [secondaryContainer]. - /// - /// To ensure that an app is accessible, a contrast ratio between - /// [secondaryContainer] and [onSecondaryContainer] of at least 4.5:1 is - /// recommended. See - /// . - Color get onSecondaryContainer => _onSecondaryContainer ?? onSecondary; - - final Color? _tertiary; - /// A color used as a contrasting accent that can balance [primary] - /// and [secondary] colors or bring heightened attention to an element, - /// such as an input field. - Color get tertiary => _tertiary ?? secondary; - - final Color? _onTertiary; - /// A color that's clearly legible when drawn on [tertiary]. - /// - /// To ensure that an app is accessible, a contrast ratio between - /// [tertiary] and [onTertiary] of at least 4.5:1 is recommended. See - /// . - Color get onTertiary => _onTertiary ?? onSecondary; + /// A darker version of the secondary color. + final Color secondaryVariant; - final Color? _tertiaryContainer; - /// A color used for elements needing less emphasis than [tertiary]. - Color get tertiaryContainer => _tertiaryContainer ?? tertiary; + /// The background color for widgets like [Card]. + final Color surface; - final Color? _onTertiaryContainer; - /// A color that's clearly legible when drawn on [tertiaryContainer]. - /// - /// To ensure that an app is accessible, a contrast ratio between - /// [tertiaryContainer] and [onTertiaryContainer] of at least 4.5:1 is - /// recommended. See - /// . - Color get onTertiaryContainer => _onTertiaryContainer ?? onTertiary; + /// A color that typically appears behind scrollable content. + final Color background; /// The color to use for input validation errors, e.g. for /// [InputDecoration.errorText]. final Color error; - /// A color that's clearly legible when drawn on [error]. - /// - /// To ensure that an app is accessible, a contrast ratio between - /// [error] and [onError] of at least 4.5:1 is recommended. See - /// . - final Color onError; - - final Color? _errorContainer; - /// A color used for error elements needing less emphasis than [error]. - Color get errorContainer => _errorContainer ?? error; - - final Color? _onErrorContainer; - /// A color that's clearly legible when drawn on [errorContainer]. + /// A color that's clearly legible when drawn on [primary]. /// - /// To ensure that an app is accessible, a contrast ratio between - /// [errorContainer] and [onErrorContainer] of at least 4.5:1 is - /// recommended. See + /// To ensure that an app is accessible, a contrast ratio of 4.5:1 for [primary] + /// and [onPrimary] is recommended. See /// . - Color get onErrorContainer => _onErrorContainer ?? onError; - - /// A color that typically appears behind scrollable content. - final Color background; + final Color onPrimary; - /// A color that's clearly legible when drawn on [background]. + /// A color that's clearly legible when drawn on [secondary]. /// - /// To ensure that an app is accessible, a contrast ratio between - /// [background] and [onBackground] of at least 4.5:1 is recommended. See + /// To ensure that an app is accessible, a contrast ratio of 4.5:1 for [secondary] + /// and [onSecondary] is recommended. See /// . - final Color onBackground; - - /// The background color for widgets like [Card]. - final Color surface; + final Color onSecondary; /// A color that's clearly legible when drawn on [surface]. /// - /// To ensure that an app is accessible, a contrast ratio between - /// [surface] and [onSurface] of at least 4.5:1 is recommended. See + /// To ensure that an app is accessible, a contrast ratio of 4.5:1 for [surface] + /// and [onSurface] is recommended. See /// . final Color onSurface; - final Color? _surfaceVariant; - /// A color variant of [surface] that can be used for differentiation against - /// a component using [surface]. - Color get surfaceVariant => _surfaceVariant ?? surface; - - final Color? _onSurfaceVariant; - /// A color that's clearly legible when drawn on [surfaceVariant]. + /// A color that's clearly legible when drawn on [background]. /// - /// To ensure that an app is accessible, a contrast ratio between - /// [surfaceVariant] and [onSurfaceVariant] of at least 4.5:1 is - /// recommended. See + /// To ensure that an app is accessible, a contrast ratio of 4.5:1 for [background] + /// and [onBackground] is recommended. See /// . - Color get onSurfaceVariant => _onSurfaceVariant ?? onSurface; - - final Color? _outline; - /// A utility color that creates boundaries and emphasis to improve usability. - Color get outline => _outline ?? onBackground; - - final Color? _shadow; - /// A color use to paint the drop shadows of elevated components. - Color get shadow => _shadow ?? onBackground; - - final Color? _inverseSurface; - /// A surface color used for displaying the reverse of what’s seen in the - /// surrounding UI, for example in a SnackBar to bring attention to - /// an alert. - Color get inverseSurface => _inverseSurface ?? onSurface; + final Color onBackground; - final Color? _onInverseSurface; - /// A color that's clearly legible when drawn on [inverseSurface]. + /// A color that's clearly legible when drawn on [error]. /// - /// To ensure that an app is accessible, a contrast ratio between - /// [inverseSurface] and [onInverseSurface] of at least 4.5:1 is - /// recommended. See + /// To ensure that an app is accessible, a contrast ratio of 4.5:1 for [error] + /// and [onError] is recommended. See /// . - Color get onInverseSurface => _onInverseSurface ?? surface; - - final Color? _inversePrimary; - /// An accent color used for displaying a highlight color on [inverseSurface] - /// backgrounds, like button text in a SnackBar. - Color get inversePrimary => _inversePrimary ?? onPrimary; - - final Color? _primaryVariant; - /// A darker version of the primary color. - @Deprecated( - 'Use primary or primaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color get primaryVariant => _primaryVariant ?? primary; + final Color onError; - final Color? _secondaryVariant; - /// A darker version of the secondary color. - @Deprecated( - 'Use secondary or secondaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color get secondaryVariant => _secondaryVariant ?? secondary; + /// The overall brightness of this color scheme. + final Brightness brightness; /// Creates a copy of this color scheme with the given fields /// replaced by the non-null parameter values. ColorScheme copyWith({ - Brightness? brightness, Color? primary, - Color? onPrimary, - Color? primaryContainer, - Color? onPrimaryContainer, + Color? primaryVariant, Color? secondary, - Color? onSecondary, - Color? secondaryContainer, - Color? onSecondaryContainer, - Color? tertiary, - Color? onTertiary, - Color? tertiaryContainer, - Color? onTertiaryContainer, - Color? error, - Color? onError, - Color? errorContainer, - Color? onErrorContainer, - Color? background, - Color? onBackground, + Color? secondaryVariant, Color? surface, + Color? background, + Color? error, + Color? onPrimary, + Color? onSecondary, Color? onSurface, - Color? surfaceVariant, - Color? onSurfaceVariant, - Color? outline, - Color? shadow, - Color? inverseSurface, - Color? onInverseSurface, - Color? inversePrimary, - @Deprecated( - 'Use primary or primaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? primaryVariant, - @Deprecated( - 'Use secondary or secondaryContainer instead. ' - 'This feature was deprecated after v2.6.0-0.0.pre.' - ) - Color? secondaryVariant, + Color? onBackground, + Color? onError, + Brightness? brightness, }) { return ColorScheme( - brightness: brightness ?? this.brightness, - primary : primary ?? this.primary, - onPrimary : onPrimary ?? this.onPrimary, - primaryContainer : primaryContainer ?? this.primaryContainer, - onPrimaryContainer : onPrimaryContainer ?? this.onPrimaryContainer, - secondary : secondary ?? this.secondary, - onSecondary : onSecondary ?? this.onSecondary, - secondaryContainer : secondaryContainer ?? this.secondaryContainer, - onSecondaryContainer : onSecondaryContainer ?? this.onSecondaryContainer, - tertiary : tertiary ?? this.tertiary, - onTertiary : onTertiary ?? this.onTertiary, - tertiaryContainer : tertiaryContainer ?? this.tertiaryContainer, - onTertiaryContainer : onTertiaryContainer ?? this.onTertiaryContainer, - error : error ?? this.error, - onError : onError ?? this.onError, - errorContainer : errorContainer ?? this.errorContainer, - onErrorContainer : onErrorContainer ?? this.onErrorContainer, - background : background ?? this.background, - onBackground : onBackground ?? this.onBackground, - surface : surface ?? this.surface, - onSurface : onSurface ?? this.onSurface, - surfaceVariant : surfaceVariant ?? this.surfaceVariant, - onSurfaceVariant : onSurfaceVariant ?? this.onSurfaceVariant, - outline : outline ?? this.outline, - shadow : shadow ?? this.shadow, - inverseSurface : inverseSurface ?? this.inverseSurface, - onInverseSurface : onInverseSurface ?? this.onInverseSurface, - inversePrimary : inversePrimary ?? this.inversePrimary, + primary: primary ?? this.primary, primaryVariant: primaryVariant ?? this.primaryVariant, + secondary: secondary ?? this.secondary, secondaryVariant: secondaryVariant ?? this.secondaryVariant, + surface: surface ?? this.surface, + background: background ?? this.background, + error: error ?? this.error, + onPrimary: onPrimary ?? this.onPrimary, + onSecondary: onSecondary ?? this.onSecondary, + onSurface: onSurface ?? this.onSurface, + onBackground: onBackground ?? this.onBackground, + onError: onError ?? this.onError, + brightness: brightness ?? this.brightness, ); } @@ -827,36 +306,19 @@ class ColorScheme with Diagnosticable { /// {@macro dart.ui.shadow.lerp} static ColorScheme lerp(ColorScheme a, ColorScheme b, double t) { return ColorScheme( - brightness: t < 0.5 ? a.brightness : b.brightness, primary: Color.lerp(a.primary, b.primary, t)!, - onPrimary: Color.lerp(a.onPrimary, b.onPrimary, t)!, - primaryContainer: Color.lerp(a.primaryContainer, b.primaryContainer, t), - onPrimaryContainer: Color.lerp(a.onPrimaryContainer, b.onPrimaryContainer, t), + primaryVariant: Color.lerp(a.primaryVariant, b.primaryVariant, t)!, secondary: Color.lerp(a.secondary, b.secondary, t)!, - onSecondary: Color.lerp(a.onSecondary, b.onSecondary, t)!, - secondaryContainer: Color.lerp(a.secondaryContainer, b.secondaryContainer, t), - onSecondaryContainer: Color.lerp(a.onSecondaryContainer, b.onSecondaryContainer, t), - tertiary: Color.lerp(a.tertiary, b.tertiary, t), - onTertiary: Color.lerp(a.onTertiary, b.onTertiary, t), - tertiaryContainer: Color.lerp(a.tertiaryContainer, b.tertiaryContainer, t), - onTertiaryContainer: Color.lerp(a.onTertiaryContainer, b.onTertiaryContainer, t), - error: Color.lerp(a.error, b.error, t)!, - onError: Color.lerp(a.onError, b.onError, t)!, - errorContainer: Color.lerp(a.errorContainer, b.errorContainer, t), - onErrorContainer: Color.lerp(a.onErrorContainer, b.onErrorContainer, t), - background: Color.lerp(a.background, b.background, t)!, - onBackground: Color.lerp(a.onBackground, b.onBackground, t)!, + secondaryVariant: Color.lerp(a.secondaryVariant, b.secondaryVariant, t)!, surface: Color.lerp(a.surface, b.surface, t)!, + background: Color.lerp(a.background, b.background, t)!, + error: Color.lerp(a.error, b.error, t)!, + onPrimary: Color.lerp(a.onPrimary, b.onPrimary, t)!, + onSecondary: Color.lerp(a.onSecondary, b.onSecondary, t)!, onSurface: Color.lerp(a.onSurface, b.onSurface, t)!, - surfaceVariant: Color.lerp(a.surfaceVariant, b.surfaceVariant, t), - onSurfaceVariant: Color.lerp(a.onSurfaceVariant, b.onSurfaceVariant, t), - outline: Color.lerp(a.outline, b.outline, t), - shadow: Color.lerp(a.shadow, b.shadow, t), - inverseSurface: Color.lerp(a.inverseSurface, b.inverseSurface, t), - onInverseSurface: Color.lerp(a.onInverseSurface, b.onInverseSurface, t), - inversePrimary: Color.lerp(a.inversePrimary, b.inversePrimary, t), - primaryVariant: Color.lerp(a.primaryVariant, b.primaryVariant, t), - secondaryVariant: Color.lerp(a.secondaryVariant, b.secondaryVariant, t), + onBackground: Color.lerp(a.onBackground, b.onBackground, t)!, + onError: Color.lerp(a.onError, b.onError, t)!, + brightness: t < 0.5 ? a.brightness : b.brightness, ); } @@ -867,107 +329,56 @@ class ColorScheme with Diagnosticable { if (other.runtimeType != runtimeType) return false; return other is ColorScheme - && other.brightness == brightness - && other.primary == primary - && other.onPrimary == onPrimary - && other.primaryContainer == primaryContainer - && other.onPrimaryContainer == onPrimaryContainer - && other.secondary == secondary - && other.onSecondary == onSecondary - && other.secondaryContainer == secondaryContainer - && other.onSecondaryContainer == onSecondaryContainer - && other.tertiary == tertiary - && other.onTertiary == onTertiary - && other.tertiaryContainer == tertiaryContainer - && other.onTertiaryContainer == onTertiaryContainer - && other.error == error - && other.onError == onError - && other.errorContainer == errorContainer - && other.onErrorContainer == onErrorContainer - && other.background == background - && other.onBackground == onBackground - && other.surface == surface - && other.onSurface == onSurface - && other.surfaceVariant == surfaceVariant - && other.onSurfaceVariant == onSurfaceVariant - && other.outline == outline - && other.shadow == shadow - && other.inverseSurface == inverseSurface - && other.onInverseSurface == onInverseSurface - && other.inversePrimary == inversePrimary - && other.primaryVariant == primaryVariant - && other.secondaryVariant == secondaryVariant; + && other.primary == primary + && other.primaryVariant == primaryVariant + && other.secondary == secondary + && other.secondaryVariant == secondaryVariant + && other.surface == surface + && other.background == background + && other.error == error + && other.onPrimary == onPrimary + && other.onSecondary == onSecondary + && other.onSurface == onSurface + && other.onBackground == onBackground + && other.onError == onError + && other.brightness == brightness; } @override int get hashCode { - return hashList([ - brightness, + return hashValues( primary, - onPrimary, - primaryContainer, - onPrimaryContainer, + primaryVariant, secondary, - onSecondary, - secondaryContainer, - onSecondaryContainer, - tertiary, - onTertiary, - tertiaryContainer, - onTertiaryContainer, - error, - onError, - errorContainer, - onErrorContainer, - background, - onBackground, + secondaryVariant, surface, + background, + error, + onPrimary, + onSecondary, onSurface, - surfaceVariant, - onSurfaceVariant, - outline, - shadow, - inverseSurface, - onInverseSurface, - inversePrimary, - primaryVariant, - secondaryVariant, - ]); + onBackground, + onError, + brightness, + ); } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); const ColorScheme defaultScheme = ColorScheme.light(); - properties.add(DiagnosticsProperty('brightness', brightness, defaultValue: defaultScheme.brightness)); properties.add(ColorProperty('primary', primary, defaultValue: defaultScheme.primary)); - properties.add(ColorProperty('onPrimary', onPrimary, defaultValue: defaultScheme.onPrimary)); - properties.add(ColorProperty('primaryContainer', primaryContainer, defaultValue: defaultScheme.primaryContainer)); - properties.add(ColorProperty('onPrimaryContainer', onPrimaryContainer, defaultValue: defaultScheme.onPrimaryContainer)); + properties.add(ColorProperty('primaryVariant', primaryVariant, defaultValue: defaultScheme.primaryVariant)); properties.add(ColorProperty('secondary', secondary, defaultValue: defaultScheme.secondary)); - properties.add(ColorProperty('onSecondary', onSecondary, defaultValue: defaultScheme.onSecondary)); - properties.add(ColorProperty('secondaryContainer', secondaryContainer, defaultValue: defaultScheme.secondaryContainer)); - properties.add(ColorProperty('onSecondaryContainer', onSecondaryContainer, defaultValue: defaultScheme.onSecondaryContainer)); - properties.add(ColorProperty('tertiary', tertiary, defaultValue: defaultScheme.tertiary)); - properties.add(ColorProperty('onTertiary', onTertiary, defaultValue: defaultScheme.onTertiary)); - properties.add(ColorProperty('tertiaryContainer', tertiaryContainer, defaultValue: defaultScheme.tertiaryContainer)); - properties.add(ColorProperty('onTertiaryContainer', onTertiaryContainer, defaultValue: defaultScheme.onTertiaryContainer)); - properties.add(ColorProperty('error', error, defaultValue: defaultScheme.error)); - properties.add(ColorProperty('onError', onError, defaultValue: defaultScheme.onError)); - properties.add(ColorProperty('errorContainer', errorContainer, defaultValue: defaultScheme.errorContainer)); - properties.add(ColorProperty('onErrorContainer', onErrorContainer, defaultValue: defaultScheme.onErrorContainer)); - properties.add(ColorProperty('background', background, defaultValue: defaultScheme.background)); - properties.add(ColorProperty('onBackground', onBackground, defaultValue: defaultScheme.onBackground)); + properties.add(ColorProperty('secondaryVariant', secondaryVariant, defaultValue: defaultScheme.secondaryVariant)); properties.add(ColorProperty('surface', surface, defaultValue: defaultScheme.surface)); + properties.add(ColorProperty('background', background, defaultValue: defaultScheme.background)); + properties.add(ColorProperty('error', error, defaultValue: defaultScheme.error)); + properties.add(ColorProperty('onPrimary', onPrimary, defaultValue: defaultScheme.onPrimary)); + properties.add(ColorProperty('onSecondary', onSecondary, defaultValue: defaultScheme.onSecondary)); properties.add(ColorProperty('onSurface', onSurface, defaultValue: defaultScheme.onSurface)); - properties.add(ColorProperty('surfaceVariant', surfaceVariant, defaultValue: defaultScheme.surfaceVariant)); - properties.add(ColorProperty('onSurfaceVariant', onSurfaceVariant, defaultValue: defaultScheme.onSurfaceVariant)); - properties.add(ColorProperty('outline', outline, defaultValue: defaultScheme.outline)); - properties.add(ColorProperty('shadow', shadow, defaultValue: defaultScheme.shadow)); - properties.add(ColorProperty('inverseSurface', inverseSurface, defaultValue: defaultScheme.inverseSurface)); - properties.add(ColorProperty('onInverseSurface', onInverseSurface, defaultValue: defaultScheme.onInverseSurface)); - properties.add(ColorProperty('inversePrimary', inversePrimary, defaultValue: defaultScheme.inversePrimary)); - properties.add(ColorProperty('primaryVariant', primaryVariant, defaultValue: defaultScheme.primaryVariant)); - properties.add(ColorProperty('secondaryVariant', secondaryVariant, defaultValue: defaultScheme.secondaryVariant)); + properties.add(ColorProperty('onBackground', onBackground, defaultValue: defaultScheme.onBackground)); + properties.add(ColorProperty('onError', onError, defaultValue: defaultScheme.onError)); + properties.add(DiagnosticsProperty('brightness', brightness, defaultValue: defaultScheme.brightness)); } } diff --git a/packages/flutter/lib/src/material/colors.dart b/packages/flutter/lib/src/material/colors.dart index f112b90e2630c..71da21568e20f 100644 --- a/packages/flutter/lib/src/material/colors.dart +++ b/packages/flutter/lib/src/material/colors.dart @@ -71,6 +71,9 @@ class MaterialAccentColor extends ColorSwatch { const MaterialAccentColor(int primary, Map swatch) : super(primary, swatch); /// The lightest shade. + Color get shade50 => this[50]!; + + /// The second lightest shade. Color get shade100 => this[100]!; /// The default shade. diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart index f8972c3fc282c..4aa24900d75c7 100644 --- a/packages/flutter/lib/src/material/data_table.dart +++ b/packages/flutter/lib/src/material/data_table.dart @@ -701,6 +701,9 @@ class DataTable extends StatelessWidget { ), child: Center( child: Checkbox( + // TODO(per): Remove when Checkbox has theme, https://github.com/flutter/flutter/issues/53420. + activeColor: themeData.colorScheme.primary, + checkColor: themeData.colorScheme.onPrimary, value: checked, onChanged: onCheckboxChanged, tristate: tristate, @@ -1139,7 +1142,6 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin { @override void initState() { super.initState(); - _up = widget.up; _opacityAnimation = CurvedAnimation( parent: _opacityController = AnimationController( duration: widget.duration, diff --git a/packages/flutter/lib/src/material/desktop_text_selection.dart b/packages/flutter/lib/src/material/desktop_text_selection.dart index 9ee6610360610..e24f4dbb26ed6 100644 --- a/packages/flutter/lib/src/material/desktop_text_selection.dart +++ b/packages/flutter/lib/src/material/desktop_text_selection.dart @@ -236,6 +236,7 @@ class _DesktopTextSelectionToolbar extends StatelessWidget { Key? key, required this.anchor, required this.children, + this.toolbarBuilder = _defaultToolbarBuilder, }) : assert(children.length > 0), super(key: key); @@ -250,6 +251,12 @@ class _DesktopTextSelectionToolbar extends StatelessWidget { /// Material-style desktop text selection toolbar text button. final List children; + /// {@macro flutter.material.TextSelectionToolbar.toolbarBuilder} + /// + /// The given anchor and isAbove can be used to position an arrow, as in the + /// default toolbar. + final ToolbarBuilder toolbarBuilder; + // Builds a desktop toolbar in the Material style. static Widget _defaultToolbarBuilder(BuildContext context, Widget child) { return SizedBox( @@ -283,7 +290,7 @@ class _DesktopTextSelectionToolbar extends StatelessWidget { delegate: DesktopTextSelectionToolbarLayoutDelegate( anchor: anchor - localAdjustment, ), - child: _defaultToolbarBuilder(context, Column( + child: toolbarBuilder(context, Column( mainAxisSize: MainAxisSize.min, children: children, )), diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 128e56c3a9d48..a8f362fed50d3 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -448,7 +448,7 @@ class AlertDialog extends StatelessWidget { /// {@macro flutter.material.dialog.shape} final ShapeBorder? shape; - /// {@macro flutter.material.dialog.alignment} + /// {@macro flutter.material.dialog.shape} final AlignmentGeometry? alignment; /// Determines whether the [title] and [content] widgets are wrapped in a diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart index faccd47bb3062..ee2f713aea587 100644 --- a/packages/flutter/lib/src/material/dropdown.dart +++ b/packages/flutter/lib/src/material/dropdown.dart @@ -1276,7 +1276,6 @@ class _DropdownButtonState extends State> with WidgetsBindi borderRadius: widget.borderRadius, ); - focusNode?.requestFocus(); navigator.push(_dropdownRoute!).then((_DropdownRouteResult? newValue) { _removeDropdownRoute(); if (!mounted || newValue == null) @@ -1360,8 +1359,8 @@ class _DropdownButtonState extends State> with WidgetsBindi // otherwise, no explicit type adding items maybe trigger a crash/failure // when hint and selectedItemBuilder are provided. final List items = widget.selectedItemBuilder == null - ? (widget.items != null ? List.of(widget.items!) : []) - : List.of(widget.selectedItemBuilder!(context)); + ? (widget.items != null ? List.from(widget.items!) : []) + : List.from(widget.selectedItemBuilder!(context)); int? hintIndex; if (widget.hint != null || (!_enabled && widget.disabledHint != null)) { @@ -1540,9 +1539,6 @@ class DropdownButtonFormField extends FormField { double? menuMaxHeight, bool? enableFeedback, AlignmentGeometry alignment = AlignmentDirectional.centerStart, - BorderRadius? borderRadius, - // When adding new arguments, consider adding similar arguments to - // DropdownButton. }) : assert(items == null || items.isEmpty || value == null || items.where((DropdownMenuItem item) { return item.value == value; @@ -1618,7 +1614,6 @@ class DropdownButtonFormField extends FormField { menuMaxHeight: menuMaxHeight, enableFeedback: enableFeedback, alignment: alignment, - borderRadius: borderRadius, ), ), ); diff --git a/packages/flutter/lib/src/material/elevated_button.dart b/packages/flutter/lib/src/material/elevated_button.dart index 6b163549f272c..7afb26a15854a 100644 --- a/packages/flutter/lib/src/material/elevated_button.dart +++ b/packages/flutter/lib/src/material/elevated_button.dart @@ -255,7 +255,7 @@ class ElevatedButton extends ButtonStyleButton { /// * `side` - null /// * `shape` - RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)) /// * `mouseCursor` - /// * disabled - SystemMouseCursors.basic + /// * disabled - SystemMouseCursors.forbidden /// * others - SystemMouseCursors.click /// * `visualDensity` - theme.visualDensity /// * `tapTargetSize` - theme.materialTapTargetSize @@ -300,7 +300,7 @@ class ElevatedButton extends ButtonStyleButton { maximumSize: Size.infinite, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), enabledMouseCursor: SystemMouseCursors.click, - disabledMouseCursor: SystemMouseCursors.basic, + disabledMouseCursor: SystemMouseCursors.forbidden, visualDensity: theme.visualDensity, tapTargetSize: theme.materialTapTargetSize, animationDuration: kThemeChangeDuration, diff --git a/packages/flutter/lib/src/material/expansion_panel.dart b/packages/flutter/lib/src/material/expansion_panel.dart index 60c558790f5e1..b82d76bcfccc6 100644 --- a/packages/flutter/lib/src/material/expansion_panel.dart +++ b/packages/flutter/lib/src/material/expansion_panel.dart @@ -58,8 +58,6 @@ typedef ExpansionPanelHeaderBuilder = Widget Function(BuildContext context, bool /// expanded or collapsed. The body of the panel is only visible when it is /// expanded. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=2aJZzRMziJc} -/// /// Expansion panels are only intended to be used as children for /// [ExpansionPanelList]. /// diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart index ff8c739f86789..1ca2fe6121242 100644 --- a/packages/flutter/lib/src/material/flexible_space_bar.dart +++ b/packages/flutter/lib/src/material/flexible_space_bar.dart @@ -82,9 +82,7 @@ class FlexibleSpaceBar extends StatefulWidget { this.titlePadding, this.collapseMode = CollapseMode.parallax, this.stretchModes = const [StretchMode.zoomBackground], - this.expandedTitleScale = 1.5, }) : assert(collapseMode != null), - assert(expandedTitleScale >= 1), super(key: key); /// The primary contents of the flexible space bar when expanded. @@ -125,14 +123,6 @@ class FlexibleSpaceBar extends StatefulWidget { /// not centered, `EdgeInsetsDirectional.only(start: 0, bottom: 16)` otherwise. final EdgeInsetsGeometry? titlePadding; - /// Defines how much the title is scaled when the FlexibleSpaceBar is expanded - /// due to the user scrolling downwards. The title is scaled uniformly on the - /// x and y axes while maintaining its bottom-left position (bottom-center if - /// [centerTitle] is true). - /// - /// Defaults to 1.5 and must be greater than 1. - final double expandedTitleScale; - /// Wraps a widget that contains an [AppBar] to convey sizing information down /// to the [FlexibleSpaceBar]. /// @@ -327,7 +317,7 @@ class _FlexibleSpaceBarState extends State { start: effectiveCenterTitle ? 0.0 : 72.0, bottom: 16.0, ); - final double scaleValue = Tween(begin: widget.expandedTitleScale, end: 1.0).transform(t); + final double scaleValue = Tween(begin: 1.5, end: 1.0).transform(t); final Matrix4 scaleTransform = Matrix4.identity() ..scale(scaleValue, scaleValue, 1.0); final Alignment titleAlignment = _getTitleAlignment(effectiveCenterTitle); diff --git a/packages/flutter/lib/src/material/floating_action_button.dart b/packages/flutter/lib/src/material/floating_action_button.dart index fcb6c32e35f02..0b7fefddf11c4 100644 --- a/packages/flutter/lib/src/material/floating_action_button.dart +++ b/packages/flutter/lib/src/material/floating_action_button.dart @@ -9,14 +9,31 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'button.dart'; -import 'color_scheme.dart'; import 'floating_action_button_theme.dart'; import 'scaffold.dart'; -import 'text_theme.dart'; import 'theme.dart'; import 'theme_data.dart'; import 'tooltip.dart'; +const BoxConstraints _kSizeConstraints = BoxConstraints.tightFor( + width: 56.0, + height: 56.0, +); + +const BoxConstraints _kMiniSizeConstraints = BoxConstraints.tightFor( + width: 40.0, + height: 40.0, +); + +const BoxConstraints _kLargeSizeConstraints = BoxConstraints.tightFor( + width: 96.0, + height: 96.0, +); + +const BoxConstraints _kExtendedSizeConstraints = BoxConstraints.tightFor( + height: 48.0, +); + class _DefaultHeroTag { const _DefaultHeroTag(); @override @@ -491,80 +508,82 @@ class FloatingActionButton extends StatelessWidget { final Widget? _extendedLabel; + static const double _defaultElevation = 6; + static const double _defaultFocusElevation = 6; + static const double _defaultHoverElevation = 8; + static const double _defaultHighlightElevation = 12; + static const ShapeBorder _defaultShape = CircleBorder(); + static const ShapeBorder _defaultExtendedShape = StadiumBorder(); + @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); final FloatingActionButtonThemeData floatingActionButtonTheme = theme.floatingActionButtonTheme; - final FloatingActionButtonThemeData defaults = theme.useMaterial3 - ? _M3Defaults(context, _floatingActionButtonType, child != null) - : _M2Defaults(context, _floatingActionButtonType, child != null); final Color foregroundColor = this.foregroundColor ?? floatingActionButtonTheme.foregroundColor - ?? defaults.foregroundColor!; + ?? theme.colorScheme.onSecondary; final Color backgroundColor = this.backgroundColor ?? floatingActionButtonTheme.backgroundColor - ?? defaults.backgroundColor!; + ?? theme.colorScheme.secondary; final Color focusColor = this.focusColor ?? floatingActionButtonTheme.focusColor - ?? defaults.focusColor!; + ?? theme.focusColor; final Color hoverColor = this.hoverColor ?? floatingActionButtonTheme.hoverColor - ?? defaults.hoverColor!; + ?? theme.hoverColor; final Color splashColor = this.splashColor ?? floatingActionButtonTheme.splashColor - ?? defaults.splashColor!; + ?? theme.splashColor; final double elevation = this.elevation ?? floatingActionButtonTheme.elevation - ?? defaults.elevation!; + ?? _defaultElevation; final double focusElevation = this.focusElevation ?? floatingActionButtonTheme.focusElevation - ?? defaults.focusElevation!; + ?? _defaultFocusElevation; final double hoverElevation = this.hoverElevation ?? floatingActionButtonTheme.hoverElevation - ?? defaults.hoverElevation!; + ?? _defaultHoverElevation; final double disabledElevation = this.disabledElevation ?? floatingActionButtonTheme.disabledElevation - ?? defaults.disabledElevation ?? elevation; final double highlightElevation = this.highlightElevation ?? floatingActionButtonTheme.highlightElevation - ?? defaults.highlightElevation!; + ?? _defaultHighlightElevation; final MaterialTapTargetSize materialTapTargetSize = this.materialTapTargetSize ?? theme.materialTapTargetSize; final bool enableFeedback = this.enableFeedback - ?? floatingActionButtonTheme.enableFeedback - ?? defaults.enableFeedback!; - final double iconSize = floatingActionButtonTheme.iconSize - ?? defaults.iconSize!; + ?? floatingActionButtonTheme.enableFeedback ?? true; final TextStyle extendedTextStyle = (this.extendedTextStyle - ?? floatingActionButtonTheme.extendedTextStyle - ?? defaults.extendedTextStyle!).copyWith(color: foregroundColor); + ?? floatingActionButtonTheme.extendedTextStyle + ?? theme.textTheme.button!.copyWith(letterSpacing: 1.2)).copyWith(color: foregroundColor); final ShapeBorder shape = this.shape ?? floatingActionButtonTheme.shape - ?? defaults.shape!; + ?? (isExtended ? _defaultExtendedShape : _defaultShape); BoxConstraints sizeConstraints; - Widget? resolvedChild = child != null ? IconTheme.merge( - data: IconThemeData(size: iconSize), - child: child!, - ) : child; + Widget? resolvedChild = child; switch(_floatingActionButtonType) { case _FloatingActionButtonType.regular: - sizeConstraints = floatingActionButtonTheme.sizeConstraints ?? defaults.sizeConstraints!; + sizeConstraints = floatingActionButtonTheme.sizeConstraints ?? _kSizeConstraints; break; case _FloatingActionButtonType.small: - sizeConstraints = floatingActionButtonTheme.smallSizeConstraints ?? defaults.smallSizeConstraints!; + sizeConstraints = floatingActionButtonTheme.smallSizeConstraints ?? _kMiniSizeConstraints; break; case _FloatingActionButtonType.large: - sizeConstraints = floatingActionButtonTheme.largeSizeConstraints ?? defaults.largeSizeConstraints!; + sizeConstraints = floatingActionButtonTheme.largeSizeConstraints ?? _kLargeSizeConstraints; + // The large FAB uses a larger icon. + resolvedChild = child != null ? IconTheme.merge( + data: const IconThemeData(size: 36.0), + child: child!, + ) : child; break; case _FloatingActionButtonType.extended: - sizeConstraints = floatingActionButtonTheme.extendedSizeConstraints ?? defaults.extendedSizeConstraints!; + sizeConstraints = floatingActionButtonTheme.extendedSizeConstraints ?? _kExtendedSizeConstraints; final double iconLabelSpacing = extendedIconLabelSpacing ?? floatingActionButtonTheme.extendedIconLabelSpacing ?? 8.0; final EdgeInsetsGeometry padding = extendedPadding ?? floatingActionButtonTheme.extendedPadding - ?? defaults.extendedPadding!; + ?? EdgeInsetsDirectional.only(start: child != null && isExtended ? 16.0 : 20.0, end: 20.0); resolvedChild = _ChildOverflowBox( child: Padding( padding: padding, @@ -711,148 +730,3 @@ class _RenderChildOverflowBox extends RenderAligningShiftedBox { } } } - -// Generate a FloatingActionButtonThemeData that represents -// the M2 default values. This was generated by hand from the -// previous hand coded defaults for M2. It uses get method overrides -// instead of properties to avoid computing values that we may not -// need upfront. -class _M2Defaults extends FloatingActionButtonThemeData { - _M2Defaults(BuildContext context, this.type, this.hasChild) - : _theme = Theme.of(context), - _colors = Theme.of(context).colorScheme; - - final _FloatingActionButtonType type; - final bool hasChild; - final ThemeData _theme; - final ColorScheme _colors; - - bool get _isExtended => type == _FloatingActionButtonType.extended; - bool get _isLarge => type == _FloatingActionButtonType.large; - - @override Color? get foregroundColor => _colors.onSecondary; - @override Color? get backgroundColor => _colors.secondary; - @override Color? get focusColor => _theme.focusColor; - @override Color? get hoverColor => _theme.hoverColor; - @override Color? get splashColor => _theme.splashColor; - @override double? get elevation => 6; - @override double? get focusElevation => 6; - @override double? get hoverElevation => 8; - @override double? get highlightElevation => 12; - @override ShapeBorder? get shape => _isExtended ? const StadiumBorder() : const CircleBorder(); - @override bool? get enableFeedback => true; - @override double? get iconSize => _isLarge ? 36.0 : 24.0; - - @override - BoxConstraints? get sizeConstraints => const BoxConstraints.tightFor( - width: 56.0, - height: 56.0, - ); - - @override - BoxConstraints? get smallSizeConstraints => const BoxConstraints.tightFor( - width: 40.0, - height: 40.0, - ); - - @override - BoxConstraints? get largeSizeConstraints => const BoxConstraints.tightFor( - width: 96.0, - height: 96.0, - ); - - @override - BoxConstraints? get extendedSizeConstraints => const BoxConstraints.tightFor( - height: 48.0, - ); - - @override double? get extendedIconLabelSpacing => 8.0; - @override EdgeInsetsGeometry? get extendedPadding => EdgeInsetsDirectional.only(start: hasChild && _isExtended ? 16.0 : 20.0, end: 20.0); - @override TextStyle? get extendedTextStyle => _theme.textTheme.button!.copyWith(letterSpacing: 1.2); -} - -// BEGIN GENERATED TOKEN PROPERTIES - -// Generated code to the end of this file. Do not edit by hand. -// These defaults are generated from the Material Design Token -// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart. - -// Generated version v0.74, 2022-01-06 -class _M3Defaults extends FloatingActionButtonThemeData { - _M3Defaults(this.context, this.type, this.hasChild) - : _colors = Theme.of(context).colorScheme, - _textTheme = Theme.of(context).textTheme; - - final BuildContext context; - final _FloatingActionButtonType type; - final bool hasChild; - final ColorScheme _colors; - final TextTheme _textTheme; - - bool get _isExtended => type == _FloatingActionButtonType.extended; - - @override Color? get foregroundColor => _colors.onPrimaryContainer; - @override Color? get backgroundColor => _colors.primaryContainer; - @override Color? get splashColor => _colors.onPrimaryContainer.withOpacity(0.12); - @override double get elevation => 6.0; - @override Color? get focusColor => _colors.onPrimaryContainer.withOpacity(0.12); - @override double get focusElevation => 6.0; - @override Color? get hoverColor => _colors.onPrimaryContainer.withOpacity(0.08); - @override double get hoverElevation => 8.0; - @override double get highlightElevation => 6.0; - - @override - ShapeBorder? get shape { - switch (type) { - case _FloatingActionButtonType.regular: - return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); - case _FloatingActionButtonType.small: - return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12.0))); - case _FloatingActionButtonType.large: - return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0))); - case _FloatingActionButtonType.extended: - return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); - } - } - - @override bool? get enableFeedback => true; - - @override - double? get iconSize { - switch (type) { - case _FloatingActionButtonType.regular: return 24.0; - case _FloatingActionButtonType.small: return 24.0; - case _FloatingActionButtonType.large: return 36.0; - case _FloatingActionButtonType.extended: return 24.0; - } - } - - @override - BoxConstraints? get sizeConstraints => const BoxConstraints.tightFor( - width: 56.0, - height: 56.0, - ); - - @override - BoxConstraints? get smallSizeConstraints => const BoxConstraints.tightFor( - width: 40.0, - height: 40.0, - ); - - @override - BoxConstraints? get largeSizeConstraints => const BoxConstraints.tightFor( - width: 96.0, - height: 96.0, - ); - - @override - BoxConstraints? get extendedSizeConstraints => const BoxConstraints.tightFor( - height: 56.0, - ); - - @override double? get extendedIconLabelSpacing => 8.0; - @override EdgeInsetsGeometry? get extendedPadding => EdgeInsetsDirectional.only(start: hasChild && _isExtended ? 16.0 : 20.0, end: 20.0); - @override TextStyle? get extendedTextStyle => _textTheme.labelLarge; -} - -// END GENERATED TOKEN PROPERTIES diff --git a/packages/flutter/lib/src/material/floating_action_button_theme.dart b/packages/flutter/lib/src/material/floating_action_button_theme.dart index 81337cf0b9ec5..61e63382e063c 100644 --- a/packages/flutter/lib/src/material/floating_action_button_theme.dart +++ b/packages/flutter/lib/src/material/floating_action_button_theme.dart @@ -43,7 +43,6 @@ class FloatingActionButtonThemeData with Diagnosticable { this.highlightElevation, this.shape, this.enableFeedback, - this.iconSize, this.sizeConstraints, this.smallSizeConstraints, this.largeSizeConstraints, @@ -104,9 +103,6 @@ class FloatingActionButtonThemeData with Diagnosticable { /// ignored. final bool? enableFeedback; - /// Overrides the default icon size for the [FloatingActionButton]; - final double? iconSize; - /// Overrides the default size constraints for the [FloatingActionButton]. final BoxConstraints? sizeConstraints; @@ -144,7 +140,6 @@ class FloatingActionButtonThemeData with Diagnosticable { double? highlightElevation, ShapeBorder? shape, bool? enableFeedback, - double? iconSize, BoxConstraints? sizeConstraints, BoxConstraints? smallSizeConstraints, BoxConstraints? largeSizeConstraints, @@ -166,7 +161,6 @@ class FloatingActionButtonThemeData with Diagnosticable { highlightElevation: highlightElevation ?? this.highlightElevation, shape: shape ?? this.shape, enableFeedback: enableFeedback ?? this.enableFeedback, - iconSize: iconSize ?? this.iconSize, sizeConstraints: sizeConstraints ?? this.sizeConstraints, smallSizeConstraints: smallSizeConstraints ?? this.smallSizeConstraints, largeSizeConstraints: largeSizeConstraints ?? this.largeSizeConstraints, @@ -199,7 +193,6 @@ class FloatingActionButtonThemeData with Diagnosticable { highlightElevation: lerpDouble(a?.highlightElevation, b?.highlightElevation, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t), enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback, - iconSize: lerpDouble(a?.iconSize, b?.iconSize, t), sizeConstraints: BoxConstraints.lerp(a?.sizeConstraints, b?.sizeConstraints, t), smallSizeConstraints: BoxConstraints.lerp(a?.smallSizeConstraints, b?.smallSizeConstraints, t), largeSizeConstraints: BoxConstraints.lerp(a?.largeSizeConstraints, b?.largeSizeConstraints, t), @@ -225,7 +218,6 @@ class FloatingActionButtonThemeData with Diagnosticable { highlightElevation, shape, enableFeedback, - iconSize, sizeConstraints, smallSizeConstraints, largeSizeConstraints, @@ -255,7 +247,6 @@ class FloatingActionButtonThemeData with Diagnosticable { && other.highlightElevation == highlightElevation && other.shape == shape && other.enableFeedback == enableFeedback - && other.iconSize == iconSize && other.sizeConstraints == sizeConstraints && other.smallSizeConstraints == smallSizeConstraints && other.largeSizeConstraints == largeSizeConstraints @@ -281,7 +272,6 @@ class FloatingActionButtonThemeData with Diagnosticable { properties.add(DoubleProperty('highlightElevation', highlightElevation, defaultValue: null)); properties.add(DiagnosticsProperty('shape', shape, defaultValue: null)); properties.add(DiagnosticsProperty('enableFeedback', enableFeedback, defaultValue: null)); - properties.add(DoubleProperty('iconSize', iconSize, defaultValue: null)); properties.add(DiagnosticsProperty('sizeConstraints', sizeConstraints, defaultValue: null)); properties.add(DiagnosticsProperty('smallSizeConstraints', smallSizeConstraints, defaultValue: null)); properties.add(DiagnosticsProperty('largeSizeConstraints', largeSizeConstraints, defaultValue: null)); diff --git a/packages/flutter/lib/src/material/icon_button.dart b/packages/flutter/lib/src/material/icon_button.dart index 1d15f1caff48e..ce90231083d7c 100644 --- a/packages/flutter/lib/src/material/icon_button.dart +++ b/packages/flutter/lib/src/material/icon_button.dart @@ -116,7 +116,7 @@ class IconButton extends StatelessWidget { /// or an [ImageIcon]. const IconButton({ Key? key, - this.iconSize, + this.iconSize = 24.0, this.visualDensity, this.padding = const EdgeInsets.all(8.0), this.alignment = Alignment.center, @@ -135,7 +135,8 @@ class IconButton extends StatelessWidget { this.enableFeedback = true, this.constraints, required this.icon, - }) : assert(padding != null), + }) : assert(iconSize != null), + assert(padding != null), assert(alignment != null), assert(splashRadius == null || splashRadius > 0), assert(autofocus != null), @@ -144,8 +145,7 @@ class IconButton extends StatelessWidget { /// The size of the icon inside the button. /// - /// If null, uses [IconThemeData.size]. If it is also null, the default size - /// is 24.0. + /// This property must not be null. It defaults to 24.0. /// /// The size given here is passed down to the widget in the [icon] property /// via an [IconTheme]. Setting the size here instead of in, for example, the @@ -153,7 +153,7 @@ class IconButton extends StatelessWidget { /// fit the [Icon]. If you were to set the size of the [Icon] using /// [Icon.size] instead, then the [IconButton] would default to 24.0 and then /// the [Icon] itself would likely get clipped. - final double? iconSize; + final double iconSize; /// Defines how compact the icon button's layout will be. /// @@ -256,7 +256,7 @@ class IconButton extends StatelessWidget { /// {@macro flutter.material.RawMaterialButton.mouseCursor} /// /// If set to null, will default to - /// - [SystemMouseCursors.basic], if [onPressed] is null + /// - [SystemMouseCursors.forbidden], if [onPressed] is null /// - [SystemMouseCursors.click], otherwise final MouseCursor? mouseCursor; @@ -319,20 +319,19 @@ class IconButton extends StatelessWidget { minHeight: _kMinButtonSize, ); final BoxConstraints adjustedConstraints = effectiveVisualDensity.effectiveConstraints(unadjustedConstraints); - final double effectiveIconSize = iconSize ?? IconTheme.of(context).size ?? 24.0; Widget result = ConstrainedBox( constraints: adjustedConstraints, child: Padding( padding: padding, child: SizedBox( - height: effectiveIconSize, - width: effectiveIconSize, + height: iconSize, + width: iconSize, child: Align( alignment: alignment, child: IconTheme.merge( data: IconThemeData( - size: effectiveIconSize, + size: iconSize, color: currentColor, ), child: icon, @@ -357,7 +356,7 @@ class IconButton extends StatelessWidget { autofocus: autofocus, canRequestFocus: onPressed != null, onTap: onPressed, - mouseCursor: mouseCursor ?? (onPressed == null ? SystemMouseCursors.basic : SystemMouseCursors.click), + mouseCursor: mouseCursor ?? (onPressed == null ? SystemMouseCursors.forbidden : SystemMouseCursors.click), enableFeedback: enableFeedback, focusColor: focusColor ?? theme.focusColor, hoverColor: hoverColor ?? theme.hoverColor, @@ -365,7 +364,7 @@ class IconButton extends StatelessWidget { splashColor: splashColor ?? theme.splashColor, radius: splashRadius ?? math.max( Material.defaultSplashRadius, - (effectiveIconSize + math.min(padding.horizontal, padding.vertical)) * 0.7, + (iconSize + math.min(padding.horizontal, padding.vertical)) * 0.7, // x 0.5 for diameter -> radius and + 40% overflow derived from other Material apps. ), child: result, diff --git a/packages/flutter/lib/src/material/icons.dart b/packages/flutter/lib/src/material/icons.dart index ddb13bfea9666..7d8b69abf0c0a 100644 --- a/packages/flutter/lib/src/material/icons.dart +++ b/packages/flutter/lib/src/material/icons.dart @@ -97,7 +97,8 @@ class PlatformAdaptiveIcons implements Icons { /// /// Use with the [Icon] class to show specific icons. /// -/// Icons are identified by their name as listed below, e.g. [Icons.airplanemode_on]. +/// Icons are identified by their name as listed below. **Do not use codepoints +/// directly, as they are subject to change.** /// /// To use this class, make sure you set `uses-material-design: true` in your /// project's `pubspec.yaml` file in the `flutter` section. This ensures that @@ -115,7 +116,7 @@ class PlatformAdaptiveIcons implements Icons { /// sizes. The first [Icon] uses a [Icon.semanticLabel] to announce in accessibility /// modes like TalkBack and VoiceOver. /// -/// ![The following code snippet would generate a row of icons consisting of a pink heart, a green musical note, and a blue umbrella, each progressively bigger than the last.](https://flutter.github.io/assets-for-api-docs/assets/widgets/icon.png) +/// ![A row of icons representing a pink heart, a green musical note, and a blue umbrella](https://flutter.github.io/assets-for-api-docs/assets/widgets/icon.png) /// /// ```dart /// Row( @@ -218,18 +219,6 @@ class Icons { /// 11mp — material icon named "11mp" (outlined). static const IconData eleven_mp_outlined = IconData(0xedf4, fontFamily: 'MaterialIcons'); - /// 123 — material icon named "123". - static const IconData onetwothree = IconData(0xf04b5, fontFamily: 'MaterialIcons'); - - /// 123 — material icon named "123" (sharp). - static const IconData onetwothree_sharp = IconData(0xf03c2, fontFamily: 'MaterialIcons'); - - /// 123 — material icon named "123" (round). - static const IconData onetwothree_rounded = IconData(0xe340, fontFamily: 'MaterialIcons'); - - /// 123 — material icon named "123" (outlined). - static const IconData onetwothree_outlined = IconData(0xf05b0, fontFamily: 'MaterialIcons'); - /// 12mp — material icon named "12mp". static const IconData twelve_mp = IconData(0xe003, fontFamily: 'MaterialIcons'); @@ -854,18 +843,6 @@ class Icons { /// 9mp — material icon named "9mp" (outlined). static const IconData nine_mp_outlined = IconData(0xee28, fontFamily: 'MaterialIcons'); - /// abc — material icon named "abc". - static const IconData abc = IconData(0xf04b6, fontFamily: 'MaterialIcons'); - - /// abc — material icon named "abc" (sharp). - static const IconData abc_sharp = IconData(0xf03c3, fontFamily: 'MaterialIcons'); - - /// abc — material icon named "abc" (round). - static const IconData abc_rounded = IconData(0xe4c4, fontFamily: 'MaterialIcons'); - - /// abc — material icon named "abc" (outlined). - static const IconData abc_outlined = IconData(0xf05b1, fontFamily: 'MaterialIcons'); - /// ac_unit — material icon named "ac unit". static const IconData ac_unit = IconData(0xe037, fontFamily: 'MaterialIcons'); @@ -1133,18 +1110,6 @@ class Icons { /// add_call — material icon named "add call". static const IconData add_call = IconData(0xe04d, fontFamily: 'MaterialIcons'); - /// add_card — material icon named "add card". - static const IconData add_card = IconData(0xf04b7, fontFamily: 'MaterialIcons'); - - /// add_card — material icon named "add card" (sharp). - static const IconData add_card_sharp = IconData(0xf03c4, fontFamily: 'MaterialIcons'); - - /// add_card — material icon named "add card" (round). - static const IconData add_card_rounded = IconData(0xf02d1, fontFamily: 'MaterialIcons'); - - /// add_card — material icon named "add card" (outlined). - static const IconData add_card_outlined = IconData(0xf05b2, fontFamily: 'MaterialIcons'); - /// add_chart — material icon named "add chart". static const IconData add_chart = IconData(0xe04e, fontFamily: 'MaterialIcons'); @@ -1373,18 +1338,6 @@ class Icons { /// addchart — material icon named "addchart" (outlined). static const IconData addchart_outlined = IconData(0xee51, fontFamily: 'MaterialIcons'); - /// adf_scanner — material icon named "adf scanner". - static const IconData adf_scanner = IconData(0xf04b8, fontFamily: 'MaterialIcons'); - - /// adf_scanner — material icon named "adf scanner" (sharp). - static const IconData adf_scanner_sharp = IconData(0xf03c5, fontFamily: 'MaterialIcons'); - - /// adf_scanner — material icon named "adf scanner" (round). - static const IconData adf_scanner_rounded = IconData(0xf02d2, fontFamily: 'MaterialIcons'); - - /// adf_scanner — material icon named "adf scanner" (outlined). - static const IconData adf_scanner_outlined = IconData(0xf05b3, fontFamily: 'MaterialIcons'); - /// adjust — material icon named "adjust". static const IconData adjust = IconData(0xe061, fontFamily: 'MaterialIcons'); @@ -1409,30 +1362,6 @@ class Icons { /// admin_panel_settings — material icon named "admin panel settings" (outlined). static const IconData admin_panel_settings_outlined = IconData(0xee53, fontFamily: 'MaterialIcons'); - /// adobe — material icon named "adobe". - static const IconData adobe = IconData(0xf04b9, fontFamily: 'MaterialIcons'); - - /// adobe — material icon named "adobe" (sharp). - static const IconData adobe_sharp = IconData(0xf03c6, fontFamily: 'MaterialIcons'); - - /// adobe — material icon named "adobe" (round). - static const IconData adobe_rounded = IconData(0xf02d3, fontFamily: 'MaterialIcons'); - - /// adobe — material icon named "adobe" (outlined). - static const IconData adobe_outlined = IconData(0xf05b4, fontFamily: 'MaterialIcons'); - - /// ads_click — material icon named "ads click". - static const IconData ads_click = IconData(0xf04ba, fontFamily: 'MaterialIcons'); - - /// ads_click — material icon named "ads click" (sharp). - static const IconData ads_click_sharp = IconData(0xf03c7, fontFamily: 'MaterialIcons'); - - /// ads_click — material icon named "ads click" (round). - static const IconData ads_click_rounded = IconData(0xf02d4, fontFamily: 'MaterialIcons'); - - /// ads_click — material icon named "ads click" (outlined). - static const IconData ads_click_outlined = IconData(0xf05b5, fontFamily: 'MaterialIcons'); - /// agriculture — material icon named "agriculture". static const IconData agriculture = IconData(0xe063, fontFamily: 'MaterialIcons'); @@ -1553,30 +1482,6 @@ class Icons { /// airline_seat_recline_normal — material icon named "airline seat recline normal" (outlined). static const IconData airline_seat_recline_normal_outlined = IconData(0xee5d, fontFamily: 'MaterialIcons'); - /// airline_stops — material icon named "airline stops". - static const IconData airline_stops = IconData(0xf04bb, fontFamily: 'MaterialIcons'); - - /// airline_stops — material icon named "airline stops" (sharp). - static const IconData airline_stops_sharp = IconData(0xf03c8, fontFamily: 'MaterialIcons'); - - /// airline_stops — material icon named "airline stops" (round). - static const IconData airline_stops_rounded = IconData(0xf02d5, fontFamily: 'MaterialIcons'); - - /// airline_stops — material icon named "airline stops" (outlined). - static const IconData airline_stops_outlined = IconData(0xf05b6, fontFamily: 'MaterialIcons'); - - /// airlines — material icon named "airlines". - static const IconData airlines = IconData(0xf04bc, fontFamily: 'MaterialIcons'); - - /// airlines — material icon named "airlines" (sharp). - static const IconData airlines_sharp = IconData(0xf03c9, fontFamily: 'MaterialIcons'); - - /// airlines — material icon named "airlines" (round). - static const IconData airlines_rounded = IconData(0xf02d6, fontFamily: 'MaterialIcons'); - - /// airlines — material icon named "airlines" (outlined). - static const IconData airlines_outlined = IconData(0xf05b7, fontFamily: 'MaterialIcons'); - /// airplane_ticket — material icon named "airplane ticket". static const IconData airplane_ticket = IconData(0xe06d, fontFamily: 'MaterialIcons'); @@ -1997,30 +1902,6 @@ class Icons { /// app_settings_alt — material icon named "app settings alt" (outlined). static const IconData app_settings_alt_outlined = IconData(0xee7e, fontFamily: 'MaterialIcons'); - /// app_shortcut — material icon named "app shortcut". - static const IconData app_shortcut = IconData(0xf04bd, fontFamily: 'MaterialIcons'); - - /// app_shortcut — material icon named "app shortcut" (sharp). - static const IconData app_shortcut_sharp = IconData(0xf03ca, fontFamily: 'MaterialIcons'); - - /// app_shortcut — material icon named "app shortcut" (round). - static const IconData app_shortcut_rounded = IconData(0xf02d7, fontFamily: 'MaterialIcons'); - - /// app_shortcut — material icon named "app shortcut" (outlined). - static const IconData app_shortcut_outlined = IconData(0xf05b8, fontFamily: 'MaterialIcons'); - - /// apple — material icon named "apple". - static const IconData apple = IconData(0xf04be, fontFamily: 'MaterialIcons'); - - /// apple — material icon named "apple" (sharp). - static const IconData apple_sharp = IconData(0xf03cb, fontFamily: 'MaterialIcons'); - - /// apple — material icon named "apple" (round). - static const IconData apple_rounded = IconData(0xf02d8, fontFamily: 'MaterialIcons'); - - /// apple — material icon named "apple" (outlined). - static const IconData apple_outlined = IconData(0xf05b9, fontFamily: 'MaterialIcons'); - /// approval — material icon named "approval". static const IconData approval = IconData(0xe08e, fontFamily: 'MaterialIcons'); @@ -2045,18 +1926,6 @@ class Icons { /// apps — material icon named "apps" (outlined). static const IconData apps_outlined = IconData(0xee80, fontFamily: 'MaterialIcons'); - /// apps_outage — material icon named "apps outage". - static const IconData apps_outage = IconData(0xf04bf, fontFamily: 'MaterialIcons'); - - /// apps_outage — material icon named "apps outage" (sharp). - static const IconData apps_outage_sharp = IconData(0xf03cc, fontFamily: 'MaterialIcons'); - - /// apps_outage — material icon named "apps outage" (round). - static const IconData apps_outage_rounded = IconData(0xf02d9, fontFamily: 'MaterialIcons'); - - /// apps_outage — material icon named "apps outage" (outlined). - static const IconData apps_outage_outlined = IconData(0xf05ba, fontFamily: 'MaterialIcons'); - /// architecture — material icon named "architecture". static const IconData architecture = IconData(0xe090, fontFamily: 'MaterialIcons'); @@ -2081,18 +1950,6 @@ class Icons { /// archive — material icon named "archive" (outlined). static const IconData archive_outlined = IconData(0xee82, fontFamily: 'MaterialIcons'); - /// area_chart — material icon named "area chart". - static const IconData area_chart = IconData(0xf04c0, fontFamily: 'MaterialIcons'); - - /// area_chart — material icon named "area chart" (sharp). - static const IconData area_chart_sharp = IconData(0xf03cd, fontFamily: 'MaterialIcons'); - - /// area_chart — material icon named "area chart" (round). - static const IconData area_chart_rounded = IconData(0xf02da, fontFamily: 'MaterialIcons'); - - /// area_chart — material icon named "area chart" (outlined). - static const IconData area_chart_outlined = IconData(0xf05bb, fontFamily: 'MaterialIcons'); - /// arrow_back — material icon named "arrow back". static const IconData arrow_back = IconData(0xe092, fontFamily: 'MaterialIcons', matchTextDirection: true); @@ -2141,30 +1998,6 @@ class Icons { /// arrow_circle_down — material icon named "arrow circle down" (outlined). static const IconData arrow_circle_down_outlined = IconData(0xee86, fontFamily: 'MaterialIcons'); - /// arrow_circle_left — material icon named "arrow circle left". - static const IconData arrow_circle_left = IconData(0xf04c1, fontFamily: 'MaterialIcons'); - - /// arrow_circle_left — material icon named "arrow circle left" (sharp). - static const IconData arrow_circle_left_sharp = IconData(0xf03ce, fontFamily: 'MaterialIcons'); - - /// arrow_circle_left — material icon named "arrow circle left" (round). - static const IconData arrow_circle_left_rounded = IconData(0xf02db, fontFamily: 'MaterialIcons'); - - /// arrow_circle_left — material icon named "arrow circle left" (outlined). - static const IconData arrow_circle_left_outlined = IconData(0xf05bc, fontFamily: 'MaterialIcons'); - - /// arrow_circle_right — material icon named "arrow circle right". - static const IconData arrow_circle_right = IconData(0xf04c2, fontFamily: 'MaterialIcons'); - - /// arrow_circle_right — material icon named "arrow circle right" (sharp). - static const IconData arrow_circle_right_sharp = IconData(0xf03cf, fontFamily: 'MaterialIcons'); - - /// arrow_circle_right — material icon named "arrow circle right" (round). - static const IconData arrow_circle_right_rounded = IconData(0xf02dc, fontFamily: 'MaterialIcons'); - - /// arrow_circle_right — material icon named "arrow circle right" (outlined). - static const IconData arrow_circle_right_outlined = IconData(0xf05bd, fontFamily: 'MaterialIcons'); - /// arrow_circle_up — material icon named "arrow circle up". static const IconData arrow_circle_up = IconData(0xe096, fontFamily: 'MaterialIcons'); @@ -2456,18 +2289,6 @@ class Icons { /// assistant_photo — material icon named "assistant photo" (outlined). static const IconData assistant_photo_outlined = IconData(0xee9e, fontFamily: 'MaterialIcons'); - /// assured_workload — material icon named "assured workload". - static const IconData assured_workload = IconData(0xf04c3, fontFamily: 'MaterialIcons'); - - /// assured_workload — material icon named "assured workload" (sharp). - static const IconData assured_workload_sharp = IconData(0xf03d0, fontFamily: 'MaterialIcons'); - - /// assured_workload — material icon named "assured workload" (round). - static const IconData assured_workload_rounded = IconData(0xf02dd, fontFamily: 'MaterialIcons'); - - /// assured_workload — material icon named "assured workload" (outlined). - static const IconData assured_workload_outlined = IconData(0xf05be, fontFamily: 'MaterialIcons'); - /// atm — material icon named "atm". static const IconData atm = IconData(0xe0af, fontFamily: 'MaterialIcons'); @@ -2552,18 +2373,6 @@ class Icons { /// attribution — material icon named "attribution" (outlined). static const IconData attribution_outlined = IconData(0xeea5, fontFamily: 'MaterialIcons'); - /// audio_file — material icon named "audio file". - static const IconData audio_file = IconData(0xf04c4, fontFamily: 'MaterialIcons'); - - /// audio_file — material icon named "audio file" (sharp). - static const IconData audio_file_sharp = IconData(0xf03d1, fontFamily: 'MaterialIcons'); - - /// audio_file — material icon named "audio file" (round). - static const IconData audio_file_rounded = IconData(0xf02de, fontFamily: 'MaterialIcons'); - - /// audio_file — material icon named "audio file" (outlined). - static const IconData audio_file_outlined = IconData(0xf05bf, fontFamily: 'MaterialIcons'); - /// audiotrack — material icon named "audiotrack". static const IconData audiotrack = IconData(0xe0b6, fontFamily: 'MaterialIcons'); @@ -2732,18 +2541,6 @@ class Icons { /// baby_changing_station — material icon named "baby changing station" (outlined). static const IconData baby_changing_station_outlined = IconData(0xeeb3, fontFamily: 'MaterialIcons'); - /// back_hand — material icon named "back hand". - static const IconData back_hand = IconData(0xf04c5, fontFamily: 'MaterialIcons'); - - /// back_hand — material icon named "back hand" (sharp). - static const IconData back_hand_sharp = IconData(0xf03d2, fontFamily: 'MaterialIcons'); - - /// back_hand — material icon named "back hand" (round). - static const IconData back_hand_rounded = IconData(0xf02df, fontFamily: 'MaterialIcons'); - - /// back_hand — material icon named "back hand" (outlined). - static const IconData back_hand_outlined = IconData(0xf05c0, fontFamily: 'MaterialIcons'); - /// backpack — material icon named "backpack". static const IconData backpack = IconData(0xe0c4, fontFamily: 'MaterialIcons'); @@ -2816,18 +2613,6 @@ class Icons { /// bakery_dining — material icon named "bakery dining" (outlined). static const IconData bakery_dining_outlined = IconData(0xeeb9, fontFamily: 'MaterialIcons'); - /// balance — material icon named "balance". - static const IconData balance = IconData(0xf04c6, fontFamily: 'MaterialIcons'); - - /// balance — material icon named "balance" (sharp). - static const IconData balance_sharp = IconData(0xf03d3, fontFamily: 'MaterialIcons'); - - /// balance — material icon named "balance" (round). - static const IconData balance_rounded = IconData(0xf02e0, fontFamily: 'MaterialIcons'); - - /// balance — material icon named "balance" (outlined). - static const IconData balance_outlined = IconData(0xf05c1, fontFamily: 'MaterialIcons'); - /// balcony — material icon named "balcony". static const IconData balcony = IconData(0xe0ca, fontFamily: 'MaterialIcons'); @@ -3044,18 +2829,6 @@ class Icons { /// bedtime — material icon named "bedtime" (outlined). static const IconData bedtime_outlined = IconData(0xeecb, fontFamily: 'MaterialIcons'); - /// bedtime_off — material icon named "bedtime off". - static const IconData bedtime_off = IconData(0xf04c7, fontFamily: 'MaterialIcons'); - - /// bedtime_off — material icon named "bedtime off" (sharp). - static const IconData bedtime_off_sharp = IconData(0xf03d4, fontFamily: 'MaterialIcons'); - - /// bedtime_off — material icon named "bedtime off" (round). - static const IconData bedtime_off_rounded = IconData(0xf02e1, fontFamily: 'MaterialIcons'); - - /// bedtime_off — material icon named "bedtime off" (outlined). - static const IconData bedtime_off_outlined = IconData(0xf05c2, fontFamily: 'MaterialIcons'); - /// beenhere — material icon named "beenhere". static const IconData beenhere = IconData(0xe0dc, fontFamily: 'MaterialIcons'); @@ -3527,18 +3300,6 @@ class Icons { /// border_vertical — material icon named "border vertical" (outlined). static const IconData border_vertical_outlined = IconData(0xeef1, fontFamily: 'MaterialIcons'); - /// boy — material icon named "boy". - static const IconData boy = IconData(0xf04c8, fontFamily: 'MaterialIcons'); - - /// boy — material icon named "boy" (sharp). - static const IconData boy_sharp = IconData(0xf03d5, fontFamily: 'MaterialIcons'); - - /// boy — material icon named "boy" (round). - static const IconData boy_rounded = IconData(0xf02e2, fontFamily: 'MaterialIcons'); - - /// boy — material icon named "boy" (outlined). - static const IconData boy_outlined = IconData(0xf05c3, fontFamily: 'MaterialIcons'); - /// branding_watermark — material icon named "branding watermark". static const IconData branding_watermark = IconData(0xe103, fontFamily: 'MaterialIcons'); @@ -3707,18 +3468,6 @@ class Icons { /// broken_image — material icon named "broken image" (outlined). static const IconData broken_image_outlined = IconData(0xeeff, fontFamily: 'MaterialIcons'); - /// browse_gallery — material icon named "browse gallery". - static const IconData browse_gallery = IconData(0xf06ba, fontFamily: 'MaterialIcons'); - - /// browse_gallery — material icon named "browse gallery" (sharp). - static const IconData browse_gallery_sharp = IconData(0xf06ad, fontFamily: 'MaterialIcons'); - - /// browse_gallery — material icon named "browse gallery" (round). - static const IconData browse_gallery_rounded = IconData(0xf06c7, fontFamily: 'MaterialIcons'); - - /// browse_gallery — material icon named "browse gallery" (outlined). - static const IconData browse_gallery_outlined = IconData(0xf03bc, fontFamily: 'MaterialIcons'); - /// browser_not_supported — material icon named "browser not supported". static const IconData browser_not_supported = IconData(0xe111, fontFamily: 'MaterialIcons'); @@ -3731,18 +3480,6 @@ class Icons { /// browser_not_supported — material icon named "browser not supported" (outlined). static const IconData browser_not_supported_outlined = IconData(0xef00, fontFamily: 'MaterialIcons'); - /// browser_updated — material icon named "browser updated". - static const IconData browser_updated = IconData(0xf04c9, fontFamily: 'MaterialIcons'); - - /// browser_updated — material icon named "browser updated" (sharp). - static const IconData browser_updated_sharp = IconData(0xf03d6, fontFamily: 'MaterialIcons'); - - /// browser_updated — material icon named "browser updated" (round). - static const IconData browser_updated_rounded = IconData(0xf02e3, fontFamily: 'MaterialIcons'); - - /// browser_updated — material icon named "browser updated" (outlined). - static const IconData browser_updated_outlined = IconData(0xf05c4, fontFamily: 'MaterialIcons'); - /// brunch_dining — material icon named "brunch dining". static const IconData brunch_dining = IconData(0xe112, fontFamily: 'MaterialIcons'); @@ -3935,18 +3672,6 @@ class Icons { /// calculate — material icon named "calculate" (outlined). static const IconData calculate_outlined = IconData(0xef10, fontFamily: 'MaterialIcons'); - /// calendar_month — material icon named "calendar month". - static const IconData calendar_month = IconData(0xf06bb, fontFamily: 'MaterialIcons'); - - /// calendar_month — material icon named "calendar month" (sharp). - static const IconData calendar_month_sharp = IconData(0xf06ae, fontFamily: 'MaterialIcons'); - - /// calendar_month — material icon named "calendar month" (round). - static const IconData calendar_month_rounded = IconData(0xf06c8, fontFamily: 'MaterialIcons'); - - /// calendar_month — material icon named "calendar month" (outlined). - static const IconData calendar_month_outlined = IconData(0xf051f, fontFamily: 'MaterialIcons'); - /// calendar_today — material icon named "calendar today". static const IconData calendar_today = IconData(0xe122, fontFamily: 'MaterialIcons'); @@ -4259,18 +3984,6 @@ class Icons { /// cancel_schedule_send — material icon named "cancel schedule send" (outlined). static const IconData cancel_schedule_send_outlined = IconData(0xef2a, fontFamily: 'MaterialIcons'); - /// candlestick_chart — material icon named "candlestick chart". - static const IconData candlestick_chart = IconData(0xf04ca, fontFamily: 'MaterialIcons'); - - /// candlestick_chart — material icon named "candlestick chart" (sharp). - static const IconData candlestick_chart_sharp = IconData(0xf03d7, fontFamily: 'MaterialIcons'); - - /// candlestick_chart — material icon named "candlestick chart" (round). - static const IconData candlestick_chart_rounded = IconData(0xf02e4, fontFamily: 'MaterialIcons'); - - /// candlestick_chart — material icon named "candlestick chart" (outlined). - static const IconData candlestick_chart_outlined = IconData(0xf05c5, fontFamily: 'MaterialIcons'); - /// car_rental — material icon named "car rental". static const IconData car_rental = IconData(0xe13c, fontFamily: 'MaterialIcons'); @@ -4403,18 +4116,6 @@ class Icons { /// cast_for_education — material icon named "cast for education" (outlined). static const IconData cast_for_education_outlined = IconData(0xef34, fontFamily: 'MaterialIcons'); - /// castle — material icon named "castle". - static const IconData castle = IconData(0xf04cb, fontFamily: 'MaterialIcons'); - - /// castle — material icon named "castle" (sharp). - static const IconData castle_sharp = IconData(0xf03d8, fontFamily: 'MaterialIcons'); - - /// castle — material icon named "castle" (round). - static const IconData castle_rounded = IconData(0xf02e5, fontFamily: 'MaterialIcons'); - - /// castle — material icon named "castle" (outlined). - static const IconData castle_outlined = IconData(0xf05c6, fontFamily: 'MaterialIcons'); - /// catching_pokemon — material icon named "catching pokemon". static const IconData catching_pokemon = IconData(0xe147, fontFamily: 'MaterialIcons'); @@ -4451,18 +4152,6 @@ class Icons { /// celebration — material icon named "celebration" (outlined). static const IconData celebration_outlined = IconData(0xef38, fontFamily: 'MaterialIcons'); - /// cell_tower — material icon named "cell tower". - static const IconData cell_tower = IconData(0xf04cc, fontFamily: 'MaterialIcons'); - - /// cell_tower — material icon named "cell tower" (sharp). - static const IconData cell_tower_sharp = IconData(0xf03d9, fontFamily: 'MaterialIcons'); - - /// cell_tower — material icon named "cell tower" (round). - static const IconData cell_tower_rounded = IconData(0xf02e6, fontFamily: 'MaterialIcons'); - - /// cell_tower — material icon named "cell tower" (outlined). - static const IconData cell_tower_outlined = IconData(0xf05c7, fontFamily: 'MaterialIcons'); - /// cell_wifi — material icon named "cell wifi". static const IconData cell_wifi = IconData(0xe14a, fontFamily: 'MaterialIcons'); @@ -4763,18 +4452,6 @@ class Icons { /// chrome_reader_mode — material icon named "chrome reader mode" (outlined). static const IconData chrome_reader_mode_outlined = IconData(0xef51, fontFamily: 'MaterialIcons', matchTextDirection: true); - /// church — material icon named "church". - static const IconData church = IconData(0xf04cd, fontFamily: 'MaterialIcons'); - - /// church — material icon named "church" (sharp). - static const IconData church_sharp = IconData(0xf03da, fontFamily: 'MaterialIcons'); - - /// church — material icon named "church" (round). - static const IconData church_rounded = IconData(0xf02e7, fontFamily: 'MaterialIcons'); - - /// church — material icon named "church" (outlined). - static const IconData church_outlined = IconData(0xf05c8, fontFamily: 'MaterialIcons'); - /// circle — material icon named "circle". static const IconData circle = IconData(0xe163, fontFamily: 'MaterialIcons'); @@ -4991,18 +4668,6 @@ class Icons { /// cloud_queue — material icon named "cloud queue" (outlined). static const IconData cloud_queue_outlined = IconData(0xef63, fontFamily: 'MaterialIcons'); - /// cloud_sync — material icon named "cloud sync". - static const IconData cloud_sync = IconData(0xf04ce, fontFamily: 'MaterialIcons'); - - /// cloud_sync — material icon named "cloud sync" (sharp). - static const IconData cloud_sync_sharp = IconData(0xf03db, fontFamily: 'MaterialIcons'); - - /// cloud_sync — material icon named "cloud sync" (round). - static const IconData cloud_sync_rounded = IconData(0xf02e8, fontFamily: 'MaterialIcons'); - - /// cloud_sync — material icon named "cloud sync" (outlined). - static const IconData cloud_sync_outlined = IconData(0xf05c9, fontFamily: 'MaterialIcons'); - /// cloud_upload — material icon named "cloud upload". static const IconData cloud_upload = IconData(0xe175, fontFamily: 'MaterialIcons'); @@ -5015,33 +4680,6 @@ class Icons { /// cloud_upload — material icon named "cloud upload" (outlined). static const IconData cloud_upload_outlined = IconData(0xef64, fontFamily: 'MaterialIcons'); - /// cloudy_snowing — material icon named "cloudy snowing". - static const IconData cloudy_snowing = IconData(0xf04cf, fontFamily: 'MaterialIcons'); - - /// co2 — material icon named "co2". - static const IconData co2 = IconData(0xf04d0, fontFamily: 'MaterialIcons'); - - /// co2 — material icon named "co2" (sharp). - static const IconData co2_sharp = IconData(0xf03dc, fontFamily: 'MaterialIcons'); - - /// co2 — material icon named "co2" (round). - static const IconData co2_rounded = IconData(0xf02e9, fontFamily: 'MaterialIcons'); - - /// co2 — material icon named "co2" (outlined). - static const IconData co2_outlined = IconData(0xf05ca, fontFamily: 'MaterialIcons'); - - /// co_present — material icon named "co present". - static const IconData co_present = IconData(0xf04d1, fontFamily: 'MaterialIcons'); - - /// co_present — material icon named "co present" (sharp). - static const IconData co_present_sharp = IconData(0xf03dd, fontFamily: 'MaterialIcons'); - - /// co_present — material icon named "co present" (round). - static const IconData co_present_rounded = IconData(0xf02ea, fontFamily: 'MaterialIcons'); - - /// co_present — material icon named "co present" (outlined). - static const IconData co_present_outlined = IconData(0xf05cb, fontFamily: 'MaterialIcons'); - /// code — material icon named "code". static const IconData code = IconData(0xe176, fontFamily: 'MaterialIcons'); @@ -5162,30 +4800,6 @@ class Icons { /// comment_bank — material icon named "comment bank" (outlined). static const IconData comment_bank_outlined = IconData(0xef6d, fontFamily: 'MaterialIcons'); - /// comments_disabled — material icon named "comments disabled". - static const IconData comments_disabled = IconData(0xf04d2, fontFamily: 'MaterialIcons'); - - /// comments_disabled — material icon named "comments disabled" (sharp). - static const IconData comments_disabled_sharp = IconData(0xf03de, fontFamily: 'MaterialIcons'); - - /// comments_disabled — material icon named "comments disabled" (round). - static const IconData comments_disabled_rounded = IconData(0xf02eb, fontFamily: 'MaterialIcons'); - - /// comments_disabled — material icon named "comments disabled" (outlined). - static const IconData comments_disabled_outlined = IconData(0xf05cc, fontFamily: 'MaterialIcons'); - - /// commit — material icon named "commit". - static const IconData commit = IconData(0xf04d3, fontFamily: 'MaterialIcons'); - - /// commit — material icon named "commit" (sharp). - static const IconData commit_sharp = IconData(0xf03df, fontFamily: 'MaterialIcons'); - - /// commit — material icon named "commit" (round). - static const IconData commit_rounded = IconData(0xf02ec, fontFamily: 'MaterialIcons'); - - /// commit — material icon named "commit" (outlined). - static const IconData commit_outlined = IconData(0xf05cd, fontFamily: 'MaterialIcons'); - /// commute — material icon named "commute". static const IconData commute = IconData(0xe180, fontFamily: 'MaterialIcons'); @@ -5234,18 +4848,6 @@ class Icons { /// compass_calibration — material icon named "compass calibration" (outlined). static const IconData compass_calibration_outlined = IconData(0xef72, fontFamily: 'MaterialIcons'); - /// compost — material icon named "compost". - static const IconData compost = IconData(0xf04d4, fontFamily: 'MaterialIcons'); - - /// compost — material icon named "compost" (sharp). - static const IconData compost_sharp = IconData(0xf03e0, fontFamily: 'MaterialIcons'); - - /// compost — material icon named "compost" (round). - static const IconData compost_rounded = IconData(0xf02ed, fontFamily: 'MaterialIcons'); - - /// compost — material icon named "compost" (outlined). - static const IconData compost_outlined = IconData(0xf05ce, fontFamily: 'MaterialIcons'); - /// compress — material icon named "compress". static const IconData compress = IconData(0xe184, fontFamily: 'MaterialIcons'); @@ -5318,18 +4920,6 @@ class Icons { /// connected_tv — material icon named "connected tv" (outlined). static const IconData connected_tv_outlined = IconData(0xef77, fontFamily: 'MaterialIcons'); - /// connecting_airports — material icon named "connecting airports". - static const IconData connecting_airports = IconData(0xf04d5, fontFamily: 'MaterialIcons'); - - /// connecting_airports — material icon named "connecting airports" (sharp). - static const IconData connecting_airports_sharp = IconData(0xf03e1, fontFamily: 'MaterialIcons'); - - /// connecting_airports — material icon named "connecting airports" (round). - static const IconData connecting_airports_rounded = IconData(0xf02ee, fontFamily: 'MaterialIcons'); - - /// connecting_airports — material icon named "connecting airports" (outlined). - static const IconData connecting_airports_outlined = IconData(0xf05cf, fontFamily: 'MaterialIcons'); - /// construction — material icon named "construction". static const IconData construction = IconData(0xe189, fontFamily: 'MaterialIcons'); @@ -5450,18 +5040,6 @@ class Icons { /// content_paste — material icon named "content paste" (outlined). static const IconData content_paste_outlined = IconData(0xef82, fontFamily: 'MaterialIcons'); - /// content_paste_go — material icon named "content paste go". - static const IconData content_paste_go = IconData(0xf04d6, fontFamily: 'MaterialIcons'); - - /// content_paste_go — material icon named "content paste go" (sharp). - static const IconData content_paste_go_sharp = IconData(0xf03e2, fontFamily: 'MaterialIcons'); - - /// content_paste_go — material icon named "content paste go" (round). - static const IconData content_paste_go_rounded = IconData(0xf02ef, fontFamily: 'MaterialIcons'); - - /// content_paste_go — material icon named "content paste go" (outlined). - static const IconData content_paste_go_outlined = IconData(0xf05d0, fontFamily: 'MaterialIcons'); - /// content_paste_off — material icon named "content paste off". static const IconData content_paste_off = IconData(0xe193, fontFamily: 'MaterialIcons'); @@ -5474,30 +5052,6 @@ class Icons { /// content_paste_off — material icon named "content paste off" (outlined). static const IconData content_paste_off_outlined = IconData(0xef81, fontFamily: 'MaterialIcons'); - /// content_paste_search — material icon named "content paste search". - static const IconData content_paste_search = IconData(0xf04d7, fontFamily: 'MaterialIcons'); - - /// content_paste_search — material icon named "content paste search" (sharp). - static const IconData content_paste_search_sharp = IconData(0xf03e3, fontFamily: 'MaterialIcons'); - - /// content_paste_search — material icon named "content paste search" (round). - static const IconData content_paste_search_rounded = IconData(0xf02f0, fontFamily: 'MaterialIcons'); - - /// content_paste_search — material icon named "content paste search" (outlined). - static const IconData content_paste_search_outlined = IconData(0xf05d1, fontFamily: 'MaterialIcons'); - - /// contrast — material icon named "contrast". - static const IconData contrast = IconData(0xf04d8, fontFamily: 'MaterialIcons'); - - /// contrast — material icon named "contrast" (sharp). - static const IconData contrast_sharp = IconData(0xf03e4, fontFamily: 'MaterialIcons'); - - /// contrast — material icon named "contrast" (round). - static const IconData contrast_rounded = IconData(0xf02f1, fontFamily: 'MaterialIcons'); - - /// contrast — material icon named "contrast" (outlined). - static const IconData contrast_outlined = IconData(0xf05d2, fontFamily: 'MaterialIcons'); - /// control_camera — material icon named "control camera". static const IconData control_camera = IconData(0xe194, fontFamily: 'MaterialIcons'); @@ -5534,18 +5088,6 @@ class Icons { /// control_point_duplicate — material icon named "control point duplicate" (outlined). static const IconData control_point_duplicate_outlined = IconData(0xef84, fontFamily: 'MaterialIcons'); - /// cookie — material icon named "cookie". - static const IconData cookie = IconData(0xf04d9, fontFamily: 'MaterialIcons'); - - /// cookie — material icon named "cookie" (sharp). - static const IconData cookie_sharp = IconData(0xf03e5, fontFamily: 'MaterialIcons'); - - /// cookie — material icon named "cookie" (round). - static const IconData cookie_rounded = IconData(0xf02f2, fontFamily: 'MaterialIcons'); - - /// cookie — material icon named "cookie" (outlined). - static const IconData cookie_outlined = IconData(0xf05d3, fontFamily: 'MaterialIcons'); - /// copy — material icon named "copy". static const IconData copy = IconData(0xe190, fontFamily: 'MaterialIcons'); @@ -5846,138 +5388,6 @@ class Icons { /// crop_square — material icon named "crop square" (outlined). static const IconData crop_square_outlined = IconData(0xef9d, fontFamily: 'MaterialIcons'); - /// cruelty_free — material icon named "cruelty free". - static const IconData cruelty_free = IconData(0xf04da, fontFamily: 'MaterialIcons'); - - /// cruelty_free — material icon named "cruelty free" (sharp). - static const IconData cruelty_free_sharp = IconData(0xf03e6, fontFamily: 'MaterialIcons'); - - /// cruelty_free — material icon named "cruelty free" (round). - static const IconData cruelty_free_rounded = IconData(0xf02f3, fontFamily: 'MaterialIcons'); - - /// cruelty_free — material icon named "cruelty free" (outlined). - static const IconData cruelty_free_outlined = IconData(0xf05d4, fontFamily: 'MaterialIcons'); - - /// css — material icon named "css". - static const IconData css = IconData(0xf04db, fontFamily: 'MaterialIcons'); - - /// css — material icon named "css" (sharp). - static const IconData css_sharp = IconData(0xf03e7, fontFamily: 'MaterialIcons'); - - /// css — material icon named "css" (round). - static const IconData css_rounded = IconData(0xf02f4, fontFamily: 'MaterialIcons'); - - /// css — material icon named "css" (outlined). - static const IconData css_outlined = IconData(0xf05d5, fontFamily: 'MaterialIcons'); - - /// currency_bitcoin — material icon named "currency bitcoin". - static const IconData currency_bitcoin = IconData(0xf06bc, fontFamily: 'MaterialIcons'); - - /// currency_bitcoin — material icon named "currency bitcoin" (sharp). - static const IconData currency_bitcoin_sharp = IconData(0xf06af, fontFamily: 'MaterialIcons'); - - /// currency_bitcoin — material icon named "currency bitcoin" (round). - static const IconData currency_bitcoin_rounded = IconData(0xf06c9, fontFamily: 'MaterialIcons'); - - /// currency_bitcoin — material icon named "currency bitcoin" (outlined). - static const IconData currency_bitcoin_outlined = IconData(0xf054a, fontFamily: 'MaterialIcons'); - - /// currency_exchange — material icon named "currency exchange". - static const IconData currency_exchange = IconData(0xf04dc, fontFamily: 'MaterialIcons'); - - /// currency_exchange — material icon named "currency exchange" (sharp). - static const IconData currency_exchange_sharp = IconData(0xf03e8, fontFamily: 'MaterialIcons'); - - /// currency_exchange — material icon named "currency exchange" (round). - static const IconData currency_exchange_rounded = IconData(0xf02f5, fontFamily: 'MaterialIcons'); - - /// currency_exchange — material icon named "currency exchange" (outlined). - static const IconData currency_exchange_outlined = IconData(0xf05d6, fontFamily: 'MaterialIcons'); - - /// currency_franc — material icon named "currency franc". - static const IconData currency_franc = IconData(0xf04dd, fontFamily: 'MaterialIcons'); - - /// currency_franc — material icon named "currency franc" (sharp). - static const IconData currency_franc_sharp = IconData(0xf03e9, fontFamily: 'MaterialIcons'); - - /// currency_franc — material icon named "currency franc" (round). - static const IconData currency_franc_rounded = IconData(0xf02f6, fontFamily: 'MaterialIcons'); - - /// currency_franc — material icon named "currency franc" (outlined). - static const IconData currency_franc_outlined = IconData(0xf05d7, fontFamily: 'MaterialIcons'); - - /// currency_lira — material icon named "currency lira". - static const IconData currency_lira = IconData(0xf04de, fontFamily: 'MaterialIcons'); - - /// currency_lira — material icon named "currency lira" (sharp). - static const IconData currency_lira_sharp = IconData(0xf03ea, fontFamily: 'MaterialIcons'); - - /// currency_lira — material icon named "currency lira" (round). - static const IconData currency_lira_rounded = IconData(0xf02f7, fontFamily: 'MaterialIcons'); - - /// currency_lira — material icon named "currency lira" (outlined). - static const IconData currency_lira_outlined = IconData(0xf05d8, fontFamily: 'MaterialIcons'); - - /// currency_pound — material icon named "currency pound". - static const IconData currency_pound = IconData(0xf04df, fontFamily: 'MaterialIcons'); - - /// currency_pound — material icon named "currency pound" (sharp). - static const IconData currency_pound_sharp = IconData(0xf03eb, fontFamily: 'MaterialIcons'); - - /// currency_pound — material icon named "currency pound" (round). - static const IconData currency_pound_rounded = IconData(0xf02f8, fontFamily: 'MaterialIcons'); - - /// currency_pound — material icon named "currency pound" (outlined). - static const IconData currency_pound_outlined = IconData(0xf05d9, fontFamily: 'MaterialIcons'); - - /// currency_ruble — material icon named "currency ruble". - static const IconData currency_ruble = IconData(0xf04e0, fontFamily: 'MaterialIcons'); - - /// currency_ruble — material icon named "currency ruble" (sharp). - static const IconData currency_ruble_sharp = IconData(0xf03ec, fontFamily: 'MaterialIcons'); - - /// currency_ruble — material icon named "currency ruble" (round). - static const IconData currency_ruble_rounded = IconData(0xf02f9, fontFamily: 'MaterialIcons'); - - /// currency_ruble — material icon named "currency ruble" (outlined). - static const IconData currency_ruble_outlined = IconData(0xf05da, fontFamily: 'MaterialIcons'); - - /// currency_rupee — material icon named "currency rupee". - static const IconData currency_rupee = IconData(0xf04e1, fontFamily: 'MaterialIcons'); - - /// currency_rupee — material icon named "currency rupee" (sharp). - static const IconData currency_rupee_sharp = IconData(0xf03ed, fontFamily: 'MaterialIcons'); - - /// currency_rupee — material icon named "currency rupee" (round). - static const IconData currency_rupee_rounded = IconData(0xf02fa, fontFamily: 'MaterialIcons'); - - /// currency_rupee — material icon named "currency rupee" (outlined). - static const IconData currency_rupee_outlined = IconData(0xf05db, fontFamily: 'MaterialIcons'); - - /// currency_yen — material icon named "currency yen". - static const IconData currency_yen = IconData(0xf04e2, fontFamily: 'MaterialIcons'); - - /// currency_yen — material icon named "currency yen" (sharp). - static const IconData currency_yen_sharp = IconData(0xf03ee, fontFamily: 'MaterialIcons'); - - /// currency_yen — material icon named "currency yen" (round). - static const IconData currency_yen_rounded = IconData(0xf02fb, fontFamily: 'MaterialIcons'); - - /// currency_yen — material icon named "currency yen" (outlined). - static const IconData currency_yen_outlined = IconData(0xf05dc, fontFamily: 'MaterialIcons'); - - /// currency_yuan — material icon named "currency yuan". - static const IconData currency_yuan = IconData(0xf04e3, fontFamily: 'MaterialIcons'); - - /// currency_yuan — material icon named "currency yuan" (sharp). - static const IconData currency_yuan_sharp = IconData(0xf03ef, fontFamily: 'MaterialIcons'); - - /// currency_yuan — material icon named "currency yuan" (round). - static const IconData currency_yuan_rounded = IconData(0xf02fc, fontFamily: 'MaterialIcons'); - - /// currency_yuan — material icon named "currency yuan" (outlined). - static const IconData currency_yuan_outlined = IconData(0xf05dd, fontFamily: 'MaterialIcons'); - /// cut — material icon named "cut". static const IconData cut = IconData(0xe191, fontFamily: 'MaterialIcons'); @@ -6038,42 +5448,6 @@ class Icons { /// dashboard_customize — material icon named "dashboard customize" (outlined). static const IconData dashboard_customize_outlined = IconData(0xefa0, fontFamily: 'MaterialIcons'); - /// data_array — material icon named "data array". - static const IconData data_array = IconData(0xf04e4, fontFamily: 'MaterialIcons'); - - /// data_array — material icon named "data array" (sharp). - static const IconData data_array_sharp = IconData(0xf03f0, fontFamily: 'MaterialIcons'); - - /// data_array — material icon named "data array" (round). - static const IconData data_array_rounded = IconData(0xf02fd, fontFamily: 'MaterialIcons'); - - /// data_array — material icon named "data array" (outlined). - static const IconData data_array_outlined = IconData(0xf05de, fontFamily: 'MaterialIcons'); - - /// data_exploration — material icon named "data exploration". - static const IconData data_exploration = IconData(0xf04e5, fontFamily: 'MaterialIcons'); - - /// data_exploration — material icon named "data exploration" (sharp). - static const IconData data_exploration_sharp = IconData(0xf03f1, fontFamily: 'MaterialIcons'); - - /// data_exploration — material icon named "data exploration" (round). - static const IconData data_exploration_rounded = IconData(0xf02fe, fontFamily: 'MaterialIcons'); - - /// data_exploration — material icon named "data exploration" (outlined). - static const IconData data_exploration_outlined = IconData(0xf05df, fontFamily: 'MaterialIcons'); - - /// data_object — material icon named "data object". - static const IconData data_object = IconData(0xf04e6, fontFamily: 'MaterialIcons'); - - /// data_object — material icon named "data object" (sharp). - static const IconData data_object_sharp = IconData(0xf03f2, fontFamily: 'MaterialIcons'); - - /// data_object — material icon named "data object" (round). - static const IconData data_object_rounded = IconData(0xf02ff, fontFamily: 'MaterialIcons'); - - /// data_object — material icon named "data object" (outlined). - static const IconData data_object_outlined = IconData(0xf05e0, fontFamily: 'MaterialIcons'); - /// data_saver_off — material icon named "data saver off". static const IconData data_saver_off = IconData(0xe1b3, fontFamily: 'MaterialIcons'); @@ -6098,18 +5472,6 @@ class Icons { /// data_saver_on — material icon named "data saver on" (outlined). static const IconData data_saver_on_outlined = IconData(0xefa3, fontFamily: 'MaterialIcons'); - /// data_thresholding — material icon named "data thresholding". - static const IconData data_thresholding = IconData(0xf04e7, fontFamily: 'MaterialIcons'); - - /// data_thresholding — material icon named "data thresholding" (sharp). - static const IconData data_thresholding_sharp = IconData(0xf03f3, fontFamily: 'MaterialIcons'); - - /// data_thresholding — material icon named "data thresholding" (round). - static const IconData data_thresholding_rounded = IconData(0xf0300, fontFamily: 'MaterialIcons'); - - /// data_thresholding — material icon named "data thresholding" (outlined). - static const IconData data_thresholding_outlined = IconData(0xf05e1, fontFamily: 'MaterialIcons'); - /// data_usage — material icon named "data usage". static const IconData data_usage = IconData(0xe1b5, fontFamily: 'MaterialIcons'); @@ -6134,18 +5496,6 @@ class Icons { /// date_range — material icon named "date range" (outlined). static const IconData date_range_outlined = IconData(0xefa5, fontFamily: 'MaterialIcons'); - /// deblur — material icon named "deblur". - static const IconData deblur = IconData(0xf04e8, fontFamily: 'MaterialIcons'); - - /// deblur — material icon named "deblur" (sharp). - static const IconData deblur_sharp = IconData(0xf03f4, fontFamily: 'MaterialIcons'); - - /// deblur — material icon named "deblur" (round). - static const IconData deblur_rounded = IconData(0xf0301, fontFamily: 'MaterialIcons'); - - /// deblur — material icon named "deblur" (outlined). - static const IconData deblur_outlined = IconData(0xf05e2, fontFamily: 'MaterialIcons'); - /// deck — material icon named "deck". static const IconData deck = IconData(0xe1b7, fontFamily: 'MaterialIcons'); @@ -6230,42 +5580,6 @@ class Icons { /// delivery_dining — material icon named "delivery dining" (outlined). static const IconData delivery_dining_outlined = IconData(0xefac, fontFamily: 'MaterialIcons'); - /// density_large — material icon named "density large". - static const IconData density_large = IconData(0xf04e9, fontFamily: 'MaterialIcons'); - - /// density_large — material icon named "density large" (sharp). - static const IconData density_large_sharp = IconData(0xf03f5, fontFamily: 'MaterialIcons'); - - /// density_large — material icon named "density large" (round). - static const IconData density_large_rounded = IconData(0xf0302, fontFamily: 'MaterialIcons'); - - /// density_large — material icon named "density large" (outlined). - static const IconData density_large_outlined = IconData(0xf05e3, fontFamily: 'MaterialIcons'); - - /// density_medium — material icon named "density medium". - static const IconData density_medium = IconData(0xf04ea, fontFamily: 'MaterialIcons'); - - /// density_medium — material icon named "density medium" (sharp). - static const IconData density_medium_sharp = IconData(0xf03f6, fontFamily: 'MaterialIcons'); - - /// density_medium — material icon named "density medium" (round). - static const IconData density_medium_rounded = IconData(0xf0303, fontFamily: 'MaterialIcons'); - - /// density_medium — material icon named "density medium" (outlined). - static const IconData density_medium_outlined = IconData(0xf05e4, fontFamily: 'MaterialIcons'); - - /// density_small — material icon named "density small". - static const IconData density_small = IconData(0xf04eb, fontFamily: 'MaterialIcons'); - - /// density_small — material icon named "density small" (sharp). - static const IconData density_small_sharp = IconData(0xf03f7, fontFamily: 'MaterialIcons'); - - /// density_small — material icon named "density small" (round). - static const IconData density_small_rounded = IconData(0xf0304, fontFamily: 'MaterialIcons'); - - /// density_small — material icon named "density small" (outlined). - static const IconData density_small_outlined = IconData(0xf05e5, fontFamily: 'MaterialIcons'); - /// departure_board — material icon named "departure board". static const IconData departure_board = IconData(0xe1be, fontFamily: 'MaterialIcons'); @@ -6290,18 +5604,6 @@ class Icons { /// description — material icon named "description" (outlined). static const IconData description_outlined = IconData(0xefae, fontFamily: 'MaterialIcons'); - /// deselect — material icon named "deselect". - static const IconData deselect = IconData(0xf04ec, fontFamily: 'MaterialIcons'); - - /// deselect — material icon named "deselect" (sharp). - static const IconData deselect_sharp = IconData(0xf03f8, fontFamily: 'MaterialIcons'); - - /// deselect — material icon named "deselect" (round). - static const IconData deselect_rounded = IconData(0xf0305, fontFamily: 'MaterialIcons'); - - /// deselect — material icon named "deselect" (outlined). - static const IconData deselect_outlined = IconData(0xf05e6, fontFamily: 'MaterialIcons'); - /// design_services — material icon named "design services". static const IconData design_services = IconData(0xe1c0, fontFamily: 'MaterialIcons'); @@ -6482,30 +5784,6 @@ class Icons { /// dialpad — material icon named "dialpad" (outlined). static const IconData dialpad_outlined = IconData(0xefbd, fontFamily: 'MaterialIcons'); - /// diamond — material icon named "diamond". - static const IconData diamond = IconData(0xf04ed, fontFamily: 'MaterialIcons'); - - /// diamond — material icon named "diamond" (sharp). - static const IconData diamond_sharp = IconData(0xf03f9, fontFamily: 'MaterialIcons'); - - /// diamond — material icon named "diamond" (round). - static const IconData diamond_rounded = IconData(0xf0306, fontFamily: 'MaterialIcons'); - - /// diamond — material icon named "diamond" (outlined). - static const IconData diamond_outlined = IconData(0xf05e7, fontFamily: 'MaterialIcons'); - - /// difference — material icon named "difference". - static const IconData difference = IconData(0xf04ee, fontFamily: 'MaterialIcons'); - - /// difference — material icon named "difference" (sharp). - static const IconData difference_sharp = IconData(0xf03fa, fontFamily: 'MaterialIcons'); - - /// difference — material icon named "difference" (round). - static const IconData difference_rounded = IconData(0xf0307, fontFamily: 'MaterialIcons'); - - /// difference — material icon named "difference" (outlined). - static const IconData difference_outlined = IconData(0xf05e8, fontFamily: 'MaterialIcons'); - /// dining — material icon named "dining". static const IconData dining = IconData(0xe1cf, fontFamily: 'MaterialIcons'); @@ -6782,18 +6060,6 @@ class Icons { /// disabled_by_default — material icon named "disabled by default" (outlined). static const IconData disabled_by_default_outlined = IconData(0xefd2, fontFamily: 'MaterialIcons'); - /// disabled_visible — material icon named "disabled visible". - static const IconData disabled_visible = IconData(0xf04ef, fontFamily: 'MaterialIcons'); - - /// disabled_visible — material icon named "disabled visible" (sharp). - static const IconData disabled_visible_sharp = IconData(0xf03fb, fontFamily: 'MaterialIcons'); - - /// disabled_visible — material icon named "disabled visible" (round). - static const IconData disabled_visible_rounded = IconData(0xf0308, fontFamily: 'MaterialIcons'); - - /// disabled_visible — material icon named "disabled visible" (outlined). - static const IconData disabled_visible_outlined = IconData(0xf05e9, fontFamily: 'MaterialIcons'); - /// disc_full — material icon named "disc full". static const IconData disc_full = IconData(0xe1e4, fontFamily: 'MaterialIcons'); @@ -6806,56 +6072,20 @@ class Icons { /// disc_full — material icon named "disc full" (outlined). static const IconData disc_full_outlined = IconData(0xefd3, fontFamily: 'MaterialIcons'); - /// discord — material icon named "discord". - static const IconData discord = IconData(0xf04f0, fontFamily: 'MaterialIcons'); - - /// discord — material icon named "discord" (sharp). - static const IconData discord_sharp = IconData(0xf03fc, fontFamily: 'MaterialIcons'); + /// dnd_forwardslash — material icon named "dnd forwardslash". + static const IconData dnd_forwardslash = IconData(0xe1eb, fontFamily: 'MaterialIcons'); - /// discord — material icon named "discord" (round). - static const IconData discord_rounded = IconData(0xf0309, fontFamily: 'MaterialIcons'); + /// dnd_forwardslash — material icon named "dnd forwardslash" (sharp). + static const IconData dnd_forwardslash_sharp = IconData(0xe8e7, fontFamily: 'MaterialIcons'); - /// discord — material icon named "discord" (outlined). - static const IconData discord_outlined = IconData(0xf05ea, fontFamily: 'MaterialIcons'); + /// dnd_forwardslash — material icon named "dnd forwardslash" (round). + static const IconData dnd_forwardslash_rounded = IconData(0xf6c6, fontFamily: 'MaterialIcons'); - /// discount — material icon named "discount". - static const IconData discount = IconData(0xf06bd, fontFamily: 'MaterialIcons'); + /// dnd_forwardslash — material icon named "dnd forwardslash" (outlined). + static const IconData dnd_forwardslash_outlined = IconData(0xefd9, fontFamily: 'MaterialIcons'); - /// discount — material icon named "discount" (sharp). - static const IconData discount_sharp = IconData(0xf06b0, fontFamily: 'MaterialIcons'); - - /// discount — material icon named "discount" (round). - static const IconData discount_rounded = IconData(0xf06ca, fontFamily: 'MaterialIcons'); - - /// discount — material icon named "discount" (outlined). - static const IconData discount_outlined = IconData(0xf06a3, fontFamily: 'MaterialIcons'); - - /// display_settings — material icon named "display settings". - static const IconData display_settings = IconData(0xf04f1, fontFamily: 'MaterialIcons'); - - /// display_settings — material icon named "display settings" (sharp). - static const IconData display_settings_sharp = IconData(0xf03fd, fontFamily: 'MaterialIcons'); - - /// display_settings — material icon named "display settings" (round). - static const IconData display_settings_rounded = IconData(0xf030a, fontFamily: 'MaterialIcons'); - - /// display_settings — material icon named "display settings" (outlined). - static const IconData display_settings_outlined = IconData(0xf05eb, fontFamily: 'MaterialIcons'); - - /// dnd_forwardslash — material icon named "dnd forwardslash". - static const IconData dnd_forwardslash = IconData(0xe1eb, fontFamily: 'MaterialIcons'); - - /// dnd_forwardslash — material icon named "dnd forwardslash" (sharp). - static const IconData dnd_forwardslash_sharp = IconData(0xe8e7, fontFamily: 'MaterialIcons'); - - /// dnd_forwardslash — material icon named "dnd forwardslash" (round). - static const IconData dnd_forwardslash_rounded = IconData(0xf6c6, fontFamily: 'MaterialIcons'); - - /// dnd_forwardslash — material icon named "dnd forwardslash" (outlined). - static const IconData dnd_forwardslash_outlined = IconData(0xefd9, fontFamily: 'MaterialIcons'); - - /// dns — material icon named "dns". - static const IconData dns = IconData(0xe1e5, fontFamily: 'MaterialIcons'); + /// dns — material icon named "dns". + static const IconData dns = IconData(0xe1e5, fontFamily: 'MaterialIcons'); /// dns — material icon named "dns" (sharp). static const IconData dns_sharp = IconData(0xe8e2, fontFamily: 'MaterialIcons'); @@ -7034,18 +6264,6 @@ class Icons { /// domain — material icon named "domain" (outlined). static const IconData domain_outlined = IconData(0xefe3, fontFamily: 'MaterialIcons'); - /// domain_add — material icon named "domain add". - static const IconData domain_add = IconData(0xf04f2, fontFamily: 'MaterialIcons'); - - /// domain_add — material icon named "domain add" (sharp). - static const IconData domain_add_sharp = IconData(0xf03fe, fontFamily: 'MaterialIcons'); - - /// domain_add — material icon named "domain add" (round). - static const IconData domain_add_rounded = IconData(0xf030b, fontFamily: 'MaterialIcons'); - - /// domain_add — material icon named "domain add" (outlined). - static const IconData domain_add_outlined = IconData(0xf05ec, fontFamily: 'MaterialIcons'); - /// domain_disabled — material icon named "domain disabled". static const IconData domain_disabled = IconData(0xe1f4, fontFamily: 'MaterialIcons'); @@ -7286,18 +6504,6 @@ class Icons { /// drag_indicator — material icon named "drag indicator" (outlined). static const IconData drag_indicator_outlined = IconData(0xeff6, fontFamily: 'MaterialIcons'); - /// draw — material icon named "draw". - static const IconData draw = IconData(0xf04f3, fontFamily: 'MaterialIcons'); - - /// draw — material icon named "draw" (sharp). - static const IconData draw_sharp = IconData(0xf03ff, fontFamily: 'MaterialIcons'); - - /// draw — material icon named "draw" (round). - static const IconData draw_rounded = IconData(0xf030c, fontFamily: 'MaterialIcons'); - - /// draw — material icon named "draw" (outlined). - static const IconData draw_outlined = IconData(0xf05ed, fontFamily: 'MaterialIcons'); - /// drive_eta — material icon named "drive eta". static const IconData drive_eta = IconData(0xe208, fontFamily: 'MaterialIcons'); @@ -7325,18 +6531,6 @@ class Icons { /// drive_file_move_outline — material icon named "drive file move outline". static const IconData drive_file_move_outline = IconData(0xe20a, fontFamily: 'MaterialIcons'); - /// drive_file_move_rtl — material icon named "drive file move rtl". - static const IconData drive_file_move_rtl = IconData(0xf04f4, fontFamily: 'MaterialIcons'); - - /// drive_file_move_rtl — material icon named "drive file move rtl" (sharp). - static const IconData drive_file_move_rtl_sharp = IconData(0xf0400, fontFamily: 'MaterialIcons'); - - /// drive_file_move_rtl — material icon named "drive file move rtl" (round). - static const IconData drive_file_move_rtl_rounded = IconData(0xf030d, fontFamily: 'MaterialIcons'); - - /// drive_file_move_rtl — material icon named "drive file move rtl" (outlined). - static const IconData drive_file_move_rtl_outlined = IconData(0xf05ee, fontFamily: 'MaterialIcons'); - /// drive_file_rename_outline — material icon named "drive file rename outline". static const IconData drive_file_rename_outline = IconData(0xe20b, fontFamily: 'MaterialIcons'); @@ -7541,18 +6735,6 @@ class Icons { /// edit_attributes — material icon named "edit attributes" (outlined). static const IconData edit_attributes_outlined = IconData(0xf008, fontFamily: 'MaterialIcons'); - /// edit_calendar — material icon named "edit calendar". - static const IconData edit_calendar = IconData(0xf04f5, fontFamily: 'MaterialIcons'); - - /// edit_calendar — material icon named "edit calendar" (sharp). - static const IconData edit_calendar_sharp = IconData(0xf0401, fontFamily: 'MaterialIcons'); - - /// edit_calendar — material icon named "edit calendar" (round). - static const IconData edit_calendar_rounded = IconData(0xf030e, fontFamily: 'MaterialIcons'); - - /// edit_calendar — material icon named "edit calendar" (outlined). - static const IconData edit_calendar_outlined = IconData(0xf05ef, fontFamily: 'MaterialIcons'); - /// edit_location — material icon named "edit location". static const IconData edit_location = IconData(0xe21c, fontFamily: 'MaterialIcons'); @@ -7577,18 +6759,6 @@ class Icons { /// edit_location_alt — material icon named "edit location alt" (outlined). static const IconData edit_location_alt_outlined = IconData(0xf009, fontFamily: 'MaterialIcons'); - /// edit_note — material icon named "edit note". - static const IconData edit_note = IconData(0xf04f6, fontFamily: 'MaterialIcons'); - - /// edit_note — material icon named "edit note" (sharp). - static const IconData edit_note_sharp = IconData(0xf0402, fontFamily: 'MaterialIcons'); - - /// edit_note — material icon named "edit note" (round). - static const IconData edit_note_rounded = IconData(0xf030f, fontFamily: 'MaterialIcons'); - - /// edit_note — material icon named "edit note" (outlined). - static const IconData edit_note_outlined = IconData(0xf05f0, fontFamily: 'MaterialIcons'); - /// edit_notifications — material icon named "edit notifications". static const IconData edit_notifications = IconData(0xe21e, fontFamily: 'MaterialIcons'); @@ -7625,30 +6795,6 @@ class Icons { /// edit_road — material icon named "edit road" (outlined). static const IconData edit_road_outlined = IconData(0xf00e, fontFamily: 'MaterialIcons'); - /// egg — material icon named "egg". - static const IconData egg = IconData(0xf04f8, fontFamily: 'MaterialIcons'); - - /// egg — material icon named "egg" (sharp). - static const IconData egg_sharp = IconData(0xf0404, fontFamily: 'MaterialIcons'); - - /// egg — material icon named "egg" (round). - static const IconData egg_rounded = IconData(0xf0311, fontFamily: 'MaterialIcons'); - - /// egg — material icon named "egg" (outlined). - static const IconData egg_outlined = IconData(0xf05f2, fontFamily: 'MaterialIcons'); - - /// egg_alt — material icon named "egg alt". - static const IconData egg_alt = IconData(0xf04f7, fontFamily: 'MaterialIcons'); - - /// egg_alt — material icon named "egg alt" (sharp). - static const IconData egg_alt_sharp = IconData(0xf0403, fontFamily: 'MaterialIcons'); - - /// egg_alt — material icon named "egg alt" (round). - static const IconData egg_alt_rounded = IconData(0xf0310, fontFamily: 'MaterialIcons'); - - /// egg_alt — material icon named "egg alt" (outlined). - static const IconData egg_alt_outlined = IconData(0xf05f1, fontFamily: 'MaterialIcons'); - /// eject — material icon named "eject". static const IconData eject = IconData(0xe221, fontFamily: 'MaterialIcons'); @@ -7673,18 +6819,6 @@ class Icons { /// elderly — material icon named "elderly" (outlined). static const IconData elderly_outlined = IconData(0xf010, fontFamily: 'MaterialIcons'); - /// elderly_woman — material icon named "elderly woman". - static const IconData elderly_woman = IconData(0xf04f9, fontFamily: 'MaterialIcons'); - - /// elderly_woman — material icon named "elderly woman" (sharp). - static const IconData elderly_woman_sharp = IconData(0xf0405, fontFamily: 'MaterialIcons'); - - /// elderly_woman — material icon named "elderly woman" (round). - static const IconData elderly_woman_rounded = IconData(0xf0312, fontFamily: 'MaterialIcons'); - - /// elderly_woman — material icon named "elderly woman" (outlined). - static const IconData elderly_woman_outlined = IconData(0xf05f3, fontFamily: 'MaterialIcons'); - /// electric_bike — material icon named "electric bike". static const IconData electric_bike = IconData(0xe223, fontFamily: 'MaterialIcons'); @@ -7781,18 +6915,6 @@ class Icons { /// email — material icon named "email" (outlined). static const IconData email_outlined = IconData(0xf018, fontFamily: 'MaterialIcons'); - /// emergency — material icon named "emergency". - static const IconData emergency = IconData(0xf04fa, fontFamily: 'MaterialIcons'); - - /// emergency — material icon named "emergency" (sharp). - static const IconData emergency_sharp = IconData(0xf0406, fontFamily: 'MaterialIcons'); - - /// emergency — material icon named "emergency" (round). - static const IconData emergency_rounded = IconData(0xf0313, fontFamily: 'MaterialIcons'); - - /// emergency — material icon named "emergency" (outlined). - static const IconData emergency_outlined = IconData(0xf05f4, fontFamily: 'MaterialIcons'); - /// emoji_emotions — material icon named "emoji emotions". static const IconData emoji_emotions = IconData(0xe22b, fontFamily: 'MaterialIcons'); @@ -8081,18 +7203,6 @@ class Icons { /// event_note — material icon named "event note" (outlined). static const IconData event_note_outlined = IconData(0xf02e, fontFamily: 'MaterialIcons', matchTextDirection: true); - /// event_repeat — material icon named "event repeat". - static const IconData event_repeat = IconData(0xf04fb, fontFamily: 'MaterialIcons'); - - /// event_repeat — material icon named "event repeat" (sharp). - static const IconData event_repeat_sharp = IconData(0xf0407, fontFamily: 'MaterialIcons'); - - /// event_repeat — material icon named "event repeat" (round). - static const IconData event_repeat_rounded = IconData(0xf0314, fontFamily: 'MaterialIcons'); - - /// event_repeat — material icon named "event repeat" (outlined). - static const IconData event_repeat_outlined = IconData(0xf05f5, fontFamily: 'MaterialIcons'); - /// event_seat — material icon named "event seat". static const IconData event_seat = IconData(0xe242, fontFamily: 'MaterialIcons'); @@ -8129,18 +7239,6 @@ class Icons { /// expand — material icon named "expand" (outlined). static const IconData expand_outlined = IconData(0xf034, fontFamily: 'MaterialIcons'); - /// expand_circle_down — material icon named "expand circle down". - static const IconData expand_circle_down = IconData(0xf04fc, fontFamily: 'MaterialIcons'); - - /// expand_circle_down — material icon named "expand circle down" (sharp). - static const IconData expand_circle_down_sharp = IconData(0xf0408, fontFamily: 'MaterialIcons'); - - /// expand_circle_down — material icon named "expand circle down" (round). - static const IconData expand_circle_down_rounded = IconData(0xf0315, fontFamily: 'MaterialIcons'); - - /// expand_circle_down — material icon named "expand circle down" (outlined). - static const IconData expand_circle_down_outlined = IconData(0xf05f6, fontFamily: 'MaterialIcons'); - /// expand_less — material icon named "expand less". static const IconData expand_less = IconData(0xe245, fontFamily: 'MaterialIcons'); @@ -8390,18 +7488,6 @@ class Icons { /// fact_check — material icon named "fact check" (outlined). static const IconData fact_check_outlined = IconData(0xf045, fontFamily: 'MaterialIcons'); - /// factory — material icon named "factory". - static const IconData factory = IconData(0xf04fd, fontFamily: 'MaterialIcons'); - - /// factory — material icon named "factory" (sharp). - static const IconData factory_sharp = IconData(0xf0409, fontFamily: 'MaterialIcons'); - - /// factory — material icon named "factory" (round). - static const IconData factory_rounded = IconData(0xf0316, fontFamily: 'MaterialIcons'); - - /// factory — material icon named "factory" (outlined). - static const IconData factory_outlined = IconData(0xf05f7, fontFamily: 'MaterialIcons'); - /// family_restroom — material icon named "family restroom". static const IconData family_restroom = IconData(0xe257, fontFamily: 'MaterialIcons'); @@ -8486,18 +7572,6 @@ class Icons { /// favorite_outline — material icon named "favorite outline" (outlined). static const IconData favorite_outline_outlined = IconData(0xf04a, fontFamily: 'MaterialIcons'); - /// fax — material icon named "fax". - static const IconData fax = IconData(0xf04fe, fontFamily: 'MaterialIcons'); - - /// fax — material icon named "fax" (sharp). - static const IconData fax_sharp = IconData(0xf040a, fontFamily: 'MaterialIcons'); - - /// fax — material icon named "fax" (round). - static const IconData fax_rounded = IconData(0xf0317, fontFamily: 'MaterialIcons'); - - /// fax — material icon named "fax" (outlined). - static const IconData fax_outlined = IconData(0xf05f8, fontFamily: 'MaterialIcons'); - /// featured_play_list — material icon named "featured play list". static const IconData featured_play_list = IconData(0xe25d, fontFamily: 'MaterialIcons', matchTextDirection: true); @@ -8690,18 +7764,6 @@ class Icons { /// file_download_off — material icon named "file download off" (outlined). static const IconData file_download_off_outlined = IconData(0xf05a, fontFamily: 'MaterialIcons'); - /// file_open — material icon named "file open". - static const IconData file_open = IconData(0xf04ff, fontFamily: 'MaterialIcons'); - - /// file_open — material icon named "file open" (sharp). - static const IconData file_open_sharp = IconData(0xf040b, fontFamily: 'MaterialIcons'); - - /// file_open — material icon named "file open" (round). - static const IconData file_open_rounded = IconData(0xf0318, fontFamily: 'MaterialIcons'); - - /// file_open — material icon named "file open" (outlined). - static const IconData file_open_outlined = IconData(0xf05f9, fontFamily: 'MaterialIcons'); - /// file_present — material icon named "file present". static const IconData file_present = IconData(0xe26d, fontFamily: 'MaterialIcons'); @@ -8870,18 +7932,6 @@ class Icons { /// filter_alt — material icon named "filter alt" (outlined). static const IconData filter_alt_outlined = IconData(0xf068, fontFamily: 'MaterialIcons'); - /// filter_alt_off — material icon named "filter alt off". - static const IconData filter_alt_off = IconData(0xf0500, fontFamily: 'MaterialIcons'); - - /// filter_alt_off — material icon named "filter alt off" (sharp). - static const IconData filter_alt_off_sharp = IconData(0xf040c, fontFamily: 'MaterialIcons'); - - /// filter_alt_off — material icon named "filter alt off" (round). - static const IconData filter_alt_off_rounded = IconData(0xf0319, fontFamily: 'MaterialIcons'); - - /// filter_alt_off — material icon named "filter alt off" (outlined). - static const IconData filter_alt_off_outlined = IconData(0xf05fa, fontFamily: 'MaterialIcons'); - /// filter_b_and_w — material icon named "filter b and w". static const IconData filter_b_and_w = IconData(0xe27b, fontFamily: 'MaterialIcons'); @@ -8957,18 +8007,6 @@ class Icons { /// filter_list_alt — material icon named "filter list alt". static const IconData filter_list_alt = IconData(0xe281, fontFamily: 'MaterialIcons'); - /// filter_list_off — material icon named "filter list off". - static const IconData filter_list_off = IconData(0xf0501, fontFamily: 'MaterialIcons'); - - /// filter_list_off — material icon named "filter list off" (sharp). - static const IconData filter_list_off_sharp = IconData(0xf040d, fontFamily: 'MaterialIcons'); - - /// filter_list_off — material icon named "filter list off" (round). - static const IconData filter_list_off_rounded = IconData(0xf031a, fontFamily: 'MaterialIcons'); - - /// filter_list_off — material icon named "filter list off" (outlined). - static const IconData filter_list_off_outlined = IconData(0xf05fb, fontFamily: 'MaterialIcons'); - /// filter_none — material icon named "filter none". static const IconData filter_none = IconData(0xe282, fontFamily: 'MaterialIcons'); @@ -9092,18 +8130,6 @@ class Icons { /// fit_screen — material icon named "fit screen" (outlined). static const IconData fit_screen_outlined = IconData(0xf079, fontFamily: 'MaterialIcons'); - /// fitbit — material icon named "fitbit". - static const IconData fitbit = IconData(0xf0502, fontFamily: 'MaterialIcons'); - - /// fitbit — material icon named "fitbit" (sharp). - static const IconData fitbit_sharp = IconData(0xf040e, fontFamily: 'MaterialIcons'); - - /// fitbit — material icon named "fitbit" (round). - static const IconData fitbit_rounded = IconData(0xf031b, fontFamily: 'MaterialIcons'); - - /// fitbit — material icon named "fitbit" (outlined). - static const IconData fitbit_outlined = IconData(0xf05fc, fontFamily: 'MaterialIcons'); - /// fitness_center — material icon named "fitness center". static const IconData fitness_center = IconData(0xe28d, fontFamily: 'MaterialIcons'); @@ -9128,18 +8154,6 @@ class Icons { /// flag — material icon named "flag" (outlined). static const IconData flag_outlined = IconData(0xf07b, fontFamily: 'MaterialIcons'); - /// flag_circle — material icon named "flag circle". - static const IconData flag_circle = IconData(0xf0503, fontFamily: 'MaterialIcons'); - - /// flag_circle — material icon named "flag circle" (sharp). - static const IconData flag_circle_sharp = IconData(0xf040f, fontFamily: 'MaterialIcons'); - - /// flag_circle — material icon named "flag circle" (round). - static const IconData flag_circle_rounded = IconData(0xf031c, fontFamily: 'MaterialIcons'); - - /// flag_circle — material icon named "flag circle" (outlined). - static const IconData flag_circle_outlined = IconData(0xf05fd, fontFamily: 'MaterialIcons'); - /// flaky — material icon named "flaky". static const IconData flaky = IconData(0xe28f, fontFamily: 'MaterialIcons'); @@ -9248,18 +8262,6 @@ class Icons { /// flight — material icon named "flight" (outlined). static const IconData flight_outlined = IconData(0xf085, fontFamily: 'MaterialIcons'); - /// flight_class — material icon named "flight class". - static const IconData flight_class = IconData(0xf0504, fontFamily: 'MaterialIcons'); - - /// flight_class — material icon named "flight class" (sharp). - static const IconData flight_class_sharp = IconData(0xf0410, fontFamily: 'MaterialIcons'); - - /// flight_class — material icon named "flight class" (round). - static const IconData flight_class_rounded = IconData(0xf031d, fontFamily: 'MaterialIcons'); - - /// flight_class — material icon named "flight class" (outlined). - static const IconData flight_class_outlined = IconData(0xf05fe, fontFamily: 'MaterialIcons'); - /// flight_land — material icon named "flight land". static const IconData flight_land = IconData(0xe298, fontFamily: 'MaterialIcons', matchTextDirection: true); @@ -9392,9 +8394,6 @@ class Icons { /// fmd_good — material icon named "fmd good" (outlined). static const IconData fmd_good_outlined = IconData(0xf08f, fontFamily: 'MaterialIcons'); - /// foggy — material icon named "foggy". - static const IconData foggy = IconData(0xf0505, fontFamily: 'MaterialIcons'); - /// folder — material icon named "folder". static const IconData folder = IconData(0xe2a3, fontFamily: 'MaterialIcons'); @@ -9407,42 +8406,6 @@ class Icons { /// folder — material icon named "folder" (outlined). static const IconData folder_outlined = IconData(0xf091, fontFamily: 'MaterialIcons'); - /// folder_copy — material icon named "folder copy". - static const IconData folder_copy = IconData(0xf0506, fontFamily: 'MaterialIcons'); - - /// folder_copy — material icon named "folder copy" (sharp). - static const IconData folder_copy_sharp = IconData(0xf0411, fontFamily: 'MaterialIcons'); - - /// folder_copy — material icon named "folder copy" (round). - static const IconData folder_copy_rounded = IconData(0xf031e, fontFamily: 'MaterialIcons'); - - /// folder_copy — material icon named "folder copy" (outlined). - static const IconData folder_copy_outlined = IconData(0xf05ff, fontFamily: 'MaterialIcons'); - - /// folder_delete — material icon named "folder delete". - static const IconData folder_delete = IconData(0xf0507, fontFamily: 'MaterialIcons'); - - /// folder_delete — material icon named "folder delete" (sharp). - static const IconData folder_delete_sharp = IconData(0xf0412, fontFamily: 'MaterialIcons'); - - /// folder_delete — material icon named "folder delete" (round). - static const IconData folder_delete_rounded = IconData(0xf031f, fontFamily: 'MaterialIcons'); - - /// folder_delete — material icon named "folder delete" (outlined). - static const IconData folder_delete_outlined = IconData(0xf0600, fontFamily: 'MaterialIcons'); - - /// folder_off — material icon named "folder off". - static const IconData folder_off = IconData(0xf0508, fontFamily: 'MaterialIcons'); - - /// folder_off — material icon named "folder off" (sharp). - static const IconData folder_off_sharp = IconData(0xf0413, fontFamily: 'MaterialIcons'); - - /// folder_off — material icon named "folder off" (round). - static const IconData folder_off_rounded = IconData(0xf0320, fontFamily: 'MaterialIcons'); - - /// folder_off — material icon named "folder off" (outlined). - static const IconData folder_off_outlined = IconData(0xf0601, fontFamily: 'MaterialIcons'); - /// folder_open — material icon named "folder open". static const IconData folder_open = IconData(0xe2a4, fontFamily: 'MaterialIcons'); @@ -9479,18 +8442,6 @@ class Icons { /// folder_special — material icon named "folder special" (outlined). static const IconData folder_special_outlined = IconData(0xf093, fontFamily: 'MaterialIcons'); - /// folder_zip — material icon named "folder zip". - static const IconData folder_zip = IconData(0xf0509, fontFamily: 'MaterialIcons'); - - /// folder_zip — material icon named "folder zip" (sharp). - static const IconData folder_zip_sharp = IconData(0xf0414, fontFamily: 'MaterialIcons'); - - /// folder_zip — material icon named "folder zip" (round). - static const IconData folder_zip_rounded = IconData(0xf0321, fontFamily: 'MaterialIcons'); - - /// folder_zip — material icon named "folder zip" (outlined). - static const IconData folder_zip_outlined = IconData(0xf0602, fontFamily: 'MaterialIcons'); - /// follow_the_signs — material icon named "follow the signs". static const IconData follow_the_signs = IconData(0xe2a7, fontFamily: 'MaterialIcons'); @@ -9539,42 +8490,6 @@ class Icons { /// food_bank — material icon named "food bank" (outlined). static const IconData food_bank_outlined = IconData(0xf097, fontFamily: 'MaterialIcons'); - /// forest — material icon named "forest". - static const IconData forest = IconData(0xf050a, fontFamily: 'MaterialIcons'); - - /// forest — material icon named "forest" (sharp). - static const IconData forest_sharp = IconData(0xf0415, fontFamily: 'MaterialIcons'); - - /// forest — material icon named "forest" (round). - static const IconData forest_rounded = IconData(0xf0322, fontFamily: 'MaterialIcons'); - - /// forest — material icon named "forest" (outlined). - static const IconData forest_outlined = IconData(0xf0603, fontFamily: 'MaterialIcons'); - - /// fork_left — material icon named "fork left". - static const IconData fork_left = IconData(0xf050b, fontFamily: 'MaterialIcons'); - - /// fork_left — material icon named "fork left" (sharp). - static const IconData fork_left_sharp = IconData(0xf0416, fontFamily: 'MaterialIcons'); - - /// fork_left — material icon named "fork left" (round). - static const IconData fork_left_rounded = IconData(0xf0323, fontFamily: 'MaterialIcons'); - - /// fork_left — material icon named "fork left" (outlined). - static const IconData fork_left_outlined = IconData(0xf0604, fontFamily: 'MaterialIcons'); - - /// fork_right — material icon named "fork right". - static const IconData fork_right = IconData(0xf050c, fontFamily: 'MaterialIcons'); - - /// fork_right — material icon named "fork right" (sharp). - static const IconData fork_right_sharp = IconData(0xf0417, fontFamily: 'MaterialIcons'); - - /// fork_right — material icon named "fork right" (round). - static const IconData fork_right_rounded = IconData(0xf0324, fontFamily: 'MaterialIcons'); - - /// fork_right — material icon named "fork right" (outlined). - static const IconData fork_right_outlined = IconData(0xf0605, fontFamily: 'MaterialIcons'); - /// format_align_center — material icon named "format align center". static const IconData format_align_center = IconData(0xe2ab, fontFamily: 'MaterialIcons'); @@ -9767,18 +8682,6 @@ class Icons { /// format_list_numbered_rtl — material icon named "format list numbered rtl" (outlined). static const IconData format_list_numbered_rtl_outlined = IconData(0xf0a7, fontFamily: 'MaterialIcons'); - /// format_overline — material icon named "format overline". - static const IconData format_overline = IconData(0xf050d, fontFamily: 'MaterialIcons'); - - /// format_overline — material icon named "format overline" (sharp). - static const IconData format_overline_sharp = IconData(0xf0418, fontFamily: 'MaterialIcons'); - - /// format_overline — material icon named "format overline" (round). - static const IconData format_overline_rounded = IconData(0xf0325, fontFamily: 'MaterialIcons'); - - /// format_overline — material icon named "format overline" (outlined). - static const IconData format_overline_outlined = IconData(0xf0606, fontFamily: 'MaterialIcons'); - /// format_paint — material icon named "format paint". static const IconData format_paint = IconData(0xe2bb, fontFamily: 'MaterialIcons'); @@ -9887,18 +8790,6 @@ class Icons { /// format_underlined — material icon named "format underlined" (outlined). static const IconData format_underlined_outlined = IconData(0xf0af, fontFamily: 'MaterialIcons'); - /// fort — material icon named "fort". - static const IconData fort = IconData(0xf050e, fontFamily: 'MaterialIcons'); - - /// fort — material icon named "fort" (sharp). - static const IconData fort_sharp = IconData(0xf0419, fontFamily: 'MaterialIcons'); - - /// fort — material icon named "fort" (round). - static const IconData fort_rounded = IconData(0xf0326, fontFamily: 'MaterialIcons'); - - /// fort — material icon named "fort" (outlined). - static const IconData fort_outlined = IconData(0xf0607, fontFamily: 'MaterialIcons'); - /// forum — material icon named "forum". static const IconData forum = IconData(0xe2c3, fontFamily: 'MaterialIcons'); @@ -9995,30 +8886,6 @@ class Icons { /// free_breakfast — material icon named "free breakfast" (outlined). static const IconData free_breakfast_outlined = IconData(0xf0b7, fontFamily: 'MaterialIcons'); - /// free_cancellation — material icon named "free cancellation". - static const IconData free_cancellation = IconData(0xf050f, fontFamily: 'MaterialIcons'); - - /// free_cancellation — material icon named "free cancellation" (sharp). - static const IconData free_cancellation_sharp = IconData(0xf041a, fontFamily: 'MaterialIcons'); - - /// free_cancellation — material icon named "free cancellation" (round). - static const IconData free_cancellation_rounded = IconData(0xf0327, fontFamily: 'MaterialIcons'); - - /// free_cancellation — material icon named "free cancellation" (outlined). - static const IconData free_cancellation_outlined = IconData(0xf0608, fontFamily: 'MaterialIcons'); - - /// front_hand — material icon named "front hand". - static const IconData front_hand = IconData(0xf0510, fontFamily: 'MaterialIcons'); - - /// front_hand — material icon named "front hand" (sharp). - static const IconData front_hand_sharp = IconData(0xf041b, fontFamily: 'MaterialIcons'); - - /// front_hand — material icon named "front hand" (round). - static const IconData front_hand_rounded = IconData(0xf0328, fontFamily: 'MaterialIcons'); - - /// front_hand — material icon named "front hand" (outlined). - static const IconData front_hand_outlined = IconData(0xf0609, fontFamily: 'MaterialIcons'); - /// fullscreen — material icon named "fullscreen". static const IconData fullscreen = IconData(0xe2cb, fontFamily: 'MaterialIcons'); @@ -10127,18 +8994,6 @@ class Icons { /// gavel — material icon named "gavel" (outlined). static const IconData gavel_outlined = IconData(0xf0c0, fontFamily: 'MaterialIcons'); - /// generating_tokens — material icon named "generating tokens". - static const IconData generating_tokens = IconData(0xf0511, fontFamily: 'MaterialIcons'); - - /// generating_tokens — material icon named "generating tokens" (sharp). - static const IconData generating_tokens_sharp = IconData(0xf041c, fontFamily: 'MaterialIcons'); - - /// generating_tokens — material icon named "generating tokens" (round). - static const IconData generating_tokens_rounded = IconData(0xf0329, fontFamily: 'MaterialIcons'); - - /// generating_tokens — material icon named "generating tokens" (outlined). - static const IconData generating_tokens_outlined = IconData(0xf060a, fontFamily: 'MaterialIcons'); - /// gesture — material icon named "gesture". static const IconData gesture = IconData(0xe2d4, fontFamily: 'MaterialIcons'); @@ -10175,30 +9030,6 @@ class Icons { /// gif — material icon named "gif" (outlined). static const IconData gif_outlined = IconData(0xf0c3, fontFamily: 'MaterialIcons'); - /// gif_box — material icon named "gif box". - static const IconData gif_box = IconData(0xf0512, fontFamily: 'MaterialIcons'); - - /// gif_box — material icon named "gif box" (sharp). - static const IconData gif_box_sharp = IconData(0xf041d, fontFamily: 'MaterialIcons'); - - /// gif_box — material icon named "gif box" (round). - static const IconData gif_box_rounded = IconData(0xf032a, fontFamily: 'MaterialIcons'); - - /// gif_box — material icon named "gif box" (outlined). - static const IconData gif_box_outlined = IconData(0xf060b, fontFamily: 'MaterialIcons'); - - /// girl — material icon named "girl". - static const IconData girl = IconData(0xf0513, fontFamily: 'MaterialIcons'); - - /// girl — material icon named "girl" (sharp). - static const IconData girl_sharp = IconData(0xf041e, fontFamily: 'MaterialIcons'); - - /// girl — material icon named "girl" (round). - static const IconData girl_rounded = IconData(0xf032b, fontFamily: 'MaterialIcons'); - - /// girl — material icon named "girl" (outlined). - static const IconData girl_outlined = IconData(0xf060c, fontFamily: 'MaterialIcons'); - /// gite — material icon named "gite". static const IconData gite = IconData(0xe2d7, fontFamily: 'MaterialIcons'); @@ -10463,30 +9294,6 @@ class Icons { /// group_add — material icon named "group add" (outlined). static const IconData group_add_outlined = IconData(0xf0d8, fontFamily: 'MaterialIcons'); - /// group_off — material icon named "group off". - static const IconData group_off = IconData(0xf0514, fontFamily: 'MaterialIcons'); - - /// group_off — material icon named "group off" (sharp). - static const IconData group_off_sharp = IconData(0xf041f, fontFamily: 'MaterialIcons'); - - /// group_off — material icon named "group off" (round). - static const IconData group_off_rounded = IconData(0xf032c, fontFamily: 'MaterialIcons'); - - /// group_off — material icon named "group off" (outlined). - static const IconData group_off_outlined = IconData(0xf060d, fontFamily: 'MaterialIcons'); - - /// group_remove — material icon named "group remove". - static const IconData group_remove = IconData(0xf0515, fontFamily: 'MaterialIcons'); - - /// group_remove — material icon named "group remove" (sharp). - static const IconData group_remove_sharp = IconData(0xf0420, fontFamily: 'MaterialIcons'); - - /// group_remove — material icon named "group remove" (round). - static const IconData group_remove_rounded = IconData(0xf032d, fontFamily: 'MaterialIcons'); - - /// group_remove — material icon named "group remove" (outlined). - static const IconData group_remove_outlined = IconData(0xf060e, fontFamily: 'MaterialIcons'); - /// group_work — material icon named "group work". static const IconData group_work = IconData(0xe2ed, fontFamily: 'MaterialIcons'); @@ -10547,18 +9354,6 @@ class Icons { /// hail — material icon named "hail" (outlined). static const IconData hail_outlined = IconData(0xf0de, fontFamily: 'MaterialIcons'); - /// handshake — material icon named "handshake". - static const IconData handshake = IconData(0xf06be, fontFamily: 'MaterialIcons'); - - /// handshake — material icon named "handshake" (sharp). - static const IconData handshake_sharp = IconData(0xf06b1, fontFamily: 'MaterialIcons'); - - /// handshake — material icon named "handshake" (round). - static const IconData handshake_rounded = IconData(0xf06cb, fontFamily: 'MaterialIcons'); - - /// handshake — material icon named "handshake" (outlined). - static const IconData handshake_outlined = IconData(0xf06a4, fontFamily: 'MaterialIcons'); - /// handyman — material icon named "handyman". static const IconData handyman = IconData(0xe2f2, fontFamily: 'MaterialIcons'); @@ -10823,18 +9618,6 @@ class Icons { /// hearing_disabled — material icon named "hearing disabled" (outlined). static const IconData hearing_disabled_outlined = IconData(0xf0f3, fontFamily: 'MaterialIcons'); - /// heart_broken — material icon named "heart broken". - static const IconData heart_broken = IconData(0xf0516, fontFamily: 'MaterialIcons'); - - /// heart_broken — material icon named "heart broken" (sharp). - static const IconData heart_broken_sharp = IconData(0xf0421, fontFamily: 'MaterialIcons'); - - /// heart_broken — material icon named "heart broken" (round). - static const IconData heart_broken_rounded = IconData(0xf032e, fontFamily: 'MaterialIcons'); - - /// heart_broken — material icon named "heart broken" (outlined). - static const IconData heart_broken_outlined = IconData(0xf060f, fontFamily: 'MaterialIcons'); - /// height — material icon named "height". static const IconData height = IconData(0xe308, fontFamily: 'MaterialIcons'); @@ -10895,18 +9678,6 @@ class Icons { /// hevc — material icon named "hevc" (outlined). static const IconData hevc_outlined = IconData(0xf0f9, fontFamily: 'MaterialIcons'); - /// hexagon — material icon named "hexagon". - static const IconData hexagon = IconData(0xf0517, fontFamily: 'MaterialIcons'); - - /// hexagon — material icon named "hexagon" (sharp). - static const IconData hexagon_sharp = IconData(0xf0422, fontFamily: 'MaterialIcons'); - - /// hexagon — material icon named "hexagon" (round). - static const IconData hexagon_rounded = IconData(0xf032f, fontFamily: 'MaterialIcons'); - - /// hexagon — material icon named "hexagon" (outlined). - static const IconData hexagon_outlined = IconData(0xf0610, fontFamily: 'MaterialIcons'); - /// hide_image — material icon named "hide image". static const IconData hide_image = IconData(0xe30d, fontFamily: 'MaterialIcons'); @@ -11039,42 +9810,6 @@ class Icons { /// history_toggle_off — material icon named "history toggle off" (outlined). static const IconData history_toggle_off_outlined = IconData(0xf103, fontFamily: 'MaterialIcons'); - /// hive — material icon named "hive". - static const IconData hive = IconData(0xf0518, fontFamily: 'MaterialIcons'); - - /// hive — material icon named "hive" (sharp). - static const IconData hive_sharp = IconData(0xf0423, fontFamily: 'MaterialIcons'); - - /// hive — material icon named "hive" (round). - static const IconData hive_rounded = IconData(0xf0330, fontFamily: 'MaterialIcons'); - - /// hive — material icon named "hive" (outlined). - static const IconData hive_outlined = IconData(0xf0611, fontFamily: 'MaterialIcons'); - - /// hls — material icon named "hls". - static const IconData hls = IconData(0xf0519, fontFamily: 'MaterialIcons'); - - /// hls — material icon named "hls" (sharp). - static const IconData hls_sharp = IconData(0xf0425, fontFamily: 'MaterialIcons'); - - /// hls — material icon named "hls" (round). - static const IconData hls_rounded = IconData(0xf0332, fontFamily: 'MaterialIcons'); - - /// hls — material icon named "hls" (outlined). - static const IconData hls_outlined = IconData(0xf0613, fontFamily: 'MaterialIcons'); - - /// hls_off — material icon named "hls off". - static const IconData hls_off = IconData(0xf051a, fontFamily: 'MaterialIcons'); - - /// hls_off — material icon named "hls off" (sharp). - static const IconData hls_off_sharp = IconData(0xf0424, fontFamily: 'MaterialIcons'); - - /// hls_off — material icon named "hls off" (round). - static const IconData hls_off_rounded = IconData(0xf0331, fontFamily: 'MaterialIcons'); - - /// hls_off — material icon named "hls off" (outlined). - static const IconData hls_off_outlined = IconData(0xf0612, fontFamily: 'MaterialIcons'); - /// holiday_village — material icon named "holiday village". static const IconData holiday_village = IconData(0xe317, fontFamily: 'MaterialIcons'); @@ -11210,18 +9945,6 @@ class Icons { /// hotel — material icon named "hotel" (outlined). static const IconData hotel_outlined = IconData(0xf10e, fontFamily: 'MaterialIcons'); - /// hotel_class — material icon named "hotel class". - static const IconData hotel_class = IconData(0xf051b, fontFamily: 'MaterialIcons'); - - /// hotel_class — material icon named "hotel class" (sharp). - static const IconData hotel_class_sharp = IconData(0xf0426, fontFamily: 'MaterialIcons'); - - /// hotel_class — material icon named "hotel class" (round). - static const IconData hotel_class_rounded = IconData(0xf0333, fontFamily: 'MaterialIcons'); - - /// hotel_class — material icon named "hotel class" (outlined). - static const IconData hotel_class_outlined = IconData(0xf0614, fontFamily: 'MaterialIcons'); - /// hourglass_bottom — material icon named "hourglass bottom". static const IconData hourglass_bottom = IconData(0xe323, fontFamily: 'MaterialIcons'); @@ -11342,18 +10065,6 @@ class Icons { /// how_to_vote — material icon named "how to vote" (outlined). static const IconData how_to_vote_outlined = IconData(0xf118, fontFamily: 'MaterialIcons'); - /// html — material icon named "html". - static const IconData html = IconData(0xf051c, fontFamily: 'MaterialIcons'); - - /// html — material icon named "html" (sharp). - static const IconData html_sharp = IconData(0xf0427, fontFamily: 'MaterialIcons'); - - /// html — material icon named "html" (round). - static const IconData html_rounded = IconData(0xf0334, fontFamily: 'MaterialIcons'); - - /// html — material icon named "html" (outlined). - static const IconData html_outlined = IconData(0xf0615, fontFamily: 'MaterialIcons'); - /// http — material icon named "http". static const IconData http = IconData(0xe32d, fontFamily: 'MaterialIcons'); @@ -11378,18 +10089,6 @@ class Icons { /// https — material icon named "https" (outlined). static const IconData https_outlined = IconData(0xf11a, fontFamily: 'MaterialIcons'); - /// hub — material icon named "hub". - static const IconData hub = IconData(0xf051d, fontFamily: 'MaterialIcons'); - - /// hub — material icon named "hub" (sharp). - static const IconData hub_sharp = IconData(0xf0428, fontFamily: 'MaterialIcons'); - - /// hub — material icon named "hub" (round). - static const IconData hub_rounded = IconData(0xf0335, fontFamily: 'MaterialIcons'); - - /// hub — material icon named "hub" (outlined). - static const IconData hub_outlined = IconData(0xf0616, fontFamily: 'MaterialIcons'); - /// hvac — material icon named "hvac". static const IconData hvac = IconData(0xe32f, fontFamily: 'MaterialIcons'); @@ -11534,18 +10233,6 @@ class Icons { /// inbox — material icon named "inbox" (outlined). static const IconData inbox_outlined = IconData(0xf126, fontFamily: 'MaterialIcons'); - /// incomplete_circle — material icon named "incomplete circle". - static const IconData incomplete_circle = IconData(0xf051e, fontFamily: 'MaterialIcons'); - - /// incomplete_circle — material icon named "incomplete circle" (sharp). - static const IconData incomplete_circle_sharp = IconData(0xf0429, fontFamily: 'MaterialIcons'); - - /// incomplete_circle — material icon named "incomplete circle" (round). - static const IconData incomplete_circle_rounded = IconData(0xf0336, fontFamily: 'MaterialIcons'); - - /// incomplete_circle — material icon named "incomplete circle" (outlined). - static const IconData incomplete_circle_outlined = IconData(0xf0617, fontFamily: 'MaterialIcons'); - /// indeterminate_check_box — material icon named "indeterminate check box". static const IconData indeterminate_check_box = IconData(0xe33b, fontFamily: 'MaterialIcons'); @@ -11600,7 +10287,7 @@ class Icons { /// insert_chart — material icon named "insert chart" (round). static const IconData insert_chart_rounded = IconData(0xf819, fontFamily: 'MaterialIcons'); - /// insert_chart — material icon named "insert chart". + /// insert_chart_outlined — material icon named "insert chart outlined". static const IconData insert_chart_outlined = IconData(0xf12a, fontFamily: 'MaterialIcons'); /// insert_chart_outlined — material icon named "insert chart outlined" (sharp). @@ -11672,18 +10359,6 @@ class Icons { /// insert_link — material icon named "insert link" (outlined). static const IconData insert_link_outlined = IconData(0xf130, fontFamily: 'MaterialIcons'); - /// insert_page_break — material icon named "insert page break". - static const IconData insert_page_break = IconData(0xf0520, fontFamily: 'MaterialIcons'); - - /// insert_page_break — material icon named "insert page break" (sharp). - static const IconData insert_page_break_sharp = IconData(0xf042a, fontFamily: 'MaterialIcons'); - - /// insert_page_break — material icon named "insert page break" (round). - static const IconData insert_page_break_rounded = IconData(0xf0337, fontFamily: 'MaterialIcons'); - - /// insert_page_break — material icon named "insert page break" (outlined). - static const IconData insert_page_break_outlined = IconData(0xf0618, fontFamily: 'MaterialIcons'); - /// insert_photo — material icon named "insert photo". static const IconData insert_photo = IconData(0xe346, fontFamily: 'MaterialIcons'); @@ -11708,30 +10383,6 @@ class Icons { /// insights — material icon named "insights" (outlined). static const IconData insights_outlined = IconData(0xf132, fontFamily: 'MaterialIcons'); - /// install_desktop — material icon named "install desktop". - static const IconData install_desktop = IconData(0xf0521, fontFamily: 'MaterialIcons'); - - /// install_desktop — material icon named "install desktop" (sharp). - static const IconData install_desktop_sharp = IconData(0xf042b, fontFamily: 'MaterialIcons'); - - /// install_desktop — material icon named "install desktop" (round). - static const IconData install_desktop_rounded = IconData(0xf0338, fontFamily: 'MaterialIcons'); - - /// install_desktop — material icon named "install desktop" (outlined). - static const IconData install_desktop_outlined = IconData(0xf0619, fontFamily: 'MaterialIcons'); - - /// install_mobile — material icon named "install mobile". - static const IconData install_mobile = IconData(0xf0522, fontFamily: 'MaterialIcons'); - - /// install_mobile — material icon named "install mobile" (sharp). - static const IconData install_mobile_sharp = IconData(0xf042c, fontFamily: 'MaterialIcons'); - - /// install_mobile — material icon named "install mobile" (round). - static const IconData install_mobile_rounded = IconData(0xf0339, fontFamily: 'MaterialIcons'); - - /// install_mobile — material icon named "install mobile" (outlined). - static const IconData install_mobile_outlined = IconData(0xf061a, fontFamily: 'MaterialIcons'); - /// integration_instructions — material icon named "integration instructions". static const IconData integration_instructions = IconData(0xe348, fontFamily: 'MaterialIcons'); @@ -11744,30 +10395,6 @@ class Icons { /// integration_instructions — material icon named "integration instructions" (outlined). static const IconData integration_instructions_outlined = IconData(0xf133, fontFamily: 'MaterialIcons'); - /// interests — material icon named "interests". - static const IconData interests = IconData(0xf0523, fontFamily: 'MaterialIcons'); - - /// interests — material icon named "interests" (sharp). - static const IconData interests_sharp = IconData(0xf042d, fontFamily: 'MaterialIcons'); - - /// interests — material icon named "interests" (round). - static const IconData interests_rounded = IconData(0xf033a, fontFamily: 'MaterialIcons'); - - /// interests — material icon named "interests" (outlined). - static const IconData interests_outlined = IconData(0xf061b, fontFamily: 'MaterialIcons'); - - /// interpreter_mode — material icon named "interpreter mode". - static const IconData interpreter_mode = IconData(0xf0524, fontFamily: 'MaterialIcons'); - - /// interpreter_mode — material icon named "interpreter mode" (sharp). - static const IconData interpreter_mode_sharp = IconData(0xf042e, fontFamily: 'MaterialIcons'); - - /// interpreter_mode — material icon named "interpreter mode" (round). - static const IconData interpreter_mode_rounded = IconData(0xf033b, fontFamily: 'MaterialIcons'); - - /// interpreter_mode — material icon named "interpreter mode" (outlined). - static const IconData interpreter_mode_outlined = IconData(0xf061c, fontFamily: 'MaterialIcons'); - /// inventory — material icon named "inventory". static const IconData inventory = IconData(0xe349, fontFamily: 'MaterialIcons'); @@ -11864,66 +10491,6 @@ class Icons { /// iso — material icon named "iso" (outlined). static const IconData iso_outlined = IconData(0xf13a, fontFamily: 'MaterialIcons'); - /// javascript — material icon named "javascript". - static const IconData javascript = IconData(0xf0525, fontFamily: 'MaterialIcons'); - - /// javascript — material icon named "javascript" (sharp). - static const IconData javascript_sharp = IconData(0xf042f, fontFamily: 'MaterialIcons'); - - /// javascript — material icon named "javascript" (round). - static const IconData javascript_rounded = IconData(0xf033c, fontFamily: 'MaterialIcons'); - - /// javascript — material icon named "javascript" (outlined). - static const IconData javascript_outlined = IconData(0xf061d, fontFamily: 'MaterialIcons'); - - /// join_full — material icon named "join full". - static const IconData join_full = IconData(0xf0526, fontFamily: 'MaterialIcons'); - - /// join_full — material icon named "join full" (sharp). - static const IconData join_full_sharp = IconData(0xf0430, fontFamily: 'MaterialIcons'); - - /// join_full — material icon named "join full" (round). - static const IconData join_full_rounded = IconData(0xf033d, fontFamily: 'MaterialIcons'); - - /// join_full — material icon named "join full" (outlined). - static const IconData join_full_outlined = IconData(0xf061e, fontFamily: 'MaterialIcons'); - - /// join_inner — material icon named "join inner". - static const IconData join_inner = IconData(0xf0527, fontFamily: 'MaterialIcons'); - - /// join_inner — material icon named "join inner" (sharp). - static const IconData join_inner_sharp = IconData(0xf0431, fontFamily: 'MaterialIcons'); - - /// join_inner — material icon named "join inner" (round). - static const IconData join_inner_rounded = IconData(0xf033e, fontFamily: 'MaterialIcons'); - - /// join_inner — material icon named "join inner" (outlined). - static const IconData join_inner_outlined = IconData(0xf061f, fontFamily: 'MaterialIcons'); - - /// join_left — material icon named "join left". - static const IconData join_left = IconData(0xf0528, fontFamily: 'MaterialIcons'); - - /// join_left — material icon named "join left" (sharp). - static const IconData join_left_sharp = IconData(0xf0432, fontFamily: 'MaterialIcons'); - - /// join_left — material icon named "join left" (round). - static const IconData join_left_rounded = IconData(0xf033f, fontFamily: 'MaterialIcons'); - - /// join_left — material icon named "join left" (outlined). - static const IconData join_left_outlined = IconData(0xf0620, fontFamily: 'MaterialIcons'); - - /// join_right — material icon named "join right". - static const IconData join_right = IconData(0xf0529, fontFamily: 'MaterialIcons'); - - /// join_right — material icon named "join right" (sharp). - static const IconData join_right_sharp = IconData(0xf0433, fontFamily: 'MaterialIcons'); - - /// join_right — material icon named "join right" (round). - static const IconData join_right_rounded = IconData(0xf0340, fontFamily: 'MaterialIcons'); - - /// join_right — material icon named "join right" (outlined). - static const IconData join_right_outlined = IconData(0xf0621, fontFamily: 'MaterialIcons'); - /// kayaking — material icon named "kayaking". static const IconData kayaking = IconData(0xe350, fontFamily: 'MaterialIcons'); @@ -11936,42 +10503,6 @@ class Icons { /// kayaking — material icon named "kayaking" (outlined). static const IconData kayaking_outlined = IconData(0xf13b, fontFamily: 'MaterialIcons'); - /// kebab_dining — material icon named "kebab dining". - static const IconData kebab_dining = IconData(0xf052a, fontFamily: 'MaterialIcons'); - - /// kebab_dining — material icon named "kebab dining" (sharp). - static const IconData kebab_dining_sharp = IconData(0xf0434, fontFamily: 'MaterialIcons'); - - /// kebab_dining — material icon named "kebab dining" (round). - static const IconData kebab_dining_rounded = IconData(0xf0341, fontFamily: 'MaterialIcons'); - - /// kebab_dining — material icon named "kebab dining" (outlined). - static const IconData kebab_dining_outlined = IconData(0xf0622, fontFamily: 'MaterialIcons'); - - /// key — material icon named "key". - static const IconData key = IconData(0xf052b, fontFamily: 'MaterialIcons'); - - /// key — material icon named "key" (sharp). - static const IconData key_sharp = IconData(0xf0436, fontFamily: 'MaterialIcons'); - - /// key — material icon named "key" (round). - static const IconData key_rounded = IconData(0xf0343, fontFamily: 'MaterialIcons'); - - /// key — material icon named "key" (outlined). - static const IconData key_outlined = IconData(0xf0624, fontFamily: 'MaterialIcons'); - - /// key_off — material icon named "key off". - static const IconData key_off = IconData(0xf052c, fontFamily: 'MaterialIcons'); - - /// key_off — material icon named "key off" (sharp). - static const IconData key_off_sharp = IconData(0xf0435, fontFamily: 'MaterialIcons'); - - /// key_off — material icon named "key off" (round). - static const IconData key_off_rounded = IconData(0xf0342, fontFamily: 'MaterialIcons'); - - /// key_off — material icon named "key off" (outlined). - static const IconData key_off_outlined = IconData(0xf0623, fontFamily: 'MaterialIcons'); - /// keyboard — material icon named "keyboard". static const IconData keyboard = IconData(0xe351, fontFamily: 'MaterialIcons'); @@ -12068,18 +10599,6 @@ class Icons { /// keyboard_capslock — material icon named "keyboard capslock" (outlined). static const IconData keyboard_capslock_outlined = IconData(0xf142, fontFamily: 'MaterialIcons'); - /// keyboard_command_key — material icon named "keyboard command key". - static const IconData keyboard_command_key = IconData(0xf052d, fontFamily: 'MaterialIcons'); - - /// keyboard_command_key — material icon named "keyboard command key" (sharp). - static const IconData keyboard_command_key_sharp = IconData(0xf0437, fontFamily: 'MaterialIcons'); - - /// keyboard_command_key — material icon named "keyboard command key" (round). - static const IconData keyboard_command_key_rounded = IconData(0xf0344, fontFamily: 'MaterialIcons'); - - /// keyboard_command_key — material icon named "keyboard command key" (outlined). - static const IconData keyboard_command_key_outlined = IconData(0xf0625, fontFamily: 'MaterialIcons'); - /// keyboard_control — material icon named "keyboard control". static const IconData keyboard_control = IconData(0xe402, fontFamily: 'MaterialIcons'); @@ -12092,66 +10611,6 @@ class Icons { /// keyboard_control — material icon named "keyboard control" (outlined). static const IconData keyboard_control_outlined = IconData(0xf1e7, fontFamily: 'MaterialIcons'); - /// keyboard_control_key — material icon named "keyboard control key". - static const IconData keyboard_control_key = IconData(0xf052e, fontFamily: 'MaterialIcons'); - - /// keyboard_control_key — material icon named "keyboard control key" (sharp). - static const IconData keyboard_control_key_sharp = IconData(0xf0438, fontFamily: 'MaterialIcons'); - - /// keyboard_control_key — material icon named "keyboard control key" (round). - static const IconData keyboard_control_key_rounded = IconData(0xf0345, fontFamily: 'MaterialIcons'); - - /// keyboard_control_key — material icon named "keyboard control key" (outlined). - static const IconData keyboard_control_key_outlined = IconData(0xf0626, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_down — material icon named "keyboard double arrow down". - static const IconData keyboard_double_arrow_down = IconData(0xf052f, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_down — material icon named "keyboard double arrow down" (sharp). - static const IconData keyboard_double_arrow_down_sharp = IconData(0xf0439, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_down — material icon named "keyboard double arrow down" (round). - static const IconData keyboard_double_arrow_down_rounded = IconData(0xf0346, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_down — material icon named "keyboard double arrow down" (outlined). - static const IconData keyboard_double_arrow_down_outlined = IconData(0xf0627, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_left — material icon named "keyboard double arrow left". - static const IconData keyboard_double_arrow_left = IconData(0xf0530, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_left — material icon named "keyboard double arrow left" (sharp). - static const IconData keyboard_double_arrow_left_sharp = IconData(0xf043a, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_left — material icon named "keyboard double arrow left" (round). - static const IconData keyboard_double_arrow_left_rounded = IconData(0xf0347, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_left — material icon named "keyboard double arrow left" (outlined). - static const IconData keyboard_double_arrow_left_outlined = IconData(0xf0628, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_right — material icon named "keyboard double arrow right". - static const IconData keyboard_double_arrow_right = IconData(0xf0531, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_right — material icon named "keyboard double arrow right" (sharp). - static const IconData keyboard_double_arrow_right_sharp = IconData(0xf043b, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_right — material icon named "keyboard double arrow right" (round). - static const IconData keyboard_double_arrow_right_rounded = IconData(0xf0348, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_right — material icon named "keyboard double arrow right" (outlined). - static const IconData keyboard_double_arrow_right_outlined = IconData(0xf0629, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_up — material icon named "keyboard double arrow up". - static const IconData keyboard_double_arrow_up = IconData(0xf0532, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_up — material icon named "keyboard double arrow up" (sharp). - static const IconData keyboard_double_arrow_up_sharp = IconData(0xf043c, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_up — material icon named "keyboard double arrow up" (round). - static const IconData keyboard_double_arrow_up_rounded = IconData(0xf0349, fontFamily: 'MaterialIcons'); - - /// keyboard_double_arrow_up — material icon named "keyboard double arrow up" (outlined). - static const IconData keyboard_double_arrow_up_outlined = IconData(0xf062a, fontFamily: 'MaterialIcons'); - /// keyboard_hide — material icon named "keyboard hide". static const IconData keyboard_hide = IconData(0xe359, fontFamily: 'MaterialIcons'); @@ -12164,18 +10623,6 @@ class Icons { /// keyboard_hide — material icon named "keyboard hide" (outlined). static const IconData keyboard_hide_outlined = IconData(0xf143, fontFamily: 'MaterialIcons'); - /// keyboard_option_key — material icon named "keyboard option key". - static const IconData keyboard_option_key = IconData(0xf0533, fontFamily: 'MaterialIcons'); - - /// keyboard_option_key — material icon named "keyboard option key" (sharp). - static const IconData keyboard_option_key_sharp = IconData(0xf043d, fontFamily: 'MaterialIcons'); - - /// keyboard_option_key — material icon named "keyboard option key" (round). - static const IconData keyboard_option_key_rounded = IconData(0xf034a, fontFamily: 'MaterialIcons'); - - /// keyboard_option_key — material icon named "keyboard option key" (outlined). - static const IconData keyboard_option_key_outlined = IconData(0xf062b, fontFamily: 'MaterialIcons'); - /// keyboard_return — material icon named "keyboard return". static const IconData keyboard_return = IconData(0xe35a, fontFamily: 'MaterialIcons'); @@ -12302,18 +10749,6 @@ class Icons { /// label_outline — material icon named "label outline" (round). static const IconData label_outline_rounded = IconData(0xf83c, fontFamily: 'MaterialIcons', matchTextDirection: true); - /// lan — material icon named "lan". - static const IconData lan = IconData(0xf0534, fontFamily: 'MaterialIcons'); - - /// lan — material icon named "lan" (sharp). - static const IconData lan_sharp = IconData(0xf043e, fontFamily: 'MaterialIcons'); - - /// lan — material icon named "lan" (round). - static const IconData lan_rounded = IconData(0xf034b, fontFamily: 'MaterialIcons'); - - /// lan — material icon named "lan" (outlined). - static const IconData lan_outlined = IconData(0xf062c, fontFamily: 'MaterialIcons'); - /// landscape — material icon named "landscape". static const IconData landscape = IconData(0xe365, fontFamily: 'MaterialIcons'); @@ -12611,18 +11046,6 @@ class Icons { /// lightbulb_outline — material icon named "lightbulb outline" (round). static const IconData lightbulb_outline_rounded = IconData(0xf854, fontFamily: 'MaterialIcons'); - /// line_axis — material icon named "line axis". - static const IconData line_axis = IconData(0xf0535, fontFamily: 'MaterialIcons'); - - /// line_axis — material icon named "line axis" (sharp). - static const IconData line_axis_sharp = IconData(0xf043f, fontFamily: 'MaterialIcons'); - - /// line_axis — material icon named "line axis" (round). - static const IconData line_axis_rounded = IconData(0xf034c, fontFamily: 'MaterialIcons'); - - /// line_axis — material icon named "line axis" (outlined). - static const IconData line_axis_outlined = IconData(0xf062d, fontFamily: 'MaterialIcons'); - /// line_style — material icon named "line style". static const IconData line_style = IconData(0xe37d, fontFamily: 'MaterialIcons'); @@ -13295,18 +11718,6 @@ class Icons { /// lock_outline — material icon named "lock outline" (round). static const IconData lock_outline_rounded = IconData(0xf888, fontFamily: 'MaterialIcons'); - /// lock_reset — material icon named "lock reset". - static const IconData lock_reset = IconData(0xf0536, fontFamily: 'MaterialIcons'); - - /// lock_reset — material icon named "lock reset" (sharp). - static const IconData lock_reset_sharp = IconData(0xf0440, fontFamily: 'MaterialIcons'); - - /// lock_reset — material icon named "lock reset" (round). - static const IconData lock_reset_rounded = IconData(0xf034d, fontFamily: 'MaterialIcons'); - - /// lock_reset — material icon named "lock reset" (outlined). - static const IconData lock_reset_outlined = IconData(0xf062e, fontFamily: 'MaterialIcons'); - /// login — material icon named "login". static const IconData login = IconData(0xe3b2, fontFamily: 'MaterialIcons'); @@ -13319,18 +11730,6 @@ class Icons { /// login — material icon named "login" (outlined). static const IconData login_outlined = IconData(0xf198, fontFamily: 'MaterialIcons'); - /// logo_dev — material icon named "logo dev". - static const IconData logo_dev = IconData(0xf0537, fontFamily: 'MaterialIcons'); - - /// logo_dev — material icon named "logo dev" (sharp). - static const IconData logo_dev_sharp = IconData(0xf0441, fontFamily: 'MaterialIcons'); - - /// logo_dev — material icon named "logo dev" (round). - static const IconData logo_dev_rounded = IconData(0xf034e, fontFamily: 'MaterialIcons'); - - /// logo_dev — material icon named "logo dev" (outlined). - static const IconData logo_dev_outlined = IconData(0xf062f, fontFamily: 'MaterialIcons'); - /// logout — material icon named "logout". static const IconData logout = IconData(0xe3b3, fontFamily: 'MaterialIcons'); @@ -13559,18 +11958,6 @@ class Icons { /// male — material icon named "male" (outlined). static const IconData male_outlined = IconData(0xf1ab, fontFamily: 'MaterialIcons'); - /// man — material icon named "man". - static const IconData man = IconData(0xf0538, fontFamily: 'MaterialIcons'); - - /// man — material icon named "man" (sharp). - static const IconData man_sharp = IconData(0xf0442, fontFamily: 'MaterialIcons'); - - /// man — material icon named "man" (round). - static const IconData man_rounded = IconData(0xf034f, fontFamily: 'MaterialIcons'); - - /// man — material icon named "man" (outlined). - static const IconData man_outlined = IconData(0xf0630, fontFamily: 'MaterialIcons'); - /// manage_accounts — material icon named "manage accounts". static const IconData manage_accounts = IconData(0xe3c6, fontFamily: 'MaterialIcons'); @@ -13703,18 +12090,6 @@ class Icons { /// mark_email_unread — material icon named "mark email unread" (outlined). static const IconData mark_email_unread_outlined = IconData(0xf1b6, fontFamily: 'MaterialIcons'); - /// mark_unread_chat_alt — material icon named "mark unread chat alt". - static const IconData mark_unread_chat_alt = IconData(0xf0539, fontFamily: 'MaterialIcons'); - - /// mark_unread_chat_alt — material icon named "mark unread chat alt" (sharp). - static const IconData mark_unread_chat_alt_sharp = IconData(0xf0443, fontFamily: 'MaterialIcons'); - - /// mark_unread_chat_alt — material icon named "mark unread chat alt" (round). - static const IconData mark_unread_chat_alt_rounded = IconData(0xf0350, fontFamily: 'MaterialIcons'); - - /// mark_unread_chat_alt — material icon named "mark unread chat alt" (outlined). - static const IconData mark_unread_chat_alt_outlined = IconData(0xf0631, fontFamily: 'MaterialIcons'); - /// markunread — material icon named "markunread". static const IconData markunread = IconData(0xe3d1, fontFamily: 'MaterialIcons'); @@ -13823,18 +12198,6 @@ class Icons { /// medication — material icon named "medication" (outlined). static const IconData medication_outlined = IconData(0xf1bf, fontFamily: 'MaterialIcons'); - /// medication_liquid — material icon named "medication liquid". - static const IconData medication_liquid = IconData(0xf053a, fontFamily: 'MaterialIcons'); - - /// medication_liquid — material icon named "medication liquid" (sharp). - static const IconData medication_liquid_sharp = IconData(0xf0444, fontFamily: 'MaterialIcons'); - - /// medication_liquid — material icon named "medication liquid" (round). - static const IconData medication_liquid_rounded = IconData(0xf0351, fontFamily: 'MaterialIcons'); - - /// medication_liquid — material icon named "medication liquid" (outlined). - static const IconData medication_liquid_outlined = IconData(0xf0632, fontFamily: 'MaterialIcons'); - /// meeting_room — material icon named "meeting room". static const IconData meeting_room = IconData(0xe3da, fontFamily: 'MaterialIcons'); @@ -13895,18 +12258,6 @@ class Icons { /// menu_open — material icon named "menu open" (outlined). static const IconData menu_open_outlined = IconData(0xf1c3, fontFamily: 'MaterialIcons'); - /// merge — material icon named "merge". - static const IconData merge = IconData(0xf053b, fontFamily: 'MaterialIcons'); - - /// merge — material icon named "merge" (sharp). - static const IconData merge_sharp = IconData(0xf0445, fontFamily: 'MaterialIcons'); - - /// merge — material icon named "merge" (round). - static const IconData merge_rounded = IconData(0xf0352, fontFamily: 'MaterialIcons'); - - /// merge — material icon named "merge" (outlined). - static const IconData merge_outlined = IconData(0xf0633, fontFamily: 'MaterialIcons'); - /// merge_type — material icon named "merge type". static const IconData merge_type = IconData(0xe3df, fontFamily: 'MaterialIcons'); @@ -14195,18 +12546,6 @@ class Icons { /// mode_night — material icon named "mode night" (outlined). static const IconData mode_night_outlined = IconData(0xf1d9, fontFamily: 'MaterialIcons'); - /// mode_of_travel — material icon named "mode of travel". - static const IconData mode_of_travel = IconData(0xf053c, fontFamily: 'MaterialIcons'); - - /// mode_of_travel — material icon named "mode of travel" (sharp). - static const IconData mode_of_travel_sharp = IconData(0xf0446, fontFamily: 'MaterialIcons'); - - /// mode_of_travel — material icon named "mode of travel" (round). - static const IconData mode_of_travel_rounded = IconData(0xf0353, fontFamily: 'MaterialIcons'); - - /// mode_of_travel — material icon named "mode of travel" (outlined). - static const IconData mode_of_travel_outlined = IconData(0xf0634, fontFamily: 'MaterialIcons'); - /// mode_standby — material icon named "mode standby". static const IconData mode_standby = IconData(0xe3f5, fontFamily: 'MaterialIcons'); @@ -14291,18 +12630,6 @@ class Icons { /// monitor — material icon named "monitor" (outlined). static const IconData monitor_outlined = IconData(0xf1e1, fontFamily: 'MaterialIcons'); - /// monitor_heart — material icon named "monitor heart". - static const IconData monitor_heart = IconData(0xf053d, fontFamily: 'MaterialIcons'); - - /// monitor_heart — material icon named "monitor heart" (sharp). - static const IconData monitor_heart_sharp = IconData(0xf0447, fontFamily: 'MaterialIcons'); - - /// monitor_heart — material icon named "monitor heart" (round). - static const IconData monitor_heart_rounded = IconData(0xf0354, fontFamily: 'MaterialIcons'); - - /// monitor_heart — material icon named "monitor heart" (outlined). - static const IconData monitor_heart_outlined = IconData(0xf0635, fontFamily: 'MaterialIcons'); - /// monitor_weight — material icon named "monitor weight". static const IconData monitor_weight = IconData(0xe3fc, fontFamily: 'MaterialIcons'); @@ -14411,18 +12738,6 @@ class Icons { /// more_vert — material icon named "more vert" (outlined). static const IconData more_vert_outlined = IconData(0xf1ea, fontFamily: 'MaterialIcons'); - /// mosque — material icon named "mosque". - static const IconData mosque = IconData(0xf053e, fontFamily: 'MaterialIcons'); - - /// mosque — material icon named "mosque" (sharp). - static const IconData mosque_sharp = IconData(0xf0448, fontFamily: 'MaterialIcons'); - - /// mosque — material icon named "mosque" (round). - static const IconData mosque_rounded = IconData(0xf0355, fontFamily: 'MaterialIcons'); - - /// mosque — material icon named "mosque" (outlined). - static const IconData mosque_outlined = IconData(0xf0636, fontFamily: 'MaterialIcons'); - /// motion_photos_auto — material icon named "motion photos auto". static const IconData motion_photos_auto = IconData(0xe405, fontFamily: 'MaterialIcons'); @@ -14507,18 +12822,6 @@ class Icons { /// mouse — material icon named "mouse" (outlined). static const IconData mouse_outlined = IconData(0xf1f1, fontFamily: 'MaterialIcons'); - /// move_down — material icon named "move down". - static const IconData move_down = IconData(0xf053f, fontFamily: 'MaterialIcons'); - - /// move_down — material icon named "move down" (sharp). - static const IconData move_down_sharp = IconData(0xf0449, fontFamily: 'MaterialIcons'); - - /// move_down — material icon named "move down" (round). - static const IconData move_down_rounded = IconData(0xf0356, fontFamily: 'MaterialIcons'); - - /// move_down — material icon named "move down" (outlined). - static const IconData move_down_outlined = IconData(0xf0637, fontFamily: 'MaterialIcons'); - /// move_to_inbox — material icon named "move to inbox". static const IconData move_to_inbox = IconData(0xe40c, fontFamily: 'MaterialIcons'); @@ -14531,18 +12834,6 @@ class Icons { /// move_to_inbox — material icon named "move to inbox" (outlined). static const IconData move_to_inbox_outlined = IconData(0xf1f2, fontFamily: 'MaterialIcons'); - /// move_up — material icon named "move up". - static const IconData move_up = IconData(0xf0540, fontFamily: 'MaterialIcons'); - - /// move_up — material icon named "move up" (sharp). - static const IconData move_up_sharp = IconData(0xf044a, fontFamily: 'MaterialIcons'); - - /// move_up — material icon named "move up" (round). - static const IconData move_up_rounded = IconData(0xf0357, fontFamily: 'MaterialIcons'); - - /// move_up — material icon named "move up" (outlined). - static const IconData move_up_outlined = IconData(0xf0638, fontFamily: 'MaterialIcons'); - /// movie — material icon named "movie". static const IconData movie = IconData(0xe40d, fontFamily: 'MaterialIcons'); @@ -14891,18 +13182,6 @@ class Icons { /// network_locked — material icon named "network locked" (outlined). static const IconData network_locked_outlined = IconData(0xf20b, fontFamily: 'MaterialIcons'); - /// network_ping — material icon named "network ping". - static const IconData network_ping = IconData(0xf06bf, fontFamily: 'MaterialIcons'); - - /// network_ping — material icon named "network ping" (sharp). - static const IconData network_ping_sharp = IconData(0xf06b2, fontFamily: 'MaterialIcons'); - - /// network_ping — material icon named "network ping" (round). - static const IconData network_ping_rounded = IconData(0xf06cc, fontFamily: 'MaterialIcons'); - - /// network_ping — material icon named "network ping" (outlined). - static const IconData network_ping_outlined = IconData(0xf06a5, fontFamily: 'MaterialIcons'); - /// network_wifi — material icon named "network wifi". static const IconData network_wifi = IconData(0xe426, fontFamily: 'MaterialIcons'); @@ -14939,18 +13218,6 @@ class Icons { /// new_releases — material icon named "new releases" (outlined). static const IconData new_releases_outlined = IconData(0xf20e, fontFamily: 'MaterialIcons'); - /// newspaper — material icon named "newspaper". - static const IconData newspaper = IconData(0xf0541, fontFamily: 'MaterialIcons'); - - /// newspaper — material icon named "newspaper" (sharp). - static const IconData newspaper_sharp = IconData(0xf044b, fontFamily: 'MaterialIcons'); - - /// newspaper — material icon named "newspaper" (round). - static const IconData newspaper_rounded = IconData(0xf0358, fontFamily: 'MaterialIcons'); - - /// newspaper — material icon named "newspaper" (outlined). - static const IconData newspaper_outlined = IconData(0xf0639, fontFamily: 'MaterialIcons'); - /// next_plan — material icon named "next plan". static const IconData next_plan = IconData(0xe429, fontFamily: 'MaterialIcons'); @@ -15494,18 +13761,6 @@ class Icons { /// now_widgets — material icon named "now widgets" (outlined). static const IconData now_widgets_outlined = IconData(0xf4c7, fontFamily: 'MaterialIcons'); - /// numbers — material icon named "numbers". - static const IconData numbers = IconData(0xf0542, fontFamily: 'MaterialIcons'); - - /// numbers — material icon named "numbers" (sharp). - static const IconData numbers_sharp = IconData(0xf044c, fontFamily: 'MaterialIcons'); - - /// numbers — material icon named "numbers" (round). - static const IconData numbers_rounded = IconData(0xf0359, fontFamily: 'MaterialIcons'); - - /// numbers — material icon named "numbers" (outlined). - static const IconData numbers_outlined = IconData(0xf063a, fontFamily: 'MaterialIcons'); - /// offline_bolt — material icon named "offline bolt". static const IconData offline_bolt = IconData(0xe454, fontFamily: 'MaterialIcons'); @@ -15725,18 +13980,6 @@ class Icons { /// outlined_flag — material icon named "outlined flag" (outlined). static const IconData outlined_flag_outlined = IconData(0xf24a, fontFamily: 'MaterialIcons'); - /// output — material icon named "output". - static const IconData output = IconData(0xf0543, fontFamily: 'MaterialIcons'); - - /// output — material icon named "output" (sharp). - static const IconData output_sharp = IconData(0xf044d, fontFamily: 'MaterialIcons'); - - /// output — material icon named "output" (round). - static const IconData output_rounded = IconData(0xf035a, fontFamily: 'MaterialIcons'); - - /// output — material icon named "output" (outlined). - static const IconData output_outlined = IconData(0xf063b, fontFamily: 'MaterialIcons'); - /// padding — material icon named "padding". static const IconData padding = IconData(0xe467, fontFamily: 'MaterialIcons'); @@ -15809,18 +14052,6 @@ class Icons { /// pan_tool — material icon named "pan tool" (outlined). static const IconData pan_tool_outlined = IconData(0xf250, fontFamily: 'MaterialIcons'); - /// pan_tool_alt — material icon named "pan tool alt". - static const IconData pan_tool_alt = IconData(0xf0544, fontFamily: 'MaterialIcons'); - - /// pan_tool_alt — material icon named "pan tool alt" (sharp). - static const IconData pan_tool_alt_sharp = IconData(0xf044e, fontFamily: 'MaterialIcons'); - - /// pan_tool_alt — material icon named "pan tool alt" (round). - static const IconData pan_tool_alt_rounded = IconData(0xf035b, fontFamily: 'MaterialIcons'); - - /// pan_tool_alt — material icon named "pan tool alt" (outlined). - static const IconData pan_tool_alt_outlined = IconData(0xf063c, fontFamily: 'MaterialIcons'); - /// panorama — material icon named "panorama". static const IconData panorama = IconData(0xe46d, fontFamily: 'MaterialIcons'); @@ -16109,18 +14340,6 @@ class Icons { /// payments — material icon named "payments" (outlined). static const IconData payments_outlined = IconData(0xf266, fontFamily: 'MaterialIcons'); - /// paypal — material icon named "paypal". - static const IconData paypal = IconData(0xf0545, fontFamily: 'MaterialIcons'); - - /// paypal — material icon named "paypal" (sharp). - static const IconData paypal_sharp = IconData(0xf044f, fontFamily: 'MaterialIcons'); - - /// paypal — material icon named "paypal" (round). - static const IconData paypal_rounded = IconData(0xf035c, fontFamily: 'MaterialIcons'); - - /// paypal — material icon named "paypal" (outlined). - static const IconData paypal_outlined = IconData(0xf063d, fontFamily: 'MaterialIcons'); - /// pedal_bike — material icon named "pedal bike". static const IconData pedal_bike = IconData(0xe483, fontFamily: 'MaterialIcons'); @@ -16157,18 +14376,6 @@ class Icons { /// pending_actions — material icon named "pending actions" (outlined). static const IconData pending_actions_outlined = IconData(0xf268, fontFamily: 'MaterialIcons'); - /// pentagon — material icon named "pentagon". - static const IconData pentagon = IconData(0xf0546, fontFamily: 'MaterialIcons'); - - /// pentagon — material icon named "pentagon" (sharp). - static const IconData pentagon_sharp = IconData(0xf0450, fontFamily: 'MaterialIcons'); - - /// pentagon — material icon named "pentagon" (round). - static const IconData pentagon_rounded = IconData(0xf035d, fontFamily: 'MaterialIcons'); - - /// pentagon — material icon named "pentagon" (outlined). - static const IconData pentagon_outlined = IconData(0xf063e, fontFamily: 'MaterialIcons'); - /// people — material icon named "people". static const IconData people = IconData(0xe486, fontFamily: 'MaterialIcons'); @@ -16205,18 +14412,6 @@ class Icons { /// people_outline — material icon named "people outline" (outlined). static const IconData people_outline_outlined = IconData(0xf26b, fontFamily: 'MaterialIcons'); - /// percent — material icon named "percent". - static const IconData percent = IconData(0xf0547, fontFamily: 'MaterialIcons'); - - /// percent — material icon named "percent" (sharp). - static const IconData percent_sharp = IconData(0xf0451, fontFamily: 'MaterialIcons'); - - /// percent — material icon named "percent" (round). - static const IconData percent_rounded = IconData(0xf035e, fontFamily: 'MaterialIcons'); - - /// percent — material icon named "percent" (outlined). - static const IconData percent_outlined = IconData(0xf063f, fontFamily: 'MaterialIcons'); - /// perm_camera_mic — material icon named "perm camera mic". static const IconData perm_camera_mic = IconData(0xe489, fontFamily: 'MaterialIcons'); @@ -16541,18 +14736,6 @@ class Icons { /// pets — material icon named "pets" (outlined). static const IconData pets_outlined = IconData(0xf285, fontFamily: 'MaterialIcons'); - /// phishing — material icon named "phishing". - static const IconData phishing = IconData(0xf0548, fontFamily: 'MaterialIcons'); - - /// phishing — material icon named "phishing" (sharp). - static const IconData phishing_sharp = IconData(0xf0452, fontFamily: 'MaterialIcons'); - - /// phishing — material icon named "phishing" (round). - static const IconData phishing_rounded = IconData(0xf035f, fontFamily: 'MaterialIcons'); - - /// phishing — material icon named "phishing" (outlined). - static const IconData phishing_outlined = IconData(0xf0640, fontFamily: 'MaterialIcons'); - /// phone — material icon named "phone". static const IconData phone = IconData(0xe4a2, fontFamily: 'MaterialIcons'); @@ -16889,18 +15072,6 @@ class Icons { /// photo_size_select_small — material icon named "photo size select small" (outlined). static const IconData photo_size_select_small_outlined = IconData(0xf2a1, fontFamily: 'MaterialIcons'); - /// php — material icon named "php". - static const IconData php = IconData(0xf0549, fontFamily: 'MaterialIcons'); - - /// php — material icon named "php" (sharp). - static const IconData php_sharp = IconData(0xf0453, fontFamily: 'MaterialIcons'); - - /// php — material icon named "php" (round). - static const IconData php_rounded = IconData(0xf0360, fontFamily: 'MaterialIcons'); - - /// php — material icon named "php" (outlined). - static const IconData php_outlined = IconData(0xf0641, fontFamily: 'MaterialIcons'); - /// piano — material icon named "piano". static const IconData piano = IconData(0xe4be, fontFamily: 'MaterialIcons'); @@ -16970,6 +15141,9 @@ class Icons { /// pie_chart — material icon named "pie chart" (round). static const IconData pie_chart_rounded = IconData(0xf009a, fontFamily: 'MaterialIcons'); + /// pie_chart — material icon named "pie chart" (outlined). + static const IconData pie_chart_outlined = IconData(0xf2a8, fontFamily: 'MaterialIcons'); + /// pie_chart_outline — material icon named "pie chart outline". static const IconData pie_chart_outline = IconData(0xe4c5, fontFamily: 'MaterialIcons'); @@ -17006,42 +15180,6 @@ class Icons { /// pin_drop — material icon named "pin drop" (outlined). static const IconData pin_drop_outlined = IconData(0xf2a9, fontFamily: 'MaterialIcons'); - /// pin_end — material icon named "pin end". - static const IconData pin_end = IconData(0xf054b, fontFamily: 'MaterialIcons'); - - /// pin_end — material icon named "pin end" (sharp). - static const IconData pin_end_sharp = IconData(0xf0454, fontFamily: 'MaterialIcons'); - - /// pin_end — material icon named "pin end" (round). - static const IconData pin_end_rounded = IconData(0xf0361, fontFamily: 'MaterialIcons'); - - /// pin_end — material icon named "pin end" (outlined). - static const IconData pin_end_outlined = IconData(0xf0642, fontFamily: 'MaterialIcons'); - - /// pin_invoke — material icon named "pin invoke". - static const IconData pin_invoke = IconData(0xf054c, fontFamily: 'MaterialIcons'); - - /// pin_invoke — material icon named "pin invoke" (sharp). - static const IconData pin_invoke_sharp = IconData(0xf0455, fontFamily: 'MaterialIcons'); - - /// pin_invoke — material icon named "pin invoke" (round). - static const IconData pin_invoke_rounded = IconData(0xf0362, fontFamily: 'MaterialIcons'); - - /// pin_invoke — material icon named "pin invoke" (outlined). - static const IconData pin_invoke_outlined = IconData(0xf0643, fontFamily: 'MaterialIcons'); - - /// pinch — material icon named "pinch". - static const IconData pinch = IconData(0xf054d, fontFamily: 'MaterialIcons'); - - /// pinch — material icon named "pinch" (sharp). - static const IconData pinch_sharp = IconData(0xf0456, fontFamily: 'MaterialIcons'); - - /// pinch — material icon named "pinch" (round). - static const IconData pinch_rounded = IconData(0xf0363, fontFamily: 'MaterialIcons'); - - /// pinch — material icon named "pinch" (outlined). - static const IconData pinch_outlined = IconData(0xf0644, fontFamily: 'MaterialIcons'); - /// pivot_table_chart — material icon named "pivot table chart". static const IconData pivot_table_chart = IconData(0xe4c8, fontFamily: 'MaterialIcons'); @@ -17054,18 +15192,6 @@ class Icons { /// pivot_table_chart — material icon named "pivot table chart" (outlined). static const IconData pivot_table_chart_outlined = IconData(0xf2ab, fontFamily: 'MaterialIcons'); - /// pix — material icon named "pix". - static const IconData pix = IconData(0xf054e, fontFamily: 'MaterialIcons'); - - /// pix — material icon named "pix" (sharp). - static const IconData pix_sharp = IconData(0xf0457, fontFamily: 'MaterialIcons'); - - /// pix — material icon named "pix" (round). - static const IconData pix_rounded = IconData(0xf0364, fontFamily: 'MaterialIcons'); - - /// pix — material icon named "pix" (outlined). - static const IconData pix_outlined = IconData(0xf0645, fontFamily: 'MaterialIcons'); - /// place — material icon named "place". static const IconData place = IconData(0xe4c9, fontFamily: 'MaterialIcons'); @@ -17210,30 +15336,6 @@ class Icons { /// playlist_add_check — material icon named "playlist add check" (outlined). static const IconData playlist_add_check_outlined = IconData(0xf2b5, fontFamily: 'MaterialIcons'); - /// playlist_add_check_circle — material icon named "playlist add check circle". - static const IconData playlist_add_check_circle = IconData(0xf054f, fontFamily: 'MaterialIcons'); - - /// playlist_add_check_circle — material icon named "playlist add check circle" (sharp). - static const IconData playlist_add_check_circle_sharp = IconData(0xf0458, fontFamily: 'MaterialIcons'); - - /// playlist_add_check_circle — material icon named "playlist add check circle" (round). - static const IconData playlist_add_check_circle_rounded = IconData(0xf0365, fontFamily: 'MaterialIcons'); - - /// playlist_add_check_circle — material icon named "playlist add check circle" (outlined). - static const IconData playlist_add_check_circle_outlined = IconData(0xf0646, fontFamily: 'MaterialIcons'); - - /// playlist_add_circle — material icon named "playlist add circle". - static const IconData playlist_add_circle = IconData(0xf0550, fontFamily: 'MaterialIcons'); - - /// playlist_add_circle — material icon named "playlist add circle" (sharp). - static const IconData playlist_add_circle_sharp = IconData(0xf0459, fontFamily: 'MaterialIcons'); - - /// playlist_add_circle — material icon named "playlist add circle" (round). - static const IconData playlist_add_circle_rounded = IconData(0xf0366, fontFamily: 'MaterialIcons'); - - /// playlist_add_circle — material icon named "playlist add circle" (outlined). - static const IconData playlist_add_circle_outlined = IconData(0xf0647, fontFamily: 'MaterialIcons'); - /// playlist_play — material icon named "playlist play". static const IconData playlist_play = IconData(0xe4d4, fontFamily: 'MaterialIcons'); @@ -17246,18 +15348,6 @@ class Icons { /// playlist_play — material icon named "playlist play" (outlined). static const IconData playlist_play_outlined = IconData(0xf2b7, fontFamily: 'MaterialIcons'); - /// playlist_remove — material icon named "playlist remove". - static const IconData playlist_remove = IconData(0xf0551, fontFamily: 'MaterialIcons'); - - /// playlist_remove — material icon named "playlist remove" (sharp). - static const IconData playlist_remove_sharp = IconData(0xf045a, fontFamily: 'MaterialIcons'); - - /// playlist_remove — material icon named "playlist remove" (round). - static const IconData playlist_remove_rounded = IconData(0xf0367, fontFamily: 'MaterialIcons'); - - /// playlist_remove — material icon named "playlist remove" (outlined). - static const IconData playlist_remove_outlined = IconData(0xf0648, fontFamily: 'MaterialIcons'); - /// plumbing — material icon named "plumbing". static const IconData plumbing = IconData(0xe4d5, fontFamily: 'MaterialIcons'); @@ -17330,18 +15420,6 @@ class Icons { /// poll — material icon named "poll" (outlined). static const IconData poll_outlined = IconData(0xf2bd, fontFamily: 'MaterialIcons'); - /// polyline — material icon named "polyline". - static const IconData polyline = IconData(0xf0552, fontFamily: 'MaterialIcons'); - - /// polyline — material icon named "polyline" (sharp). - static const IconData polyline_sharp = IconData(0xf045b, fontFamily: 'MaterialIcons'); - - /// polyline — material icon named "polyline" (round). - static const IconData polyline_rounded = IconData(0xf0368, fontFamily: 'MaterialIcons'); - - /// polyline — material icon named "polyline" (outlined). - static const IconData polyline_outlined = IconData(0xf0649, fontFamily: 'MaterialIcons'); - /// polymer — material icon named "polymer". static const IconData polymer = IconData(0xe4db, fontFamily: 'MaterialIcons'); @@ -17570,18 +15648,6 @@ class Icons { /// privacy_tip — material icon named "privacy tip" (outlined). static const IconData privacy_tip_outlined = IconData(0xf2d0, fontFamily: 'MaterialIcons'); - /// private_connectivity — material icon named "private connectivity". - static const IconData private_connectivity = IconData(0xf0553, fontFamily: 'MaterialIcons'); - - /// private_connectivity — material icon named "private connectivity" (sharp). - static const IconData private_connectivity_sharp = IconData(0xf045c, fontFamily: 'MaterialIcons'); - - /// private_connectivity — material icon named "private connectivity" (round). - static const IconData private_connectivity_rounded = IconData(0xf0369, fontFamily: 'MaterialIcons'); - - /// private_connectivity — material icon named "private connectivity" (outlined). - static const IconData private_connectivity_outlined = IconData(0xf064a, fontFamily: 'MaterialIcons'); - /// production_quantity_limits — material icon named "production quantity limits". static const IconData production_quantity_limits = IconData(0xe4ee, fontFamily: 'MaterialIcons'); @@ -17654,18 +15720,6 @@ class Icons { /// published_with_changes — material icon named "published with changes" (outlined). static const IconData published_with_changes_outlined = IconData(0xf2d6, fontFamily: 'MaterialIcons'); - /// punch_clock — material icon named "punch clock". - static const IconData punch_clock = IconData(0xf0554, fontFamily: 'MaterialIcons'); - - /// punch_clock — material icon named "punch clock" (sharp). - static const IconData punch_clock_sharp = IconData(0xf045d, fontFamily: 'MaterialIcons'); - - /// punch_clock — material icon named "punch clock" (round). - static const IconData punch_clock_rounded = IconData(0xf036a, fontFamily: 'MaterialIcons'); - - /// punch_clock — material icon named "punch clock" (outlined). - static const IconData punch_clock_outlined = IconData(0xf064b, fontFamily: 'MaterialIcons'); - /// push_pin — material icon named "push pin". static const IconData push_pin = IconData(0xe4f4, fontFamily: 'MaterialIcons'); @@ -17750,18 +15804,6 @@ class Icons { /// question_answer — material icon named "question answer" (outlined). static const IconData question_answer_outlined = IconData(0xf2dd, fontFamily: 'MaterialIcons'); - /// question_mark — material icon named "question mark". - static const IconData question_mark = IconData(0xf0555, fontFamily: 'MaterialIcons'); - - /// question_mark — material icon named "question mark" (sharp). - static const IconData question_mark_sharp = IconData(0xf045e, fontFamily: 'MaterialIcons'); - - /// question_mark — material icon named "question mark" (round). - static const IconData question_mark_rounded = IconData(0xf036b, fontFamily: 'MaterialIcons'); - - /// question_mark — material icon named "question mark" (outlined). - static const IconData question_mark_outlined = IconData(0xf064c, fontFamily: 'MaterialIcons'); - /// queue — material icon named "queue". static const IconData queue = IconData(0xe4fb, fontFamily: 'MaterialIcons'); @@ -17846,18 +15888,6 @@ class Icons { /// quiz — material icon named "quiz" (outlined). static const IconData quiz_outlined = IconData(0xf2e2, fontFamily: 'MaterialIcons'); - /// quora — material icon named "quora". - static const IconData quora = IconData(0xf0556, fontFamily: 'MaterialIcons'); - - /// quora — material icon named "quora" (sharp). - static const IconData quora_sharp = IconData(0xf045f, fontFamily: 'MaterialIcons'); - - /// quora — material icon named "quora" (round). - static const IconData quora_rounded = IconData(0xf036c, fontFamily: 'MaterialIcons'); - - /// quora — material icon named "quora" (outlined). - static const IconData quora_outlined = IconData(0xf064d, fontFamily: 'MaterialIcons'); - /// r_mobiledata — material icon named "r mobiledata". static const IconData r_mobiledata = IconData(0xe500, fontFamily: 'MaterialIcons'); @@ -17966,30 +15996,6 @@ class Icons { /// ramen_dining — material icon named "ramen dining" (outlined). static const IconData ramen_dining_outlined = IconData(0xf2e9, fontFamily: 'MaterialIcons'); - /// ramp_left — material icon named "ramp left". - static const IconData ramp_left = IconData(0xf0557, fontFamily: 'MaterialIcons'); - - /// ramp_left — material icon named "ramp left" (sharp). - static const IconData ramp_left_sharp = IconData(0xf0460, fontFamily: 'MaterialIcons'); - - /// ramp_left — material icon named "ramp left" (round). - static const IconData ramp_left_rounded = IconData(0xf036d, fontFamily: 'MaterialIcons'); - - /// ramp_left — material icon named "ramp left" (outlined). - static const IconData ramp_left_outlined = IconData(0xf064e, fontFamily: 'MaterialIcons'); - - /// ramp_right — material icon named "ramp right". - static const IconData ramp_right = IconData(0xf0558, fontFamily: 'MaterialIcons'); - - /// ramp_right — material icon named "ramp right" (sharp). - static const IconData ramp_right_sharp = IconData(0xf0461, fontFamily: 'MaterialIcons'); - - /// ramp_right — material icon named "ramp right" (round). - static const IconData ramp_right_rounded = IconData(0xf036e, fontFamily: 'MaterialIcons'); - - /// ramp_right — material icon named "ramp right" (outlined). - static const IconData ramp_right_outlined = IconData(0xf064f, fontFamily: 'MaterialIcons'); - /// rate_review — material icon named "rate review". static const IconData rate_review = IconData(0xe507, fontFamily: 'MaterialIcons'); @@ -18110,42 +16116,6 @@ class Icons { /// record_voice_over — material icon named "record voice over" (outlined). static const IconData record_voice_over_outlined = IconData(0xf2f3, fontFamily: 'MaterialIcons'); - /// rectangle — material icon named "rectangle". - static const IconData rectangle = IconData(0xf0559, fontFamily: 'MaterialIcons'); - - /// rectangle — material icon named "rectangle" (sharp). - static const IconData rectangle_sharp = IconData(0xf0462, fontFamily: 'MaterialIcons'); - - /// rectangle — material icon named "rectangle" (round). - static const IconData rectangle_rounded = IconData(0xf036f, fontFamily: 'MaterialIcons'); - - /// rectangle — material icon named "rectangle" (outlined). - static const IconData rectangle_outlined = IconData(0xf0650, fontFamily: 'MaterialIcons'); - - /// recycling — material icon named "recycling". - static const IconData recycling = IconData(0xf055a, fontFamily: 'MaterialIcons'); - - /// recycling — material icon named "recycling" (sharp). - static const IconData recycling_sharp = IconData(0xf0463, fontFamily: 'MaterialIcons'); - - /// recycling — material icon named "recycling" (round). - static const IconData recycling_rounded = IconData(0xf0370, fontFamily: 'MaterialIcons'); - - /// recycling — material icon named "recycling" (outlined). - static const IconData recycling_outlined = IconData(0xf0651, fontFamily: 'MaterialIcons'); - - /// reddit — material icon named "reddit". - static const IconData reddit = IconData(0xf055b, fontFamily: 'MaterialIcons'); - - /// reddit — material icon named "reddit" (sharp). - static const IconData reddit_sharp = IconData(0xf0464, fontFamily: 'MaterialIcons'); - - /// reddit — material icon named "reddit" (round). - static const IconData reddit_rounded = IconData(0xf0371, fontFamily: 'MaterialIcons'); - - /// reddit — material icon named "reddit" (outlined). - static const IconData reddit_outlined = IconData(0xf0652, fontFamily: 'MaterialIcons'); - /// redeem — material icon named "redeem". static const IconData redeem = IconData(0xe511, fontFamily: 'MaterialIcons'); @@ -18638,42 +16608,6 @@ class Icons { /// ring_volume — material icon named "ring volume" (outlined). static const IconData ring_volume_outlined = IconData(0xf31c, fontFamily: 'MaterialIcons'); - /// rocket — material icon named "rocket". - static const IconData rocket = IconData(0xf055c, fontFamily: 'MaterialIcons'); - - /// rocket — material icon named "rocket" (sharp). - static const IconData rocket_sharp = IconData(0xf0466, fontFamily: 'MaterialIcons'); - - /// rocket — material icon named "rocket" (round). - static const IconData rocket_rounded = IconData(0xf0373, fontFamily: 'MaterialIcons'); - - /// rocket — material icon named "rocket" (outlined). - static const IconData rocket_outlined = IconData(0xf0654, fontFamily: 'MaterialIcons'); - - /// rocket_launch — material icon named "rocket launch". - static const IconData rocket_launch = IconData(0xf055d, fontFamily: 'MaterialIcons'); - - /// rocket_launch — material icon named "rocket launch" (sharp). - static const IconData rocket_launch_sharp = IconData(0xf0465, fontFamily: 'MaterialIcons'); - - /// rocket_launch — material icon named "rocket launch" (round). - static const IconData rocket_launch_rounded = IconData(0xf0372, fontFamily: 'MaterialIcons'); - - /// rocket_launch — material icon named "rocket launch" (outlined). - static const IconData rocket_launch_outlined = IconData(0xf0653, fontFamily: 'MaterialIcons'); - - /// roller_skating — material icon named "roller skating". - static const IconData roller_skating = IconData(0xf06c0, fontFamily: 'MaterialIcons'); - - /// roller_skating — material icon named "roller skating" (sharp). - static const IconData roller_skating_sharp = IconData(0xf06b3, fontFamily: 'MaterialIcons'); - - /// roller_skating — material icon named "roller skating" (round). - static const IconData roller_skating_rounded = IconData(0xf06cd, fontFamily: 'MaterialIcons'); - - /// roller_skating — material icon named "roller skating" (outlined). - static const IconData roller_skating_outlined = IconData(0xf06a6, fontFamily: 'MaterialIcons'); - /// roofing — material icon named "roofing". static const IconData roofing = IconData(0xe53a, fontFamily: 'MaterialIcons'); @@ -18734,18 +16668,6 @@ class Icons { /// rotate_90_degrees_ccw — material icon named "rotate 90 degrees ccw" (outlined). static const IconData rotate_90_degrees_ccw_outlined = IconData(0xf321, fontFamily: 'MaterialIcons'); - /// rotate_90_degrees_cw — material icon named "rotate 90 degrees cw". - static const IconData rotate_90_degrees_cw = IconData(0xf055e, fontFamily: 'MaterialIcons'); - - /// rotate_90_degrees_cw — material icon named "rotate 90 degrees cw" (sharp). - static const IconData rotate_90_degrees_cw_sharp = IconData(0xf0467, fontFamily: 'MaterialIcons'); - - /// rotate_90_degrees_cw — material icon named "rotate 90 degrees cw" (round). - static const IconData rotate_90_degrees_cw_rounded = IconData(0xf0374, fontFamily: 'MaterialIcons'); - - /// rotate_90_degrees_cw — material icon named "rotate 90 degrees cw" (outlined). - static const IconData rotate_90_degrees_cw_outlined = IconData(0xf0655, fontFamily: 'MaterialIcons'); - /// rotate_left — material icon named "rotate left". static const IconData rotate_left = IconData(0xe53f, fontFamily: 'MaterialIcons'); @@ -18770,30 +16692,6 @@ class Icons { /// rotate_right — material icon named "rotate right" (outlined). static const IconData rotate_right_outlined = IconData(0xf323, fontFamily: 'MaterialIcons'); - /// roundabout_left — material icon named "roundabout left". - static const IconData roundabout_left = IconData(0xf055f, fontFamily: 'MaterialIcons'); - - /// roundabout_left — material icon named "roundabout left" (sharp). - static const IconData roundabout_left_sharp = IconData(0xf0468, fontFamily: 'MaterialIcons'); - - /// roundabout_left — material icon named "roundabout left" (round). - static const IconData roundabout_left_rounded = IconData(0xf0375, fontFamily: 'MaterialIcons'); - - /// roundabout_left — material icon named "roundabout left" (outlined). - static const IconData roundabout_left_outlined = IconData(0xf0656, fontFamily: 'MaterialIcons'); - - /// roundabout_right — material icon named "roundabout right". - static const IconData roundabout_right = IconData(0xf0560, fontFamily: 'MaterialIcons'); - - /// roundabout_right — material icon named "roundabout right" (sharp). - static const IconData roundabout_right_sharp = IconData(0xf0469, fontFamily: 'MaterialIcons'); - - /// roundabout_right — material icon named "roundabout right" (round). - static const IconData roundabout_right_rounded = IconData(0xf0376, fontFamily: 'MaterialIcons'); - - /// roundabout_right — material icon named "roundabout right" (outlined). - static const IconData roundabout_right_outlined = IconData(0xf0657, fontFamily: 'MaterialIcons'); - /// rounded_corner — material icon named "rounded corner". static const IconData rounded_corner = IconData(0xe541, fontFamily: 'MaterialIcons'); @@ -18806,18 +16704,6 @@ class Icons { /// rounded_corner — material icon named "rounded corner" (outlined). static const IconData rounded_corner_outlined = IconData(0xf324, fontFamily: 'MaterialIcons'); - /// route — material icon named "route". - static const IconData route = IconData(0xf0561, fontFamily: 'MaterialIcons'); - - /// route — material icon named "route" (sharp). - static const IconData route_sharp = IconData(0xf046a, fontFamily: 'MaterialIcons'); - - /// route — material icon named "route" (round). - static const IconData route_rounded = IconData(0xf0377, fontFamily: 'MaterialIcons'); - - /// route — material icon named "route" (outlined). - static const IconData route_outlined = IconData(0xf0658, fontFamily: 'MaterialIcons'); - /// router — material icon named "router". static const IconData router = IconData(0xe542, fontFamily: 'MaterialIcons'); @@ -18986,18 +16872,6 @@ class Icons { /// satellite — material icon named "satellite" (outlined). static const IconData satellite_outlined = IconData(0xf332, fontFamily: 'MaterialIcons'); - /// satellite_alt — material icon named "satellite alt". - static const IconData satellite_alt = IconData(0xf0562, fontFamily: 'MaterialIcons'); - - /// satellite_alt — material icon named "satellite alt" (sharp). - static const IconData satellite_alt_sharp = IconData(0xf046b, fontFamily: 'MaterialIcons'); - - /// satellite_alt — material icon named "satellite alt" (round). - static const IconData satellite_alt_rounded = IconData(0xf0378, fontFamily: 'MaterialIcons'); - - /// satellite_alt — material icon named "satellite alt" (outlined). - static const IconData satellite_alt_outlined = IconData(0xf0659, fontFamily: 'MaterialIcons'); - /// save — material icon named "save". static const IconData save = IconData(0xe550, fontFamily: 'MaterialIcons'); @@ -19022,18 +16896,6 @@ class Icons { /// save_alt — material icon named "save alt" (outlined). static const IconData save_alt_outlined = IconData(0xf333, fontFamily: 'MaterialIcons'); - /// save_as — material icon named "save as". - static const IconData save_as = IconData(0xf0563, fontFamily: 'MaterialIcons'); - - /// save_as — material icon named "save as" (sharp). - static const IconData save_as_sharp = IconData(0xf046c, fontFamily: 'MaterialIcons'); - - /// save_as — material icon named "save as" (round). - static const IconData save_as_rounded = IconData(0xf0379, fontFamily: 'MaterialIcons'); - - /// save_as — material icon named "save as" (outlined). - static const IconData save_as_outlined = IconData(0xf065a, fontFamily: 'MaterialIcons'); - /// saved_search — material icon named "saved search". static const IconData saved_search = IconData(0xe552, fontFamily: 'MaterialIcons'); @@ -19058,18 +16920,6 @@ class Icons { /// savings — material icon named "savings" (outlined). static const IconData savings_outlined = IconData(0xf336, fontFamily: 'MaterialIcons'); - /// scale — material icon named "scale". - static const IconData scale = IconData(0xf0564, fontFamily: 'MaterialIcons'); - - /// scale — material icon named "scale" (sharp). - static const IconData scale_sharp = IconData(0xf046d, fontFamily: 'MaterialIcons'); - - /// scale — material icon named "scale" (round). - static const IconData scale_rounded = IconData(0xf037a, fontFamily: 'MaterialIcons'); - - /// scale — material icon named "scale" (outlined). - static const IconData scale_outlined = IconData(0xf065b, fontFamily: 'MaterialIcons'); - /// scanner — material icon named "scanner". static const IconData scanner = IconData(0xe554, fontFamily: 'MaterialIcons'); @@ -19166,18 +17016,6 @@ class Icons { /// score — material icon named "score" (outlined). static const IconData score_outlined = IconData(0xf33e, fontFamily: 'MaterialIcons'); - /// scoreboard — material icon named "scoreboard". - static const IconData scoreboard = IconData(0xf06c1, fontFamily: 'MaterialIcons'); - - /// scoreboard — material icon named "scoreboard" (sharp). - static const IconData scoreboard_sharp = IconData(0xf06b4, fontFamily: 'MaterialIcons'); - - /// scoreboard — material icon named "scoreboard" (round). - static const IconData scoreboard_rounded = IconData(0xf06ce, fontFamily: 'MaterialIcons'); - - /// scoreboard — material icon named "scoreboard" (outlined). - static const IconData scoreboard_outlined = IconData(0xf06a7, fontFamily: 'MaterialIcons'); - /// screen_lock_landscape — material icon named "screen lock landscape". static const IconData screen_lock_landscape = IconData(0xe55c, fontFamily: 'MaterialIcons'); @@ -19262,18 +17100,6 @@ class Icons { /// screenshot — material icon named "screenshot" (outlined). static const IconData screenshot_outlined = IconData(0xf345, fontFamily: 'MaterialIcons'); - /// scuba_diving — material icon named "scuba diving". - static const IconData scuba_diving = IconData(0xf06c2, fontFamily: 'MaterialIcons'); - - /// scuba_diving — material icon named "scuba diving" (sharp). - static const IconData scuba_diving_sharp = IconData(0xf06b5, fontFamily: 'MaterialIcons'); - - /// scuba_diving — material icon named "scuba diving" (round). - static const IconData scuba_diving_rounded = IconData(0xf06cf, fontFamily: 'MaterialIcons'); - - /// scuba_diving — material icon named "scuba diving" (outlined). - static const IconData scuba_diving_outlined = IconData(0xf06a8, fontFamily: 'MaterialIcons'); - /// sd — material icon named "sd". static const IconData sd = IconData(0xe563, fontFamily: 'MaterialIcons'); @@ -19466,18 +17292,6 @@ class Icons { /// send_and_archive — material icon named "send and archive" (outlined). static const IconData send_and_archive_outlined = IconData(0xf354, fontFamily: 'MaterialIcons'); - /// send_time_extension — material icon named "send time extension". - static const IconData send_time_extension = IconData(0xf0565, fontFamily: 'MaterialIcons'); - - /// send_time_extension — material icon named "send time extension" (sharp). - static const IconData send_time_extension_sharp = IconData(0xf046e, fontFamily: 'MaterialIcons'); - - /// send_time_extension — material icon named "send time extension" (round). - static const IconData send_time_extension_rounded = IconData(0xf037b, fontFamily: 'MaterialIcons'); - - /// send_time_extension — material icon named "send time extension" (outlined). - static const IconData send_time_extension_outlined = IconData(0xf065c, fontFamily: 'MaterialIcons'); - /// send_to_mobile — material icon named "send to mobile". static const IconData send_to_mobile = IconData(0xe573, fontFamily: 'MaterialIcons'); @@ -19922,18 +17736,6 @@ class Icons { /// shield — material icon named "shield" (outlined). static const IconData shield_outlined = IconData(0xf379, fontFamily: 'MaterialIcons'); - /// shield_moon — material icon named "shield moon". - static const IconData shield_moon = IconData(0xf0566, fontFamily: 'MaterialIcons'); - - /// shield_moon — material icon named "shield moon" (sharp). - static const IconData shield_moon_sharp = IconData(0xf046f, fontFamily: 'MaterialIcons'); - - /// shield_moon — material icon named "shield moon" (round). - static const IconData shield_moon_rounded = IconData(0xf037c, fontFamily: 'MaterialIcons'); - - /// shield_moon — material icon named "shield moon" (outlined). - static const IconData shield_moon_outlined = IconData(0xf065d, fontFamily: 'MaterialIcons'); - /// shop — material icon named "shop". static const IconData shop = IconData(0xe597, fontFamily: 'MaterialIcons'); @@ -19970,18 +17772,6 @@ class Icons { /// shop_two — material icon named "shop two" (outlined). static const IconData shop_two_outlined = IconData(0xf37c, fontFamily: 'MaterialIcons'); - /// shopify — material icon named "shopify". - static const IconData shopify = IconData(0xf0567, fontFamily: 'MaterialIcons'); - - /// shopify — material icon named "shopify" (sharp). - static const IconData shopify_sharp = IconData(0xf0470, fontFamily: 'MaterialIcons'); - - /// shopify — material icon named "shopify" (round). - static const IconData shopify_rounded = IconData(0xf037d, fontFamily: 'MaterialIcons'); - - /// shopify — material icon named "shopify" (outlined). - static const IconData shopify_outlined = IconData(0xf065e, fontFamily: 'MaterialIcons'); - /// shopping_bag — material icon named "shopping bag". static const IconData shopping_bag = IconData(0xe59a, fontFamily: 'MaterialIcons'); @@ -20018,18 +17808,6 @@ class Icons { /// shopping_cart — material icon named "shopping cart" (outlined). static const IconData shopping_cart_outlined = IconData(0xf37f, fontFamily: 'MaterialIcons'); - /// shopping_cart_checkout — material icon named "shopping cart checkout". - static const IconData shopping_cart_checkout = IconData(0xf0568, fontFamily: 'MaterialIcons'); - - /// shopping_cart_checkout — material icon named "shopping cart checkout" (sharp). - static const IconData shopping_cart_checkout_sharp = IconData(0xf0471, fontFamily: 'MaterialIcons'); - - /// shopping_cart_checkout — material icon named "shopping cart checkout" (round). - static const IconData shopping_cart_checkout_rounded = IconData(0xf037e, fontFamily: 'MaterialIcons'); - - /// shopping_cart_checkout — material icon named "shopping cart checkout" (outlined). - static const IconData shopping_cart_checkout_outlined = IconData(0xf065f, fontFamily: 'MaterialIcons'); - /// short_text — material icon named "short text". static const IconData short_text = IconData(0xe59d, fontFamily: 'MaterialIcons', matchTextDirection: true); @@ -20342,18 +18120,6 @@ class Icons { /// signal_wifi_statusbar_null — material icon named "signal wifi statusbar null" (outlined). static const IconData signal_wifi_statusbar_null_outlined = IconData(0xf399, fontFamily: 'MaterialIcons'); - /// signpost — material icon named "signpost". - static const IconData signpost = IconData(0xf0569, fontFamily: 'MaterialIcons'); - - /// signpost — material icon named "signpost" (sharp). - static const IconData signpost_sharp = IconData(0xf0472, fontFamily: 'MaterialIcons'); - - /// signpost — material icon named "signpost" (round). - static const IconData signpost_rounded = IconData(0xf037f, fontFamily: 'MaterialIcons'); - - /// signpost — material icon named "signpost" (outlined). - static const IconData signpost_outlined = IconData(0xf0660, fontFamily: 'MaterialIcons'); - /// sim_card — material icon named "sim card". static const IconData sim_card = IconData(0xe5b7, fontFamily: 'MaterialIcons'); @@ -20594,18 +18360,6 @@ class Icons { /// sms_failed — material icon named "sms failed" (outlined). static const IconData sms_failed_outlined = IconData(0xf3ac, fontFamily: 'MaterialIcons'); - /// snapchat — material icon named "snapchat". - static const IconData snapchat = IconData(0xf056a, fontFamily: 'MaterialIcons'); - - /// snapchat — material icon named "snapchat" (sharp). - static const IconData snapchat_sharp = IconData(0xf0473, fontFamily: 'MaterialIcons'); - - /// snapchat — material icon named "snapchat" (round). - static const IconData snapchat_rounded = IconData(0xf0380, fontFamily: 'MaterialIcons'); - - /// snapchat — material icon named "snapchat" (outlined). - static const IconData snapchat_outlined = IconData(0xf0661, fontFamily: 'MaterialIcons'); - /// snippet_folder — material icon named "snippet folder". static const IconData snippet_folder = IconData(0xe5cb, fontFamily: 'MaterialIcons'); @@ -20642,9 +18396,6 @@ class Icons { /// snowboarding — material icon named "snowboarding" (outlined). static const IconData snowboarding_outlined = IconData(0xf3b0, fontFamily: 'MaterialIcons'); - /// snowing — material icon named "snowing". - static const IconData snowing = IconData(0xf056b, fontFamily: 'MaterialIcons'); - /// snowmobile — material icon named "snowmobile". static const IconData snowmobile = IconData(0xe5ce, fontFamily: 'MaterialIcons'); @@ -20717,18 +18468,6 @@ class Icons { /// sort_by_alpha — material icon named "sort by alpha" (outlined). static const IconData sort_by_alpha_outlined = IconData(0xf3b5, fontFamily: 'MaterialIcons'); - /// soup_kitchen — material icon named "soup kitchen". - static const IconData soup_kitchen = IconData(0xf056c, fontFamily: 'MaterialIcons'); - - /// soup_kitchen — material icon named "soup kitchen" (sharp). - static const IconData soup_kitchen_sharp = IconData(0xf0474, fontFamily: 'MaterialIcons'); - - /// soup_kitchen — material icon named "soup kitchen" (round). - static const IconData soup_kitchen_rounded = IconData(0xf0381, fontFamily: 'MaterialIcons'); - - /// soup_kitchen — material icon named "soup kitchen" (outlined). - static const IconData soup_kitchen_outlined = IconData(0xf0662, fontFamily: 'MaterialIcons'); - /// source — material icon named "source". static const IconData source = IconData(0xe5d4, fontFamily: 'MaterialIcons'); @@ -20753,18 +18492,6 @@ class Icons { /// south — material icon named "south" (outlined). static const IconData south_outlined = IconData(0xf3b9, fontFamily: 'MaterialIcons'); - /// south_america — material icon named "south america". - static const IconData south_america = IconData(0xf056d, fontFamily: 'MaterialIcons'); - - /// south_america — material icon named "south america" (sharp). - static const IconData south_america_sharp = IconData(0xf0475, fontFamily: 'MaterialIcons'); - - /// south_america — material icon named "south america" (round). - static const IconData south_america_rounded = IconData(0xf0382, fontFamily: 'MaterialIcons'); - - /// south_america — material icon named "south america" (outlined). - static const IconData south_america_outlined = IconData(0xf0663, fontFamily: 'MaterialIcons'); - /// south_east — material icon named "south east". static const IconData south_east = IconData(0xe5d6, fontFamily: 'MaterialIcons'); @@ -20921,18 +18648,6 @@ class Icons { /// splitscreen — material icon named "splitscreen" (outlined). static const IconData splitscreen_outlined = IconData(0xf3c5, fontFamily: 'MaterialIcons'); - /// spoke — material icon named "spoke". - static const IconData spoke = IconData(0xf056e, fontFamily: 'MaterialIcons'); - - /// spoke — material icon named "spoke" (sharp). - static const IconData spoke_sharp = IconData(0xf0476, fontFamily: 'MaterialIcons'); - - /// spoke — material icon named "spoke" (round). - static const IconData spoke_rounded = IconData(0xf0383, fontFamily: 'MaterialIcons'); - - /// spoke — material icon named "spoke" (outlined). - static const IconData spoke_outlined = IconData(0xf0664, fontFamily: 'MaterialIcons'); - /// sports — material icon named "sports". static const IconData sports = IconData(0xe5e3, fontFamily: 'MaterialIcons'); @@ -21029,18 +18744,6 @@ class Icons { /// sports_golf — material icon named "sports golf" (outlined). static const IconData sports_golf_outlined = IconData(0xf3cc, fontFamily: 'MaterialIcons'); - /// sports_gymnastics — material icon named "sports gymnastics". - static const IconData sports_gymnastics = IconData(0xf06c3, fontFamily: 'MaterialIcons'); - - /// sports_gymnastics — material icon named "sports gymnastics" (sharp). - static const IconData sports_gymnastics_sharp = IconData(0xf06b6, fontFamily: 'MaterialIcons'); - - /// sports_gymnastics — material icon named "sports gymnastics" (round). - static const IconData sports_gymnastics_rounded = IconData(0xf06d0, fontFamily: 'MaterialIcons'); - - /// sports_gymnastics — material icon named "sports gymnastics" (outlined). - static const IconData sports_gymnastics_outlined = IconData(0xf06a9, fontFamily: 'MaterialIcons'); - /// sports_handball — material icon named "sports handball". static const IconData sports_handball = IconData(0xe5eb, fontFamily: 'MaterialIcons'); @@ -21077,18 +18780,6 @@ class Icons { /// sports_kabaddi — material icon named "sports kabaddi" (outlined). static const IconData sports_kabaddi_outlined = IconData(0xf3cf, fontFamily: 'MaterialIcons'); - /// sports_martial_arts — material icon named "sports martial arts". - static const IconData sports_martial_arts = IconData(0xf056f, fontFamily: 'MaterialIcons'); - - /// sports_martial_arts — material icon named "sports martial arts" (sharp). - static const IconData sports_martial_arts_sharp = IconData(0xf0477, fontFamily: 'MaterialIcons'); - - /// sports_martial_arts — material icon named "sports martial arts" (round). - static const IconData sports_martial_arts_rounded = IconData(0xf0384, fontFamily: 'MaterialIcons'); - - /// sports_martial_arts — material icon named "sports martial arts" (outlined). - static const IconData sports_martial_arts_outlined = IconData(0xf0665, fontFamily: 'MaterialIcons'); - /// sports_mma — material icon named "sports mma". static const IconData sports_mma = IconData(0xe5ee, fontFamily: 'MaterialIcons'); @@ -21173,18 +18864,6 @@ class Icons { /// sports_volleyball — material icon named "sports volleyball" (outlined). static const IconData sports_volleyball_outlined = IconData(0xf3d7, fontFamily: 'MaterialIcons'); - /// square — material icon named "square". - static const IconData square = IconData(0xf0570, fontFamily: 'MaterialIcons'); - - /// square — material icon named "square" (sharp). - static const IconData square_sharp = IconData(0xf0478, fontFamily: 'MaterialIcons'); - - /// square — material icon named "square" (round). - static const IconData square_rounded = IconData(0xf0385, fontFamily: 'MaterialIcons'); - - /// square — material icon named "square" (outlined). - static const IconData square_outlined = IconData(0xf0666, fontFamily: 'MaterialIcons'); - /// square_foot — material icon named "square foot". static const IconData square_foot = IconData(0xe5f5, fontFamily: 'MaterialIcons'); @@ -21197,18 +18876,6 @@ class Icons { /// square_foot — material icon named "square foot" (outlined). static const IconData square_foot_outlined = IconData(0xf3d8, fontFamily: 'MaterialIcons'); - /// ssid_chart — material icon named "ssid chart". - static const IconData ssid_chart = IconData(0xf0571, fontFamily: 'MaterialIcons'); - - /// ssid_chart — material icon named "ssid chart" (sharp). - static const IconData ssid_chart_sharp = IconData(0xf0479, fontFamily: 'MaterialIcons'); - - /// ssid_chart — material icon named "ssid chart" (round). - static const IconData ssid_chart_rounded = IconData(0xf0386, fontFamily: 'MaterialIcons'); - - /// ssid_chart — material icon named "ssid chart" (outlined). - static const IconData ssid_chart_outlined = IconData(0xf0667, fontFamily: 'MaterialIcons'); - /// stacked_bar_chart — material icon named "stacked bar chart". static const IconData stacked_bar_chart = IconData(0xe5f6, fontFamily: 'MaterialIcons'); @@ -21233,18 +18900,6 @@ class Icons { /// stacked_line_chart — material icon named "stacked line chart" (outlined). static const IconData stacked_line_chart_outlined = IconData(0xf3da, fontFamily: 'MaterialIcons'); - /// stadium — material icon named "stadium". - static const IconData stadium = IconData(0xf0572, fontFamily: 'MaterialIcons'); - - /// stadium — material icon named "stadium" (sharp). - static const IconData stadium_sharp = IconData(0xf047a, fontFamily: 'MaterialIcons'); - - /// stadium — material icon named "stadium" (round). - static const IconData stadium_rounded = IconData(0xf0387, fontFamily: 'MaterialIcons'); - - /// stadium — material icon named "stadium" (outlined). - static const IconData stadium_outlined = IconData(0xf0668, fontFamily: 'MaterialIcons'); - /// stairs — material icon named "stairs". static const IconData stairs = IconData(0xe5f8, fontFamily: 'MaterialIcons'); @@ -21353,18 +19008,6 @@ class Icons { /// stars — material icon named "stars" (outlined). static const IconData stars_outlined = IconData(0xf3e3, fontFamily: 'MaterialIcons'); - /// start — material icon named "start". - static const IconData start = IconData(0xf0573, fontFamily: 'MaterialIcons'); - - /// start — material icon named "start" (sharp). - static const IconData start_sharp = IconData(0xf047b, fontFamily: 'MaterialIcons'); - - /// start — material icon named "start" (round). - static const IconData start_rounded = IconData(0xf0388, fontFamily: 'MaterialIcons'); - - /// start — material icon named "start" (outlined). - static const IconData start_outlined = IconData(0xf0669, fontFamily: 'MaterialIcons'); - /// stay_current_landscape — material icon named "stay current landscape". static const IconData stay_current_landscape = IconData(0xe601, fontFamily: 'MaterialIcons'); @@ -21521,18 +19164,6 @@ class Icons { /// storm — material icon named "storm" (outlined). static const IconData storm_outlined = IconData(0xf3f0, fontFamily: 'MaterialIcons'); - /// straight — material icon named "straight". - static const IconData straight = IconData(0xf0574, fontFamily: 'MaterialIcons'); - - /// straight — material icon named "straight" (sharp). - static const IconData straight_sharp = IconData(0xf047c, fontFamily: 'MaterialIcons'); - - /// straight — material icon named "straight" (round). - static const IconData straight_rounded = IconData(0xf0389, fontFamily: 'MaterialIcons'); - - /// straight — material icon named "straight" (outlined). - static const IconData straight_outlined = IconData(0xf066a, fontFamily: 'MaterialIcons'); - /// straighten — material icon named "straighten". static const IconData straighten = IconData(0xe60e, fontFamily: 'MaterialIcons'); @@ -21713,12 +19344,6 @@ class Icons { /// summarize — material icon named "summarize" (outlined). static const IconData summarize_outlined = IconData(0xf3ff, fontFamily: 'MaterialIcons'); - /// sunny — material icon named "sunny". - static const IconData sunny = IconData(0xf0575, fontFamily: 'MaterialIcons'); - - /// sunny_snowing — material icon named "sunny snowing". - static const IconData sunny_snowing = IconData(0xf0576, fontFamily: 'MaterialIcons'); - /// superscript — material icon named "superscript". static const IconData superscript = IconData(0xe61d, fontFamily: 'MaterialIcons'); @@ -21887,138 +19512,6 @@ class Icons { /// swipe — material icon named "swipe" (outlined). static const IconData swipe_outlined = IconData(0xf40c, fontFamily: 'MaterialIcons'); - /// swipe_down — material icon named "swipe down". - static const IconData swipe_down = IconData(0xf0578, fontFamily: 'MaterialIcons'); - - /// swipe_down — material icon named "swipe down" (sharp). - static const IconData swipe_down_sharp = IconData(0xf047e, fontFamily: 'MaterialIcons'); - - /// swipe_down — material icon named "swipe down" (round). - static const IconData swipe_down_rounded = IconData(0xf038b, fontFamily: 'MaterialIcons'); - - /// swipe_down — material icon named "swipe down" (outlined). - static const IconData swipe_down_outlined = IconData(0xf066c, fontFamily: 'MaterialIcons'); - - /// swipe_down_alt — material icon named "swipe down alt". - static const IconData swipe_down_alt = IconData(0xf0577, fontFamily: 'MaterialIcons'); - - /// swipe_down_alt — material icon named "swipe down alt" (sharp). - static const IconData swipe_down_alt_sharp = IconData(0xf047d, fontFamily: 'MaterialIcons'); - - /// swipe_down_alt — material icon named "swipe down alt" (round). - static const IconData swipe_down_alt_rounded = IconData(0xf038a, fontFamily: 'MaterialIcons'); - - /// swipe_down_alt — material icon named "swipe down alt" (outlined). - static const IconData swipe_down_alt_outlined = IconData(0xf066b, fontFamily: 'MaterialIcons'); - - /// swipe_left — material icon named "swipe left". - static const IconData swipe_left = IconData(0xf057a, fontFamily: 'MaterialIcons'); - - /// swipe_left — material icon named "swipe left" (sharp). - static const IconData swipe_left_sharp = IconData(0xf0480, fontFamily: 'MaterialIcons'); - - /// swipe_left — material icon named "swipe left" (round). - static const IconData swipe_left_rounded = IconData(0xf038d, fontFamily: 'MaterialIcons'); - - /// swipe_left — material icon named "swipe left" (outlined). - static const IconData swipe_left_outlined = IconData(0xf066e, fontFamily: 'MaterialIcons'); - - /// swipe_left_alt — material icon named "swipe left alt". - static const IconData swipe_left_alt = IconData(0xf0579, fontFamily: 'MaterialIcons'); - - /// swipe_left_alt — material icon named "swipe left alt" (sharp). - static const IconData swipe_left_alt_sharp = IconData(0xf047f, fontFamily: 'MaterialIcons'); - - /// swipe_left_alt — material icon named "swipe left alt" (round). - static const IconData swipe_left_alt_rounded = IconData(0xf038c, fontFamily: 'MaterialIcons'); - - /// swipe_left_alt — material icon named "swipe left alt" (outlined). - static const IconData swipe_left_alt_outlined = IconData(0xf066d, fontFamily: 'MaterialIcons'); - - /// swipe_right — material icon named "swipe right". - static const IconData swipe_right = IconData(0xf057c, fontFamily: 'MaterialIcons'); - - /// swipe_right — material icon named "swipe right" (sharp). - static const IconData swipe_right_sharp = IconData(0xf0482, fontFamily: 'MaterialIcons'); - - /// swipe_right — material icon named "swipe right" (round). - static const IconData swipe_right_rounded = IconData(0xf038f, fontFamily: 'MaterialIcons'); - - /// swipe_right — material icon named "swipe right" (outlined). - static const IconData swipe_right_outlined = IconData(0xf0670, fontFamily: 'MaterialIcons'); - - /// swipe_right_alt — material icon named "swipe right alt". - static const IconData swipe_right_alt = IconData(0xf057b, fontFamily: 'MaterialIcons'); - - /// swipe_right_alt — material icon named "swipe right alt" (sharp). - static const IconData swipe_right_alt_sharp = IconData(0xf0481, fontFamily: 'MaterialIcons'); - - /// swipe_right_alt — material icon named "swipe right alt" (round). - static const IconData swipe_right_alt_rounded = IconData(0xf038e, fontFamily: 'MaterialIcons'); - - /// swipe_right_alt — material icon named "swipe right alt" (outlined). - static const IconData swipe_right_alt_outlined = IconData(0xf066f, fontFamily: 'MaterialIcons'); - - /// swipe_up — material icon named "swipe up". - static const IconData swipe_up = IconData(0xf057e, fontFamily: 'MaterialIcons'); - - /// swipe_up — material icon named "swipe up" (sharp). - static const IconData swipe_up_sharp = IconData(0xf0484, fontFamily: 'MaterialIcons'); - - /// swipe_up — material icon named "swipe up" (round). - static const IconData swipe_up_rounded = IconData(0xf0391, fontFamily: 'MaterialIcons'); - - /// swipe_up — material icon named "swipe up" (outlined). - static const IconData swipe_up_outlined = IconData(0xf0672, fontFamily: 'MaterialIcons'); - - /// swipe_up_alt — material icon named "swipe up alt". - static const IconData swipe_up_alt = IconData(0xf057d, fontFamily: 'MaterialIcons'); - - /// swipe_up_alt — material icon named "swipe up alt" (sharp). - static const IconData swipe_up_alt_sharp = IconData(0xf0483, fontFamily: 'MaterialIcons'); - - /// swipe_up_alt — material icon named "swipe up alt" (round). - static const IconData swipe_up_alt_rounded = IconData(0xf0390, fontFamily: 'MaterialIcons'); - - /// swipe_up_alt — material icon named "swipe up alt" (outlined). - static const IconData swipe_up_alt_outlined = IconData(0xf0671, fontFamily: 'MaterialIcons'); - - /// swipe_vertical — material icon named "swipe vertical". - static const IconData swipe_vertical = IconData(0xf057f, fontFamily: 'MaterialIcons'); - - /// swipe_vertical — material icon named "swipe vertical" (sharp). - static const IconData swipe_vertical_sharp = IconData(0xf0485, fontFamily: 'MaterialIcons'); - - /// swipe_vertical — material icon named "swipe vertical" (round). - static const IconData swipe_vertical_rounded = IconData(0xf0392, fontFamily: 'MaterialIcons'); - - /// swipe_vertical — material icon named "swipe vertical" (outlined). - static const IconData swipe_vertical_outlined = IconData(0xf0673, fontFamily: 'MaterialIcons'); - - /// switch_access_shortcut — material icon named "switch access shortcut". - static const IconData switch_access_shortcut = IconData(0xf0581, fontFamily: 'MaterialIcons'); - - /// switch_access_shortcut — material icon named "switch access shortcut" (sharp). - static const IconData switch_access_shortcut_sharp = IconData(0xf0487, fontFamily: 'MaterialIcons'); - - /// switch_access_shortcut — material icon named "switch access shortcut" (round). - static const IconData switch_access_shortcut_rounded = IconData(0xf0394, fontFamily: 'MaterialIcons'); - - /// switch_access_shortcut — material icon named "switch access shortcut" (outlined). - static const IconData switch_access_shortcut_outlined = IconData(0xf0675, fontFamily: 'MaterialIcons'); - - /// switch_access_shortcut_add — material icon named "switch access shortcut add". - static const IconData switch_access_shortcut_add = IconData(0xf0580, fontFamily: 'MaterialIcons'); - - /// switch_access_shortcut_add — material icon named "switch access shortcut add" (sharp). - static const IconData switch_access_shortcut_add_sharp = IconData(0xf0486, fontFamily: 'MaterialIcons'); - - /// switch_access_shortcut_add — material icon named "switch access shortcut add" (round). - static const IconData switch_access_shortcut_add_rounded = IconData(0xf0393, fontFamily: 'MaterialIcons'); - - /// switch_access_shortcut_add — material icon named "switch access shortcut add" (outlined). - static const IconData switch_access_shortcut_add_outlined = IconData(0xf0674, fontFamily: 'MaterialIcons'); - /// switch_account — material icon named "switch account". static const IconData switch_account = IconData(0xe62a, fontFamily: 'MaterialIcons'); @@ -22079,18 +19572,6 @@ class Icons { /// switch_video — material icon named "switch video" (outlined). static const IconData switch_video_outlined = IconData(0xf411, fontFamily: 'MaterialIcons'); - /// synagogue — material icon named "synagogue". - static const IconData synagogue = IconData(0xf0582, fontFamily: 'MaterialIcons'); - - /// synagogue — material icon named "synagogue" (sharp). - static const IconData synagogue_sharp = IconData(0xf0488, fontFamily: 'MaterialIcons'); - - /// synagogue — material icon named "synagogue" (round). - static const IconData synagogue_rounded = IconData(0xf0395, fontFamily: 'MaterialIcons'); - - /// synagogue — material icon named "synagogue" (outlined). - static const IconData synagogue_outlined = IconData(0xf0676, fontFamily: 'MaterialIcons'); - /// sync — material icon named "sync". static const IconData sync = IconData(0xe62f, fontFamily: 'MaterialIcons'); @@ -22127,18 +19608,6 @@ class Icons { /// sync_disabled — material icon named "sync disabled" (outlined). static const IconData sync_disabled_outlined = IconData(0xf413, fontFamily: 'MaterialIcons'); - /// sync_lock — material icon named "sync lock". - static const IconData sync_lock = IconData(0xf0583, fontFamily: 'MaterialIcons'); - - /// sync_lock — material icon named "sync lock" (sharp). - static const IconData sync_lock_sharp = IconData(0xf0489, fontFamily: 'MaterialIcons'); - - /// sync_lock — material icon named "sync lock" (round). - static const IconData sync_lock_rounded = IconData(0xf0396, fontFamily: 'MaterialIcons'); - - /// sync_lock — material icon named "sync lock" (outlined). - static const IconData sync_lock_outlined = IconData(0xf0677, fontFamily: 'MaterialIcons'); - /// sync_problem — material icon named "sync problem". static const IconData sync_problem = IconData(0xe632, fontFamily: 'MaterialIcons'); @@ -22247,18 +19716,6 @@ class Icons { /// tab_unselected — material icon named "tab unselected" (outlined). static const IconData tab_unselected_outlined = IconData(0xf41c, fontFamily: 'MaterialIcons'); - /// table_bar — material icon named "table bar". - static const IconData table_bar = IconData(0xf0584, fontFamily: 'MaterialIcons'); - - /// table_bar — material icon named "table bar" (sharp). - static const IconData table_bar_sharp = IconData(0xf048a, fontFamily: 'MaterialIcons'); - - /// table_bar — material icon named "table bar" (round). - static const IconData table_bar_rounded = IconData(0xf0397, fontFamily: 'MaterialIcons'); - - /// table_bar — material icon named "table bar" (outlined). - static const IconData table_bar_outlined = IconData(0xf0678, fontFamily: 'MaterialIcons'); - /// table_chart — material icon named "table chart". static const IconData table_chart = IconData(0xe63a, fontFamily: 'MaterialIcons'); @@ -22271,18 +19728,6 @@ class Icons { /// table_chart — material icon named "table chart" (outlined). static const IconData table_chart_outlined = IconData(0xf41d, fontFamily: 'MaterialIcons'); - /// table_restaurant — material icon named "table restaurant". - static const IconData table_restaurant = IconData(0xf0585, fontFamily: 'MaterialIcons'); - - /// table_restaurant — material icon named "table restaurant" (sharp). - static const IconData table_restaurant_sharp = IconData(0xf048b, fontFamily: 'MaterialIcons'); - - /// table_restaurant — material icon named "table restaurant" (round). - static const IconData table_restaurant_rounded = IconData(0xf0398, fontFamily: 'MaterialIcons'); - - /// table_restaurant — material icon named "table restaurant" (outlined). - static const IconData table_restaurant_outlined = IconData(0xf0679, fontFamily: 'MaterialIcons'); - /// table_rows — material icon named "table rows". static const IconData table_rows = IconData(0xe63b, fontFamily: 'MaterialIcons'); @@ -22439,54 +19884,6 @@ class Icons { /// taxi_alert — material icon named "taxi alert" (outlined). static const IconData taxi_alert_outlined = IconData(0xf42a, fontFamily: 'MaterialIcons'); - /// telegram — material icon named "telegram". - static const IconData telegram = IconData(0xf0586, fontFamily: 'MaterialIcons'); - - /// telegram — material icon named "telegram" (sharp). - static const IconData telegram_sharp = IconData(0xf048c, fontFamily: 'MaterialIcons'); - - /// telegram — material icon named "telegram" (round). - static const IconData telegram_rounded = IconData(0xf0399, fontFamily: 'MaterialIcons'); - - /// telegram — material icon named "telegram" (outlined). - static const IconData telegram_outlined = IconData(0xf067a, fontFamily: 'MaterialIcons'); - - /// temple_buddhist — material icon named "temple buddhist". - static const IconData temple_buddhist = IconData(0xf0587, fontFamily: 'MaterialIcons'); - - /// temple_buddhist — material icon named "temple buddhist" (sharp). - static const IconData temple_buddhist_sharp = IconData(0xf048d, fontFamily: 'MaterialIcons'); - - /// temple_buddhist — material icon named "temple buddhist" (round). - static const IconData temple_buddhist_rounded = IconData(0xf039a, fontFamily: 'MaterialIcons'); - - /// temple_buddhist — material icon named "temple buddhist" (outlined). - static const IconData temple_buddhist_outlined = IconData(0xf067b, fontFamily: 'MaterialIcons'); - - /// temple_hindu — material icon named "temple hindu". - static const IconData temple_hindu = IconData(0xf0588, fontFamily: 'MaterialIcons'); - - /// temple_hindu — material icon named "temple hindu" (sharp). - static const IconData temple_hindu_sharp = IconData(0xf048e, fontFamily: 'MaterialIcons'); - - /// temple_hindu — material icon named "temple hindu" (round). - static const IconData temple_hindu_rounded = IconData(0xf039b, fontFamily: 'MaterialIcons'); - - /// temple_hindu — material icon named "temple hindu" (outlined). - static const IconData temple_hindu_outlined = IconData(0xf067c, fontFamily: 'MaterialIcons'); - - /// terminal — material icon named "terminal". - static const IconData terminal = IconData(0xf0589, fontFamily: 'MaterialIcons'); - - /// terminal — material icon named "terminal" (sharp). - static const IconData terminal_sharp = IconData(0xf048f, fontFamily: 'MaterialIcons'); - - /// terminal — material icon named "terminal" (round). - static const IconData terminal_rounded = IconData(0xf039c, fontFamily: 'MaterialIcons'); - - /// terminal — material icon named "terminal" (outlined). - static const IconData terminal_outlined = IconData(0xf067d, fontFamily: 'MaterialIcons'); - /// terrain — material icon named "terrain". static const IconData terrain = IconData(0xe648, fontFamily: 'MaterialIcons'); @@ -22499,18 +19896,6 @@ class Icons { /// terrain — material icon named "terrain" (outlined). static const IconData terrain_outlined = IconData(0xf42b, fontFamily: 'MaterialIcons'); - /// text_decrease — material icon named "text decrease". - static const IconData text_decrease = IconData(0xf058a, fontFamily: 'MaterialIcons'); - - /// text_decrease — material icon named "text decrease" (sharp). - static const IconData text_decrease_sharp = IconData(0xf0490, fontFamily: 'MaterialIcons'); - - /// text_decrease — material icon named "text decrease" (round). - static const IconData text_decrease_rounded = IconData(0xf039d, fontFamily: 'MaterialIcons'); - - /// text_decrease — material icon named "text decrease" (outlined). - static const IconData text_decrease_outlined = IconData(0xf067e, fontFamily: 'MaterialIcons'); - /// text_fields — material icon named "text fields". static const IconData text_fields = IconData(0xe649, fontFamily: 'MaterialIcons'); @@ -22535,18 +19920,6 @@ class Icons { /// text_format — material icon named "text format" (outlined). static const IconData text_format_outlined = IconData(0xf42d, fontFamily: 'MaterialIcons'); - /// text_increase — material icon named "text increase". - static const IconData text_increase = IconData(0xf058b, fontFamily: 'MaterialIcons'); - - /// text_increase — material icon named "text increase" (sharp). - static const IconData text_increase_sharp = IconData(0xf0491, fontFamily: 'MaterialIcons'); - - /// text_increase — material icon named "text increase" (round). - static const IconData text_increase_rounded = IconData(0xf039e, fontFamily: 'MaterialIcons'); - - /// text_increase — material icon named "text increase" (outlined). - static const IconData text_increase_outlined = IconData(0xf067f, fontFamily: 'MaterialIcons'); - /// text_rotate_up — material icon named "text rotate up". static const IconData text_rotate_up = IconData(0xe64b, fontFamily: 'MaterialIcons'); @@ -22787,18 +20160,6 @@ class Icons { /// thumbs_up_down — material icon named "thumbs up down" (outlined). static const IconData thumbs_up_down_outlined = IconData(0xf441, fontFamily: 'MaterialIcons'); - /// tiktok — material icon named "tiktok". - static const IconData tiktok = IconData(0xf058c, fontFamily: 'MaterialIcons'); - - /// tiktok — material icon named "tiktok" (sharp). - static const IconData tiktok_sharp = IconData(0xf0492, fontFamily: 'MaterialIcons'); - - /// tiktok — material icon named "tiktok" (round). - static const IconData tiktok_rounded = IconData(0xf039f, fontFamily: 'MaterialIcons'); - - /// tiktok — material icon named "tiktok" (outlined). - static const IconData tiktok_outlined = IconData(0xf0680, fontFamily: 'MaterialIcons'); - /// time_to_leave — material icon named "time to leave". static const IconData time_to_leave = IconData(0xe65f, fontFamily: 'MaterialIcons'); @@ -22907,30 +20268,6 @@ class Icons { /// timer_off — material icon named "timer off" (outlined). static const IconData timer_off_outlined = IconData(0xf449, fontFamily: 'MaterialIcons'); - /// tips_and_updates — material icon named "tips and updates". - static const IconData tips_and_updates = IconData(0xf058d, fontFamily: 'MaterialIcons'); - - /// tips_and_updates — material icon named "tips and updates" (sharp). - static const IconData tips_and_updates_sharp = IconData(0xf0493, fontFamily: 'MaterialIcons'); - - /// tips_and_updates — material icon named "tips and updates" (round). - static const IconData tips_and_updates_rounded = IconData(0xf03a0, fontFamily: 'MaterialIcons'); - - /// tips_and_updates — material icon named "tips and updates" (outlined). - static const IconData tips_and_updates_outlined = IconData(0xf0681, fontFamily: 'MaterialIcons'); - - /// tire_repair — material icon named "tire repair". - static const IconData tire_repair = IconData(0xf06c4, fontFamily: 'MaterialIcons'); - - /// tire_repair — material icon named "tire repair" (sharp). - static const IconData tire_repair_sharp = IconData(0xf06b7, fontFamily: 'MaterialIcons'); - - /// tire_repair — material icon named "tire repair" (round). - static const IconData tire_repair_rounded = IconData(0xf06d1, fontFamily: 'MaterialIcons'); - - /// tire_repair — material icon named "tire repair" (outlined). - static const IconData tire_repair_outlined = IconData(0xf06aa, fontFamily: 'MaterialIcons'); - /// title — material icon named "title". static const IconData title = IconData(0xe668, fontFamily: 'MaterialIcons'); @@ -22991,18 +20328,6 @@ class Icons { /// toggle_on — material icon named "toggle on" (outlined). static const IconData toggle_on_outlined = IconData(0xf44f, fontFamily: 'MaterialIcons'); - /// token — material icon named "token". - static const IconData token = IconData(0xf058e, fontFamily: 'MaterialIcons'); - - /// token — material icon named "token" (sharp). - static const IconData token_sharp = IconData(0xf0494, fontFamily: 'MaterialIcons'); - - /// token — material icon named "token" (round). - static const IconData token_rounded = IconData(0xf03a1, fontFamily: 'MaterialIcons'); - - /// token — material icon named "token" (outlined). - static const IconData token_outlined = IconData(0xf0682, fontFamily: 'MaterialIcons'); - /// toll — material icon named "toll". static const IconData toll = IconData(0xe66d, fontFamily: 'MaterialIcons'); @@ -23303,78 +20628,6 @@ class Icons { /// tungsten — material icon named "tungsten" (outlined). static const IconData tungsten_outlined = IconData(0xf467, fontFamily: 'MaterialIcons'); - /// turn_left — material icon named "turn left". - static const IconData turn_left = IconData(0xf058f, fontFamily: 'MaterialIcons'); - - /// turn_left — material icon named "turn left" (sharp). - static const IconData turn_left_sharp = IconData(0xf0495, fontFamily: 'MaterialIcons'); - - /// turn_left — material icon named "turn left" (round). - static const IconData turn_left_rounded = IconData(0xf03a2, fontFamily: 'MaterialIcons'); - - /// turn_left — material icon named "turn left" (outlined). - static const IconData turn_left_outlined = IconData(0xf0683, fontFamily: 'MaterialIcons'); - - /// turn_right — material icon named "turn right". - static const IconData turn_right = IconData(0xf0590, fontFamily: 'MaterialIcons'); - - /// turn_right — material icon named "turn right" (sharp). - static const IconData turn_right_sharp = IconData(0xf0496, fontFamily: 'MaterialIcons'); - - /// turn_right — material icon named "turn right" (round). - static const IconData turn_right_rounded = IconData(0xf03a3, fontFamily: 'MaterialIcons'); - - /// turn_right — material icon named "turn right" (outlined). - static const IconData turn_right_outlined = IconData(0xf0684, fontFamily: 'MaterialIcons'); - - /// turn_sharp_left — material icon named "turn sharp left". - static const IconData turn_sharp_left = IconData(0xf0591, fontFamily: 'MaterialIcons'); - - /// turn_sharp_left — material icon named "turn sharp left" (sharp). - static const IconData turn_sharp_left_sharp = IconData(0xf0497, fontFamily: 'MaterialIcons'); - - /// turn_sharp_left — material icon named "turn sharp left" (round). - static const IconData turn_sharp_left_rounded = IconData(0xf03a4, fontFamily: 'MaterialIcons'); - - /// turn_sharp_left — material icon named "turn sharp left" (outlined). - static const IconData turn_sharp_left_outlined = IconData(0xf0685, fontFamily: 'MaterialIcons'); - - /// turn_sharp_right — material icon named "turn sharp right". - static const IconData turn_sharp_right = IconData(0xf0592, fontFamily: 'MaterialIcons'); - - /// turn_sharp_right — material icon named "turn sharp right" (sharp). - static const IconData turn_sharp_right_sharp = IconData(0xf0498, fontFamily: 'MaterialIcons'); - - /// turn_sharp_right — material icon named "turn sharp right" (round). - static const IconData turn_sharp_right_rounded = IconData(0xf03a5, fontFamily: 'MaterialIcons'); - - /// turn_sharp_right — material icon named "turn sharp right" (outlined). - static const IconData turn_sharp_right_outlined = IconData(0xf0686, fontFamily: 'MaterialIcons'); - - /// turn_slight_left — material icon named "turn slight left". - static const IconData turn_slight_left = IconData(0xf0593, fontFamily: 'MaterialIcons'); - - /// turn_slight_left — material icon named "turn slight left" (sharp). - static const IconData turn_slight_left_sharp = IconData(0xf0499, fontFamily: 'MaterialIcons'); - - /// turn_slight_left — material icon named "turn slight left" (round). - static const IconData turn_slight_left_rounded = IconData(0xf03a6, fontFamily: 'MaterialIcons'); - - /// turn_slight_left — material icon named "turn slight left" (outlined). - static const IconData turn_slight_left_outlined = IconData(0xf0687, fontFamily: 'MaterialIcons'); - - /// turn_slight_right — material icon named "turn slight right". - static const IconData turn_slight_right = IconData(0xf0594, fontFamily: 'MaterialIcons'); - - /// turn_slight_right — material icon named "turn slight right" (sharp). - static const IconData turn_slight_right_sharp = IconData(0xf049a, fontFamily: 'MaterialIcons'); - - /// turn_slight_right — material icon named "turn slight right" (round). - static const IconData turn_slight_right_rounded = IconData(0xf03a7, fontFamily: 'MaterialIcons'); - - /// turn_slight_right — material icon named "turn slight right" (outlined). - static const IconData turn_slight_right_outlined = IconData(0xf0688, fontFamily: 'MaterialIcons'); - /// turned_in — material icon named "turned in". static const IconData turned_in = IconData(0xe685, fontFamily: 'MaterialIcons'); @@ -23435,30 +20688,6 @@ class Icons { /// two_wheeler — material icon named "two wheeler" (outlined). static const IconData two_wheeler_outlined = IconData(0xf46c, fontFamily: 'MaterialIcons'); - /// u_turn_left — material icon named "u turn left". - static const IconData u_turn_left = IconData(0xf0595, fontFamily: 'MaterialIcons'); - - /// u_turn_left — material icon named "u turn left" (sharp). - static const IconData u_turn_left_sharp = IconData(0xf049b, fontFamily: 'MaterialIcons'); - - /// u_turn_left — material icon named "u turn left" (round). - static const IconData u_turn_left_rounded = IconData(0xf03a8, fontFamily: 'MaterialIcons'); - - /// u_turn_left — material icon named "u turn left" (outlined). - static const IconData u_turn_left_outlined = IconData(0xf0689, fontFamily: 'MaterialIcons'); - - /// u_turn_right — material icon named "u turn right". - static const IconData u_turn_right = IconData(0xf0596, fontFamily: 'MaterialIcons'); - - /// u_turn_right — material icon named "u turn right" (sharp). - static const IconData u_turn_right_sharp = IconData(0xf049c, fontFamily: 'MaterialIcons'); - - /// u_turn_right — material icon named "u turn right" (round). - static const IconData u_turn_right_rounded = IconData(0xf03a9, fontFamily: 'MaterialIcons'); - - /// u_turn_right — material icon named "u turn right" (outlined). - static const IconData u_turn_right_outlined = IconData(0xf068a, fontFamily: 'MaterialIcons'); - /// umbrella — material icon named "umbrella". static const IconData umbrella = IconData(0xe68a, fontFamily: 'MaterialIcons'); @@ -23639,42 +20868,6 @@ class Icons { /// usb_off — material icon named "usb off" (outlined). static const IconData usb_off_outlined = IconData(0xf47a, fontFamily: 'MaterialIcons'); - /// vaccines — material icon named "vaccines". - static const IconData vaccines = IconData(0xf0597, fontFamily: 'MaterialIcons'); - - /// vaccines — material icon named "vaccines" (sharp). - static const IconData vaccines_sharp = IconData(0xf049d, fontFamily: 'MaterialIcons'); - - /// vaccines — material icon named "vaccines" (round). - static const IconData vaccines_rounded = IconData(0xf03aa, fontFamily: 'MaterialIcons'); - - /// vaccines — material icon named "vaccines" (outlined). - static const IconData vaccines_outlined = IconData(0xf068b, fontFamily: 'MaterialIcons'); - - /// vape_free — material icon named "vape free". - static const IconData vape_free = IconData(0xf06c5, fontFamily: 'MaterialIcons'); - - /// vape_free — material icon named "vape free" (sharp). - static const IconData vape_free_sharp = IconData(0xf06b8, fontFamily: 'MaterialIcons'); - - /// vape_free — material icon named "vape free" (round). - static const IconData vape_free_rounded = IconData(0xf06d2, fontFamily: 'MaterialIcons'); - - /// vape_free — material icon named "vape free" (outlined). - static const IconData vape_free_outlined = IconData(0xf06ab, fontFamily: 'MaterialIcons'); - - /// vaping_rooms — material icon named "vaping rooms". - static const IconData vaping_rooms = IconData(0xf06c6, fontFamily: 'MaterialIcons'); - - /// vaping_rooms — material icon named "vaping rooms" (sharp). - static const IconData vaping_rooms_sharp = IconData(0xf06b9, fontFamily: 'MaterialIcons'); - - /// vaping_rooms — material icon named "vaping rooms" (round). - static const IconData vaping_rooms_rounded = IconData(0xf06d3, fontFamily: 'MaterialIcons'); - - /// vaping_rooms — material icon named "vaping rooms" (outlined). - static const IconData vaping_rooms_outlined = IconData(0xf06ac, fontFamily: 'MaterialIcons'); - /// verified — material icon named "verified". static const IconData verified = IconData(0xe699, fontFamily: 'MaterialIcons'); @@ -23819,18 +21012,6 @@ class Icons { /// video_collection — material icon named "video collection" (outlined). static const IconData video_collection_outlined = IconData(0xf488, fontFamily: 'MaterialIcons'); - /// video_file — material icon named "video file". - static const IconData video_file = IconData(0xf0598, fontFamily: 'MaterialIcons'); - - /// video_file — material icon named "video file" (sharp). - static const IconData video_file_sharp = IconData(0xf049e, fontFamily: 'MaterialIcons'); - - /// video_file — material icon named "video file" (round). - static const IconData video_file_rounded = IconData(0xf03ab, fontFamily: 'MaterialIcons'); - - /// video_file — material icon named "video file" (outlined). - static const IconData video_file_outlined = IconData(0xf068c, fontFamily: 'MaterialIcons'); - /// video_label — material icon named "video label". static const IconData video_label = IconData(0xe6a4, fontFamily: 'MaterialIcons'); @@ -23999,18 +21180,6 @@ class Icons { /// view_comfy — material icon named "view comfy" (outlined). static const IconData view_comfy_outlined = IconData(0xf493, fontFamily: 'MaterialIcons'); - /// view_comfy_alt — material icon named "view comfy alt". - static const IconData view_comfy_alt = IconData(0xf0599, fontFamily: 'MaterialIcons'); - - /// view_comfy_alt — material icon named "view comfy alt" (sharp). - static const IconData view_comfy_alt_sharp = IconData(0xf049f, fontFamily: 'MaterialIcons'); - - /// view_comfy_alt — material icon named "view comfy alt" (round). - static const IconData view_comfy_alt_rounded = IconData(0xf03ac, fontFamily: 'MaterialIcons'); - - /// view_comfy_alt — material icon named "view comfy alt" (outlined). - static const IconData view_comfy_alt_outlined = IconData(0xf068d, fontFamily: 'MaterialIcons'); - /// view_compact — material icon named "view compact". static const IconData view_compact = IconData(0xe6b1, fontFamily: 'MaterialIcons'); @@ -24023,30 +21192,6 @@ class Icons { /// view_compact — material icon named "view compact" (outlined). static const IconData view_compact_outlined = IconData(0xf494, fontFamily: 'MaterialIcons'); - /// view_compact_alt — material icon named "view compact alt". - static const IconData view_compact_alt = IconData(0xf059a, fontFamily: 'MaterialIcons'); - - /// view_compact_alt — material icon named "view compact alt" (sharp). - static const IconData view_compact_alt_sharp = IconData(0xf04a0, fontFamily: 'MaterialIcons'); - - /// view_compact_alt — material icon named "view compact alt" (round). - static const IconData view_compact_alt_rounded = IconData(0xf03ad, fontFamily: 'MaterialIcons'); - - /// view_compact_alt — material icon named "view compact alt" (outlined). - static const IconData view_compact_alt_outlined = IconData(0xf068e, fontFamily: 'MaterialIcons'); - - /// view_cozy — material icon named "view cozy". - static const IconData view_cozy = IconData(0xf059b, fontFamily: 'MaterialIcons'); - - /// view_cozy — material icon named "view cozy" (sharp). - static const IconData view_cozy_sharp = IconData(0xf04a1, fontFamily: 'MaterialIcons'); - - /// view_cozy — material icon named "view cozy" (round). - static const IconData view_cozy_rounded = IconData(0xf03ae, fontFamily: 'MaterialIcons'); - - /// view_cozy — material icon named "view cozy" (outlined). - static const IconData view_cozy_outlined = IconData(0xf068f, fontFamily: 'MaterialIcons'); - /// view_day — material icon named "view day". static const IconData view_day = IconData(0xe6b2, fontFamily: 'MaterialIcons'); @@ -24083,18 +21228,6 @@ class Icons { /// view_in_ar — material icon named "view in ar" (outlined). static const IconData view_in_ar_outlined = IconData(0xf497, fontFamily: 'MaterialIcons'); - /// view_kanban — material icon named "view kanban". - static const IconData view_kanban = IconData(0xf059c, fontFamily: 'MaterialIcons'); - - /// view_kanban — material icon named "view kanban" (sharp). - static const IconData view_kanban_sharp = IconData(0xf04a2, fontFamily: 'MaterialIcons'); - - /// view_kanban — material icon named "view kanban" (round). - static const IconData view_kanban_rounded = IconData(0xf03af, fontFamily: 'MaterialIcons'); - - /// view_kanban — material icon named "view kanban" (outlined). - static const IconData view_kanban_outlined = IconData(0xf0690, fontFamily: 'MaterialIcons'); - /// view_list — material icon named "view list". static const IconData view_list = IconData(0xe6b5, fontFamily: 'MaterialIcons', matchTextDirection: true); @@ -24155,18 +21288,6 @@ class Icons { /// view_stream — material icon named "view stream" (outlined). static const IconData view_stream_outlined = IconData(0xf49c, fontFamily: 'MaterialIcons'); - /// view_timeline — material icon named "view timeline". - static const IconData view_timeline = IconData(0xf059d, fontFamily: 'MaterialIcons'); - - /// view_timeline — material icon named "view timeline" (sharp). - static const IconData view_timeline_sharp = IconData(0xf04a3, fontFamily: 'MaterialIcons'); - - /// view_timeline — material icon named "view timeline" (round). - static const IconData view_timeline_rounded = IconData(0xf03b0, fontFamily: 'MaterialIcons'); - - /// view_timeline — material icon named "view timeline" (outlined). - static const IconData view_timeline_outlined = IconData(0xf0691, fontFamily: 'MaterialIcons'); - /// view_week — material icon named "view week". static const IconData view_week = IconData(0xe6ba, fontFamily: 'MaterialIcons'); @@ -24275,9 +21396,6 @@ class Icons { /// volume_down — material icon named "volume down" (outlined). static const IconData volume_down_outlined = IconData(0xf4a5, fontFamily: 'MaterialIcons'); - /// volume_down_alt — material icon named "volume down alt". - static const IconData volume_down_alt = IconData(0xf059e, fontFamily: 'MaterialIcons'); - /// volume_mute — material icon named "volume mute". static const IconData volume_mute = IconData(0xe6c3, fontFamily: 'MaterialIcons'); @@ -24338,18 +21456,6 @@ class Icons { /// vpn_key — material icon named "vpn key" (outlined). static const IconData vpn_key_outlined = IconData(0xf4aa, fontFamily: 'MaterialIcons'); - /// vpn_key_off — material icon named "vpn key off". - static const IconData vpn_key_off = IconData(0xf059f, fontFamily: 'MaterialIcons'); - - /// vpn_key_off — material icon named "vpn key off" (sharp). - static const IconData vpn_key_off_sharp = IconData(0xf04a4, fontFamily: 'MaterialIcons'); - - /// vpn_key_off — material icon named "vpn key off" (round). - static const IconData vpn_key_off_rounded = IconData(0xf03b1, fontFamily: 'MaterialIcons'); - - /// vpn_key_off — material icon named "vpn key off" (outlined). - static const IconData vpn_key_off_outlined = IconData(0xf0692, fontFamily: 'MaterialIcons'); - /// vpn_lock — material icon named "vpn lock". static const IconData vpn_lock = IconData(0xe6c8, fontFamily: 'MaterialIcons'); @@ -24422,18 +21528,6 @@ class Icons { /// wallpaper — material icon named "wallpaper" (outlined). static const IconData wallpaper_outlined = IconData(0xf4ad, fontFamily: 'MaterialIcons'); - /// warehouse — material icon named "warehouse". - static const IconData warehouse = IconData(0xf05a0, fontFamily: 'MaterialIcons'); - - /// warehouse — material icon named "warehouse" (sharp). - static const IconData warehouse_sharp = IconData(0xf04a5, fontFamily: 'MaterialIcons'); - - /// warehouse — material icon named "warehouse" (round). - static const IconData warehouse_rounded = IconData(0xf03b2, fontFamily: 'MaterialIcons'); - - /// warehouse — material icon named "warehouse" (outlined). - static const IconData warehouse_outlined = IconData(0xf0693, fontFamily: 'MaterialIcons'); - /// warning — material icon named "warning". static const IconData warning = IconData(0xe6cb, fontFamily: 'MaterialIcons'); @@ -24494,18 +21588,6 @@ class Icons { /// watch_later — material icon named "watch later" (outlined). static const IconData watch_later_outlined = IconData(0xf4b1, fontFamily: 'MaterialIcons'); - /// watch_off — material icon named "watch off". - static const IconData watch_off = IconData(0xf05a1, fontFamily: 'MaterialIcons'); - - /// watch_off — material icon named "watch off" (sharp). - static const IconData watch_off_sharp = IconData(0xf04a6, fontFamily: 'MaterialIcons'); - - /// watch_off — material icon named "watch off" (round). - static const IconData watch_off_rounded = IconData(0xf03b3, fontFamily: 'MaterialIcons'); - - /// watch_off — material icon named "watch off" (outlined). - static const IconData watch_off_outlined = IconData(0xf0694, fontFamily: 'MaterialIcons'); - /// water — material icon named "water". static const IconData water = IconData(0xe6d0, fontFamily: 'MaterialIcons'); @@ -24530,18 +21612,6 @@ class Icons { /// water_damage — material icon named "water damage" (outlined). static const IconData water_damage_outlined = IconData(0xf4b3, fontFamily: 'MaterialIcons'); - /// water_drop — material icon named "water drop". - static const IconData water_drop = IconData(0xf05a2, fontFamily: 'MaterialIcons'); - - /// water_drop — material icon named "water drop" (sharp). - static const IconData water_drop_sharp = IconData(0xf04a7, fontFamily: 'MaterialIcons'); - - /// water_drop — material icon named "water drop" (round). - static const IconData water_drop_rounded = IconData(0xf03b4, fontFamily: 'MaterialIcons'); - - /// water_drop — material icon named "water drop" (outlined). - static const IconData water_drop_outlined = IconData(0xf0695, fontFamily: 'MaterialIcons'); - /// waterfall_chart — material icon named "waterfall chart". static const IconData waterfall_chart = IconData(0xe6d2, fontFamily: 'MaterialIcons'); @@ -24566,18 +21636,6 @@ class Icons { /// waves — material icon named "waves" (outlined). static const IconData waves_outlined = IconData(0xf4b6, fontFamily: 'MaterialIcons'); - /// waving_hand — material icon named "waving hand". - static const IconData waving_hand = IconData(0xf05a3, fontFamily: 'MaterialIcons'); - - /// waving_hand — material icon named "waving hand" (sharp). - static const IconData waving_hand_sharp = IconData(0xf04a8, fontFamily: 'MaterialIcons'); - - /// waving_hand — material icon named "waving hand" (round). - static const IconData waving_hand_rounded = IconData(0xf03b5, fontFamily: 'MaterialIcons'); - - /// waving_hand — material icon named "waving hand" (outlined). - static const IconData waving_hand_outlined = IconData(0xf0696, fontFamily: 'MaterialIcons'); - /// wb_auto — material icon named "wb auto". static const IconData wb_auto = IconData(0xe6d4, fontFamily: 'MaterialIcons'); @@ -24716,30 +21774,6 @@ class Icons { /// web_stories — material icon named "web stories". static const IconData web_stories = IconData(0xe6e0, fontFamily: 'MaterialIcons'); - /// webhook — material icon named "webhook". - static const IconData webhook = IconData(0xf05a4, fontFamily: 'MaterialIcons'); - - /// webhook — material icon named "webhook" (sharp). - static const IconData webhook_sharp = IconData(0xf04a9, fontFamily: 'MaterialIcons'); - - /// webhook — material icon named "webhook" (round). - static const IconData webhook_rounded = IconData(0xf03b6, fontFamily: 'MaterialIcons'); - - /// webhook — material icon named "webhook" (outlined). - static const IconData webhook_outlined = IconData(0xf0697, fontFamily: 'MaterialIcons'); - - /// wechat — material icon named "wechat". - static const IconData wechat = IconData(0xf05a5, fontFamily: 'MaterialIcons'); - - /// wechat — material icon named "wechat" (sharp). - static const IconData wechat_sharp = IconData(0xf04aa, fontFamily: 'MaterialIcons'); - - /// wechat — material icon named "wechat" (round). - static const IconData wechat_rounded = IconData(0xf03b7, fontFamily: 'MaterialIcons'); - - /// wechat — material icon named "wechat" (outlined). - static const IconData wechat_outlined = IconData(0xf0698, fontFamily: 'MaterialIcons'); - /// weekend — material icon named "weekend". static const IconData weekend = IconData(0xe6e1, fontFamily: 'MaterialIcons'); @@ -24764,18 +21798,6 @@ class Icons { /// west — material icon named "west" (outlined). static const IconData west_outlined = IconData(0xf4c3, fontFamily: 'MaterialIcons'); - /// whatsapp — material icon named "whatsapp". - static const IconData whatsapp = IconData(0xf05a6, fontFamily: 'MaterialIcons'); - - /// whatsapp — material icon named "whatsapp" (sharp). - static const IconData whatsapp_sharp = IconData(0xf04ab, fontFamily: 'MaterialIcons'); - - /// whatsapp — material icon named "whatsapp" (round). - static const IconData whatsapp_rounded = IconData(0xf03b8, fontFamily: 'MaterialIcons'); - - /// whatsapp — material icon named "whatsapp" (outlined). - static const IconData whatsapp_outlined = IconData(0xf0699, fontFamily: 'MaterialIcons'); - /// whatshot — material icon named "whatshot". static const IconData whatshot = IconData(0xe6e3, fontFamily: 'MaterialIcons'); @@ -24860,30 +21882,6 @@ class Icons { /// wifi_calling_3 — material icon named "wifi calling 3" (outlined). static const IconData wifi_calling_3_outlined = IconData(0xf4c8, fontFamily: 'MaterialIcons'); - /// wifi_channel — material icon named "wifi channel". - static const IconData wifi_channel = IconData(0xf05a7, fontFamily: 'MaterialIcons'); - - /// wifi_channel — material icon named "wifi channel" (sharp). - static const IconData wifi_channel_sharp = IconData(0xf04ac, fontFamily: 'MaterialIcons'); - - /// wifi_channel — material icon named "wifi channel" (round). - static const IconData wifi_channel_rounded = IconData(0xf03b9, fontFamily: 'MaterialIcons'); - - /// wifi_channel — material icon named "wifi channel" (outlined). - static const IconData wifi_channel_outlined = IconData(0xf069a, fontFamily: 'MaterialIcons'); - - /// wifi_find — material icon named "wifi find". - static const IconData wifi_find = IconData(0xf05a8, fontFamily: 'MaterialIcons'); - - /// wifi_find — material icon named "wifi find" (sharp). - static const IconData wifi_find_sharp = IconData(0xf04ad, fontFamily: 'MaterialIcons'); - - /// wifi_find — material icon named "wifi find" (round). - static const IconData wifi_find_rounded = IconData(0xf03ba, fontFamily: 'MaterialIcons'); - - /// wifi_find — material icon named "wifi find" (outlined). - static const IconData wifi_find_outlined = IconData(0xf069b, fontFamily: 'MaterialIcons'); - /// wifi_lock — material icon named "wifi lock". static const IconData wifi_lock = IconData(0xe6ea, fontFamily: 'MaterialIcons'); @@ -24908,18 +21906,6 @@ class Icons { /// wifi_off — material icon named "wifi off" (outlined). static const IconData wifi_off_outlined = IconData(0xf4cb, fontFamily: 'MaterialIcons'); - /// wifi_password — material icon named "wifi password". - static const IconData wifi_password = IconData(0xf05a9, fontFamily: 'MaterialIcons'); - - /// wifi_password — material icon named "wifi password" (sharp). - static const IconData wifi_password_sharp = IconData(0xf04ae, fontFamily: 'MaterialIcons'); - - /// wifi_password — material icon named "wifi password" (round). - static const IconData wifi_password_rounded = IconData(0xf03bb, fontFamily: 'MaterialIcons'); - - /// wifi_password — material icon named "wifi password" (outlined). - static const IconData wifi_password_outlined = IconData(0xf069c, fontFamily: 'MaterialIcons'); - /// wifi_protected_setup — material icon named "wifi protected setup". static const IconData wifi_protected_setup = IconData(0xe6ec, fontFamily: 'MaterialIcons'); @@ -24944,26 +21930,17 @@ class Icons { /// wifi_tethering — material icon named "wifi tethering" (outlined). static const IconData wifi_tethering_outlined = IconData(0xf4d0, fontFamily: 'MaterialIcons'); - /// wifi_tethering_error — material icon named "wifi tethering error". - static const IconData wifi_tethering_error = IconData(0xf05aa, fontFamily: 'MaterialIcons'); - - /// wifi_tethering_error — material icon named "wifi tethering error" (sharp). - static const IconData wifi_tethering_error_sharp = IconData(0xf04af, fontFamily: 'MaterialIcons'); - - /// wifi_tethering_error — material icon named "wifi tethering error". - static const IconData wifi_tethering_error_rounded = IconData(0xf05aa, fontFamily: 'MaterialIcons'); - - /// wifi_tethering_error — material icon named "wifi tethering error" (outlined). - static const IconData wifi_tethering_error_outlined = IconData(0xf069d, fontFamily: 'MaterialIcons'); + /// wifi_tethering_error — material icon named "wifi tethering error" (round). + static const IconData wifi_tethering_error_rounded = IconData(0xe6ee, fontFamily: 'MaterialIcons'); /// wifi_tethering_error_rounded — material icon named "wifi tethering error rounded" (sharp). - static const IconData wifi_tethering_error_rounded_sharp = IconData(0xf04af, fontFamily: 'MaterialIcons'); + static const IconData wifi_tethering_error_rounded_sharp = IconData(0xede1, fontFamily: 'MaterialIcons'); /// wifi_tethering_error_rounded — material icon named "wifi tethering error rounded" (round). static const IconData wifi_tethering_error_rounded_rounded = IconData(0xf02c0, fontFamily: 'MaterialIcons'); /// wifi_tethering_error_rounded — material icon named "wifi tethering error rounded" (outlined). - static const IconData wifi_tethering_error_rounded_outlined = IconData(0xf069d, fontFamily: 'MaterialIcons'); + static const IconData wifi_tethering_error_rounded_outlined = IconData(0xf4ce, fontFamily: 'MaterialIcons'); /// wifi_tethering_off — material icon named "wifi tethering off". static const IconData wifi_tethering_off = IconData(0xe6ef, fontFamily: 'MaterialIcons'); @@ -25001,42 +21978,6 @@ class Icons { /// wine_bar — material icon named "wine bar" (outlined). static const IconData wine_bar_outlined = IconData(0xf4d2, fontFamily: 'MaterialIcons'); - /// woman — material icon named "woman". - static const IconData woman = IconData(0xf05ab, fontFamily: 'MaterialIcons'); - - /// woman — material icon named "woman" (sharp). - static const IconData woman_sharp = IconData(0xf04b0, fontFamily: 'MaterialIcons'); - - /// woman — material icon named "woman" (round). - static const IconData woman_rounded = IconData(0xf03bd, fontFamily: 'MaterialIcons'); - - /// woman — material icon named "woman" (outlined). - static const IconData woman_outlined = IconData(0xf069e, fontFamily: 'MaterialIcons'); - - /// woo_commerce — material icon named "woo commerce". - static const IconData woo_commerce = IconData(0xf05ac, fontFamily: 'MaterialIcons'); - - /// woo_commerce — material icon named "woo commerce" (sharp). - static const IconData woo_commerce_sharp = IconData(0xf04b1, fontFamily: 'MaterialIcons'); - - /// woo_commerce — material icon named "woo commerce" (round). - static const IconData woo_commerce_rounded = IconData(0xf03be, fontFamily: 'MaterialIcons'); - - /// woo_commerce — material icon named "woo commerce" (outlined). - static const IconData woo_commerce_outlined = IconData(0xf069f, fontFamily: 'MaterialIcons'); - - /// wordpress — material icon named "wordpress". - static const IconData wordpress = IconData(0xf05ad, fontFamily: 'MaterialIcons'); - - /// wordpress — material icon named "wordpress" (sharp). - static const IconData wordpress_sharp = IconData(0xf04b2, fontFamily: 'MaterialIcons'); - - /// wordpress — material icon named "wordpress" (round). - static const IconData wordpress_rounded = IconData(0xf03bf, fontFamily: 'MaterialIcons'); - - /// wordpress — material icon named "wordpress" (outlined). - static const IconData wordpress_outlined = IconData(0xf06a0, fontFamily: 'MaterialIcons'); - /// work — material icon named "work". static const IconData work = IconData(0xe6f2, fontFamily: 'MaterialIcons'); @@ -25073,18 +22014,6 @@ class Icons { /// work_outline — material icon named "work outline" (outlined). static const IconData work_outline_outlined = IconData(0xf4d4, fontFamily: 'MaterialIcons'); - /// workspace_premium — material icon named "workspace premium". - static const IconData workspace_premium = IconData(0xf05ae, fontFamily: 'MaterialIcons'); - - /// workspace_premium — material icon named "workspace premium" (sharp). - static const IconData workspace_premium_sharp = IconData(0xf04b3, fontFamily: 'MaterialIcons'); - - /// workspace_premium — material icon named "workspace premium" (round). - static const IconData workspace_premium_rounded = IconData(0xf03c0, fontFamily: 'MaterialIcons'); - - /// workspace_premium — material icon named "workspace premium" (outlined). - static const IconData workspace_premium_outlined = IconData(0xf06a1, fontFamily: 'MaterialIcons'); - /// workspaces — material icon named "workspaces". static const IconData workspaces = IconData(0xe6f5, fontFamily: 'MaterialIcons'); @@ -25175,18 +22104,6 @@ class Icons { /// zoom_in — material icon named "zoom in" (outlined). static const IconData zoom_in_outlined = IconData(0xf4dc, fontFamily: 'MaterialIcons'); - /// zoom_in_map — material icon named "zoom in map". - static const IconData zoom_in_map = IconData(0xf05af, fontFamily: 'MaterialIcons'); - - /// zoom_in_map — material icon named "zoom in map" (sharp). - static const IconData zoom_in_map_sharp = IconData(0xf04b4, fontFamily: 'MaterialIcons'); - - /// zoom_in_map — material icon named "zoom in map" (round). - static const IconData zoom_in_map_rounded = IconData(0xf03c1, fontFamily: 'MaterialIcons'); - - /// zoom_in_map — material icon named "zoom in map" (outlined). - static const IconData zoom_in_map_outlined = IconData(0xf06a2, fontFamily: 'MaterialIcons'); - /// zoom_out — material icon named "zoom out". static const IconData zoom_out = IconData(0xe6fe, fontFamily: 'MaterialIcons'); diff --git a/packages/flutter/lib/src/material/ink_decoration.dart b/packages/flutter/lib/src/material/ink_decoration.dart index 0050ddd10df1a..e93f02b8736fa 100644 --- a/packages/flutter/lib/src/material/ink_decoration.dart +++ b/packages/flutter/lib/src/material/ink_decoration.dart @@ -104,27 +104,6 @@ import 'material.dart'; /// ``` /// {@end-tool} /// -/// What to do if you want to clip this [Ink.image]? -/// -/// {@tool dartpad} -/// Wrapping the [Ink] in a clipping widget directly will not work since the -/// [Material] it will be printed on is responsible for clipping. -/// -/// In this example the image is not being clipped as expected. This is because -/// it is being rendered onto the Scaffold body Material, which isn't wrapped in -/// the [ClipRRect]. -/// -/// ** See code in examples/api/lib/material/ink/ink.image_clip.0.dart ** -/// {@end-tool} -/// -/// {@tool dartpad} -/// One solution would be to deliberately wrap the [Ink.image] in a [Material]. -/// This makes sure the Material that the image is painted on is also responsible -/// for clipping said content. -/// -/// ** See code in examples/api/lib/material/ink/ink.image_clip.1.dart ** -/// {@end-tool} -/// /// See also: /// /// * [Container], a more generic form of this widget which paints itself, diff --git a/packages/flutter/lib/src/material/ink_well.dart b/packages/flutter/lib/src/material/ink_well.dart index 2529ca53111c8..0f8786cb4e903 100644 --- a/packages/flutter/lib/src/material/ink_well.dart +++ b/packages/flutter/lib/src/material/ink_well.dart @@ -483,12 +483,11 @@ class InkResponse extends StatelessWidget { /// Defines the ink response focus, hover, and splash colors. /// /// This default null property can be used as an alternative to - /// [focusColor], [hoverColor], [highlightColor], and - /// [splashColor]. If non-null, it is resolved against one of - /// [MaterialState.focused], [MaterialState.hovered], and - /// [MaterialState.pressed]. It's convenient to use when the parent - /// widget can pass along its own MaterialStateProperty value for - /// the overlay color. + /// [focusColor], [hoverColor], and [splashColor]. If non-null, + /// it is resolved against one of [MaterialState.focused], + /// [MaterialState.hovered], and [MaterialState.pressed]. It's + /// convenient to use when the parent widget can pass along its own + /// MaterialStateProperty value for the overlay color. /// /// [MaterialState.pressed] triggers a ripple (an ink splash), per /// the current Material Design spec. The [overlayColor] doesn't map @@ -800,21 +799,19 @@ class _InkResponseState extends State<_InkResponseStateWidget> bool get wantKeepAlive => highlightsExist || (_splashes != null && _splashes!.isNotEmpty); Color getHighlightColorForType(_HighlightType type) { - const Set pressed = {MaterialState.pressed}; const Set focused = {MaterialState.focused}; const Set hovered = {MaterialState.hovered}; - final ThemeData theme = Theme.of(context); switch (type) { // The pressed state triggers a ripple (ink splash), per the current // Material Design spec. A separate highlight is no longer used. // See https://material.io/design/interaction/states.html#pressed case _HighlightType.pressed: - return widget.overlayColor?.resolve(pressed) ?? widget.highlightColor ?? theme.highlightColor; + return widget.highlightColor ?? Theme.of(context).highlightColor; case _HighlightType.focus: - return widget.overlayColor?.resolve(focused) ?? widget.focusColor ?? theme.focusColor; + return widget.overlayColor?.resolve(focused) ?? widget.focusColor ?? Theme.of(context).focusColor; case _HighlightType.hover: - return widget.overlayColor?.resolve(hovered) ?? widget.hoverColor ?? theme.hoverColor; + return widget.overlayColor?.resolve(hovered) ?? widget.hoverColor ?? Theme.of(context).hoverColor; } } @@ -1035,7 +1032,7 @@ class _InkResponseState extends State<_InkResponseStateWidget> } bool _isWidgetEnabled(_InkResponseStateWidget widget) { - return widget.onTap != null || widget.onDoubleTap != null || widget.onLongPress != null || widget.onTapDown != null; + return widget.onTap != null || widget.onDoubleTap != null || widget.onLongPress != null; } bool get enabled => _isWidgetEnabled(widget); @@ -1087,7 +1084,6 @@ class _InkResponseState extends State<_InkResponseStateWidget> if (_hasFocus) MaterialState.focused, }, ); - return _ParentInkResponseProvider( state: this, child: Actions( @@ -1163,18 +1159,6 @@ class _InkResponseState extends State<_InkResponseStateWidget> /// ancestor to the ink well). The [MaterialType.transparency] material /// kind can be used for this purpose. /// -/// ### InkWell isn't clipping properly -/// -/// If you want to clip an InkWell or any [Ink] widgets you need to keep in mind -/// that the [Material] that the Ink will be printed on is responsible for clipping. -/// This means you can't wrap the [Ink] widget in a clipping widget directly, -/// since this will leave the [Material] not clipped (and by extension the printed -/// [Ink] widgets as well). -/// -/// An easy solution is to deliberately wrap the [Ink] widgets you want to clip -/// in a [Material], and wrap that in a clipping widget instead. See [Ink] for -/// an example. -/// /// ### The ink splashes don't track the size of an animated container /// If the size of an InkWell's [Material] ancestor changes while the InkWell's /// splashes are expanding, you may notice that the splashes aren't clipped diff --git a/packages/flutter/lib/src/material/input_border.dart b/packages/flutter/lib/src/material/input_border.dart index 4cf53344e78f5..a7b7b1e05e35d 100644 --- a/packages/flutter/lib/src/material/input_border.dart +++ b/packages/flutter/lib/src/material/input_border.dart @@ -416,15 +416,14 @@ class OutlineInputBorder extends InputBorder { scaledRRect.blRadiusX * 2.0, ); - // This assumes that the radius is circular (x and y radius are equal). - // Currently, BorderRadius only supports circular radii. const double cornerArcSweep = math.pi / 2.0; - final double tlCornerArcSweep = math.acos( - (1 - start / scaledRRect.tlRadiusX).clamp(0.0, 1.0), - ); + final double tlCornerArcSweep = start < scaledRRect.tlRadiusX + ? math.asin((start / scaledRRect.tlRadiusX).clamp(-1.0, 1.0)) + : math.pi / 2.0; final Path path = Path() - ..addArc(tlCorner, math.pi, tlCornerArcSweep); + ..addArc(tlCorner, math.pi, tlCornerArcSweep) + ..moveTo(scaledRRect.left + scaledRRect.tlRadiusX, scaledRRect.top); if (start > scaledRRect.tlRadiusX) path.lineTo(scaledRRect.left + start, scaledRRect.top); @@ -432,14 +431,13 @@ class OutlineInputBorder extends InputBorder { const double trCornerArcStart = (3 * math.pi) / 2.0; const double trCornerArcSweep = cornerArcSweep; if (start + extent < scaledRRect.width - scaledRRect.trRadiusX) { - path.moveTo(scaledRRect.left + start + extent, scaledRRect.top); - path.lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top); - path.addArc(trCorner, trCornerArcStart, trCornerArcSweep); + path + ..relativeMoveTo(extent, 0.0) + ..lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top) + ..addArc(trCorner, trCornerArcStart, trCornerArcSweep); } else if (start + extent < scaledRRect.width) { final double dx = scaledRRect.width - (start + extent); - final double sweep = math.asin( - (1 - dx / scaledRRect.trRadiusX).clamp(0.0, 1.0), - ); + final double sweep = math.acos(dx / scaledRRect.trRadiusX); path.addArc(trCorner, trCornerArcStart + sweep, trCornerArcSweep - sweep); } diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index d34a31daa8a06..4e149a807adc6 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -56,9 +56,6 @@ class _InputBorderGap extends ChangeNotifier { @override // ignore: avoid_equals_and_hash_code_on_mutable_classes, this class is not used in collection int get hashCode => hashValues(start, extent); - - @override - String toString() => describeIdentity(this); } // Used to interpolate between two InputBorders. @@ -127,9 +124,6 @@ class _InputBorderPainter extends CustomPainter { || gap != oldPainter.gap || textDirection != oldPainter.textDirection; } - - @override - String toString() => describeIdentity(this); } // An analog of AnimatedContainer, which can animate its shaped border, for @@ -145,6 +139,7 @@ class _BorderContainer extends StatefulWidget { required this.fillColor, required this.hoverColor, required this.isHovering, + this.child, }) : assert(border != null), assert(gap != null), assert(fillColor != null), @@ -156,6 +151,7 @@ class _BorderContainer extends StatefulWidget { final Color fillColor; final Color hoverColor; final bool isHovering; + final Widget? child; @override _BorderContainerState createState() => _BorderContainerState(); @@ -247,6 +243,7 @@ class _BorderContainerState extends State<_BorderContainer> with TickerProviderS hoverColorTween: _hoverColorTween, hoverAnimation: _hoverAnimation, ), + child: widget.child, ); } } @@ -470,14 +467,7 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta } } -/// Defines **how** the floating label should behave. -/// -/// See also: -/// -/// * [InputDecoration.floatingLabelBehavior] which defines the behavior for -/// [InputDecoration.label] or [InputDecoration.labelText]. -/// * [FloatingLabelAlignment] which defines **where** the floating label -/// should displayed. +/// Defines the behavior of the floating label. enum FloatingLabelBehavior { /// The label will always be positioned within the content, or hidden. never, @@ -487,57 +477,6 @@ enum FloatingLabelBehavior { always, } -/// Defines **where** the floating label should be displayed within an -/// [InputDecorator]. -/// -/// See also: -/// -/// * [InputDecoration.floatingLabelAlignment] which defines the alignment for -/// [InputDecoration.label] or [InputDecoration.labelText]. -/// * [FloatingLabelBehavior] which defines **how** the floating label should -/// behave. -@immutable -class FloatingLabelAlignment { - const FloatingLabelAlignment._(this._x) : assert(_x != null), - assert(_x >= -1.0 && _x <= 1.0); - - // -1 denotes start, 0 denotes center, and 1 denotes end. - final double _x; - - /// Align the floating label on the leading edge of the [InputDecorator]. - /// - /// For left-to-right text ([TextDirection.ltr]), this is the left edge. - /// - /// For right-to-left text ([TextDirection.rtl]), this is the right edge. - static const FloatingLabelAlignment start = FloatingLabelAlignment._(-1.0); - /// Aligns the floating label to the center of an [InputDecorator]. - static const FloatingLabelAlignment center = FloatingLabelAlignment._(0.0); - - @override - int get hashCode => _x.hashCode; - - @override - bool operator ==(Object other) { - if (identical(this, other)) - return true; - if (other.runtimeType != runtimeType) - return false; - return other is FloatingLabelAlignment - && _x == other._x; - } - - static String _stringify(double x) { - if (x == -1.0) - return 'FloatingLabelAlignment.start'; - if (x == 0.0) - return 'FloatingLabelAlignment.center'; - return 'FloatingLabelAlignment(x: ${x.toStringAsFixed(1)})'; - } - - @override - String toString() => _stringify(_x); -} - // Identifies the children of a _RenderDecorationElement. enum _DecorationSlot { icon, @@ -561,7 +500,6 @@ class _Decoration { required this.isCollapsed, required this.floatingLabelHeight, required this.floatingLabelProgress, - required this.floatingLabelAlignment, this.border, this.borderGap, required this.alignLabelWithHint, @@ -581,14 +519,12 @@ class _Decoration { }) : assert(contentPadding != null), assert(isCollapsed != null), assert(floatingLabelHeight != null), - assert(floatingLabelProgress != null), - assert(floatingLabelAlignment != null); + assert(floatingLabelProgress != null); final EdgeInsetsGeometry contentPadding; final bool isCollapsed; final double floatingLabelHeight; final double floatingLabelProgress; - final FloatingLabelAlignment floatingLabelAlignment; final InputBorder? border; final _InputBorderGap? borderGap; final bool alignLabelWithHint; @@ -617,7 +553,6 @@ class _Decoration { && other.isCollapsed == isCollapsed && other.floatingLabelHeight == floatingLabelHeight && other.floatingLabelProgress == floatingLabelProgress - && other.floatingLabelAlignment == floatingLabelAlignment && other.border == border && other.borderGap == borderGap && other.alignLabelWithHint == alignLabelWithHint @@ -642,7 +577,6 @@ class _Decoration { contentPadding, floatingLabelHeight, floatingLabelProgress, - floatingLabelAlignment, border, borderGap, alignLabelWithHint, @@ -685,7 +619,7 @@ class _RenderDecorationLayout { } // The workhorse: layout and paint a _Decorator widget's _Decoration. -class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin<_DecorationSlot> { +class _RenderDecoration extends RenderBox { _RenderDecoration({ required _Decoration decoration, required TextDirection textDirection, @@ -705,46 +639,110 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin _expands = expands; static const double subtextGap = 8.0; + final Map<_DecorationSlot, RenderBox> children = <_DecorationSlot, RenderBox>{}; + + RenderBox? _updateChild(RenderBox? oldChild, RenderBox? newChild, _DecorationSlot slot) { + if (oldChild != null) { + dropChild(oldChild); + children.remove(slot); + } + if (newChild != null) { + children[slot] = newChild; + adoptChild(newChild); + } + return newChild; + } - RenderBox? get icon => childForSlot(_DecorationSlot.icon); - RenderBox? get input => childForSlot(_DecorationSlot.input); - RenderBox? get label => childForSlot(_DecorationSlot.label); - RenderBox? get hint => childForSlot(_DecorationSlot.hint); - RenderBox? get prefix => childForSlot(_DecorationSlot.prefix); - RenderBox? get suffix => childForSlot(_DecorationSlot.suffix); - RenderBox? get prefixIcon => childForSlot(_DecorationSlot.prefixIcon); - RenderBox? get suffixIcon => childForSlot(_DecorationSlot.suffixIcon); - RenderBox? get helperError => childForSlot(_DecorationSlot.helperError); - RenderBox? get counter => childForSlot(_DecorationSlot.counter); - RenderBox? get container => childForSlot(_DecorationSlot.container); + RenderBox? _icon; + RenderBox? get icon => _icon; + set icon(RenderBox? value) { + _icon = _updateChild(_icon, value, _DecorationSlot.icon); + } + + RenderBox? _input; + RenderBox? get input => _input; + set input(RenderBox? value) { + _input = _updateChild(_input, value, _DecorationSlot.input); + } + + RenderBox? _label; + RenderBox? get label => _label; + set label(RenderBox? value) { + _label = _updateChild(_label, value, _DecorationSlot.label); + } + + RenderBox? _hint; + RenderBox? get hint => _hint; + set hint(RenderBox? value) { + _hint = _updateChild(_hint, value, _DecorationSlot.hint); + } + + RenderBox? _prefix; + RenderBox? get prefix => _prefix; + set prefix(RenderBox? value) { + _prefix = _updateChild(_prefix, value, _DecorationSlot.prefix); + } + + RenderBox? _suffix; + RenderBox? get suffix => _suffix; + set suffix(RenderBox? value) { + _suffix = _updateChild(_suffix, value, _DecorationSlot.suffix); + } + + RenderBox? _prefixIcon; + RenderBox? get prefixIcon => _prefixIcon; + set prefixIcon(RenderBox? value) { + _prefixIcon = _updateChild(_prefixIcon, value, _DecorationSlot.prefixIcon); + } + + RenderBox? _suffixIcon; + RenderBox? get suffixIcon => _suffixIcon; + set suffixIcon(RenderBox? value) { + _suffixIcon = _updateChild(_suffixIcon, value, _DecorationSlot.suffixIcon); + } + + RenderBox? _helperError; + RenderBox? get helperError => _helperError; + set helperError(RenderBox? value) { + _helperError = _updateChild(_helperError, value, _DecorationSlot.helperError); + } + + RenderBox? _counter; + RenderBox? get counter => _counter; + set counter(RenderBox? value) { + _counter = _updateChild(_counter, value, _DecorationSlot.counter); + } + + RenderBox? _container; + RenderBox? get container => _container; + set container(RenderBox? value) { + _container = _updateChild(_container, value, _DecorationSlot.container); + } // The returned list is ordered for hit testing. - @override - Iterable get children { - return [ - if (icon != null) - icon!, - if (input != null) - input!, - if (prefixIcon != null) - prefixIcon!, - if (suffixIcon != null) - suffixIcon!, - if (prefix != null) - prefix!, - if (suffix != null) - suffix!, - if (label != null) - label!, - if (hint != null) - hint!, - if (helperError != null) - helperError!, - if (counter != null) - counter!, - if (container != null) - container!, - ]; + Iterable get _children sync* { + if (icon != null) + yield icon!; + if (input != null) + yield input!; + if (prefixIcon != null) + yield prefixIcon!; + if (suffixIcon != null) + yield suffixIcon!; + if (prefix != null) + yield prefix!; + if (suffix != null) + yield suffix!; + if (label != null) + yield label!; + if (hint != null) + yield hint!; + if (helperError != null) + yield helperError!; + if (counter != null) + yield counter!; + if (container != null) + yield container!; } _Decoration get decoration => _decoration; @@ -821,6 +819,30 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin return !decoration.isCollapsed && decoration.border!.isOutline; } + @override + void attach(PipelineOwner owner) { + super.attach(owner); + for (final RenderBox child in _children) + child.attach(owner); + } + + @override + void detach() { + super.detach(); + for (final RenderBox child in _children) + child.detach(); + } + + @override + void redepthChildren() { + _children.forEach(redepthChild); + } + + @override + void visitChildren(RenderObjectVisitor visitor) { + _children.forEach(visitor); + } + @override void visitChildrenForSemantics(RenderObjectVisitor visitor) { if (icon != null) @@ -855,6 +877,27 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin visitor(counter!); } + @override + List debugDescribeChildren() { + final List value = []; + void add(RenderBox? child, String name) { + if (child != null) + value.add(child.toDiagnosticsNode(name: name)); + } + add(icon, 'icon'); + add(input, 'input'); + add(label, 'label'); + add(hint, 'hint'); + add(prefix, 'prefix'); + add(suffix, 'suffix'); + add(prefixIcon, 'prefixIcon'); + add(suffixIcon, 'suffixIcon'); + add(helperError, 'helperError'); + add(counter, 'counter'); + add(container, 'container'); + return value; + } + @override bool get sizedByParent => false; @@ -1427,28 +1470,17 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin if (label != null) { final double labelX = _boxParentData(label!).offset.dx; - // +1 shifts the range of x from (-1.0, 1.0) to (0.0, 2.0). - final double floatAlign = decoration.floatingLabelAlignment._x + 1; - final double floatWidth = _boxSize(label).width * _kFinalLabelScale; - // When floating label is centered, its x is relative to - // _BorderContainer's x and is independent of label's x. switch (textDirection) { case TextDirection.rtl: - decoration.borderGap!.start = lerpDouble(labelX + _boxSize(label).width, - _boxSize(container).width / 2.0 + floatWidth / 2.0, - floatAlign); - + decoration.borderGap!.start = labelX + label!.size.width; break; case TextDirection.ltr: // The value of _InputBorderGap.start is relative to the origin of the - // _BorderContainer which is inset by the icon's width. Although, when - // floating label is centered, it's already relative to _BorderContainer. - decoration.borderGap!.start = lerpDouble(labelX - _boxSize(icon).width, - _boxSize(container).width / 2.0 - floatWidth / 2.0, - floatAlign); + // _BorderContainer which is inset by the icon's width. + decoration.borderGap!.start = labelX - _boxSize(icon).width; break; } - decoration.borderGap!.extent = label!.size.width * _kFinalLabelScale; + decoration.borderGap!.extent = label!.size.width * 0.75; } else { decoration.borderGap!.start = null; decoration.borderGap!.extent = 0.0; @@ -1473,11 +1505,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin if (label != null) { final Offset labelOffset = _boxParentData(label!).offset; - final double labelHeight = _boxSize(label).height; - final double labelWidth = _boxSize(label).width; - // +1 shifts the range of x from (-1.0, 1.0) to (0.0, 2.0). - final double floatAlign = decoration.floatingLabelAlignment._x + 1; - final double floatWidth = labelWidth * _kFinalLabelScale; + final double labelHeight = label!.size.height; final double borderWeight = decoration.border!.borderSide.width; final double t = decoration.floatingLabelProgress; // The center of the outline border label ends up a little below the @@ -1487,19 +1515,15 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin // Center the scaled label relative to the border. final double floatingY = isOutlineBorder ? (-labelHeight * _kFinalLabelScale) / 2.0 + borderWeight / 2.0 : contentPadding.top; final double scale = lerpDouble(1.0, _kFinalLabelScale, t)!; - final double centeredFloatX = _boxParentData(container!).offset.dx + - _boxSize(container).width / 2.0 - floatWidth / 2.0; - final double floatStartX; + final double dx; switch (textDirection) { - case TextDirection.rtl: // origin is on the right - floatStartX = labelOffset.dx + labelWidth * (1.0 - scale); + case TextDirection.rtl: + dx = labelOffset.dx + label!.size.width * (1.0 - scale); // origin is on the right break; - case TextDirection.ltr: // origin on the left - floatStartX = labelOffset.dx; + case TextDirection.ltr: + dx = labelOffset.dx; // origin on the left break; } - final double floatEndX = lerpDouble(floatStartX, centeredFloatX, floatAlign)!; - final double dx = lerpDouble(floatStartX, floatEndX, t)!; final double dy = lerpDouble(0.0, floatingY - labelOffset.dy, t)!; _labelTransform = Matrix4.identity() ..translate(dx, labelOffset.dy + dy) @@ -1532,7 +1556,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin @override bool hitTestChildren(BoxHitTestResult result, { required Offset position }) { assert(position != null); - for (final RenderBox child in children) { + for (final RenderBox child in _children) { // The label must be handled specially since we've transformed it. final Offset offset = _boxParentData(child).offset; final bool isHit = result.addWithPaintOffset( @@ -1561,7 +1585,146 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin } } -class _Decorator extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin<_DecorationSlot> { +class _DecorationElement extends RenderObjectElement { + _DecorationElement(_Decorator widget) : super(widget); + + final Map<_DecorationSlot, Element> slotToChild = <_DecorationSlot, Element>{}; + + @override + _Decorator get widget => super.widget as _Decorator; + + @override + _RenderDecoration get renderObject => super.renderObject as _RenderDecoration; + + @override + void visitChildren(ElementVisitor visitor) { + slotToChild.values.forEach(visitor); + } + + @override + void forgetChild(Element child) { + assert(slotToChild.containsValue(child)); + assert(child.slot is _DecorationSlot); + assert(slotToChild.containsKey(child.slot)); + slotToChild.remove(child.slot); + super.forgetChild(child); + } + + void _mountChild(Widget? widget, _DecorationSlot slot) { + final Element? oldChild = slotToChild[slot]; + final Element? newChild = updateChild(oldChild, widget, slot); + if (oldChild != null) { + slotToChild.remove(slot); + } + if (newChild != null) { + slotToChild[slot] = newChild; + } + } + + @override + void mount(Element? parent, Object? newSlot) { + super.mount(parent, newSlot); + _mountChild(widget.decoration.icon, _DecorationSlot.icon); + _mountChild(widget.decoration.input, _DecorationSlot.input); + _mountChild(widget.decoration.label, _DecorationSlot.label); + _mountChild(widget.decoration.hint, _DecorationSlot.hint); + _mountChild(widget.decoration.prefix, _DecorationSlot.prefix); + _mountChild(widget.decoration.suffix, _DecorationSlot.suffix); + _mountChild(widget.decoration.prefixIcon, _DecorationSlot.prefixIcon); + _mountChild(widget.decoration.suffixIcon, _DecorationSlot.suffixIcon); + _mountChild(widget.decoration.helperError, _DecorationSlot.helperError); + _mountChild(widget.decoration.counter, _DecorationSlot.counter); + _mountChild(widget.decoration.container, _DecorationSlot.container); + } + + void _updateChild(Widget? widget, _DecorationSlot slot) { + final Element? oldChild = slotToChild[slot]; + final Element? newChild = updateChild(oldChild, widget, slot); + if (oldChild != null) { + slotToChild.remove(slot); + } + if (newChild != null) { + slotToChild[slot] = newChild; + } + } + + @override + void update(_Decorator newWidget) { + super.update(newWidget); + assert(widget == newWidget); + _updateChild(widget.decoration.icon, _DecorationSlot.icon); + _updateChild(widget.decoration.input, _DecorationSlot.input); + _updateChild(widget.decoration.label, _DecorationSlot.label); + _updateChild(widget.decoration.hint, _DecorationSlot.hint); + _updateChild(widget.decoration.prefix, _DecorationSlot.prefix); + _updateChild(widget.decoration.suffix, _DecorationSlot.suffix); + _updateChild(widget.decoration.prefixIcon, _DecorationSlot.prefixIcon); + _updateChild(widget.decoration.suffixIcon, _DecorationSlot.suffixIcon); + _updateChild(widget.decoration.helperError, _DecorationSlot.helperError); + _updateChild(widget.decoration.counter, _DecorationSlot.counter); + _updateChild(widget.decoration.container, _DecorationSlot.container); + } + + void _updateRenderObject(RenderBox? child, _DecorationSlot slot) { + switch (slot) { + case _DecorationSlot.icon: + renderObject.icon = child; + break; + case _DecorationSlot.input: + renderObject.input = child; + break; + case _DecorationSlot.label: + renderObject.label = child; + break; + case _DecorationSlot.hint: + renderObject.hint = child; + break; + case _DecorationSlot.prefix: + renderObject.prefix = child; + break; + case _DecorationSlot.suffix: + renderObject.suffix = child; + break; + case _DecorationSlot.prefixIcon: + renderObject.prefixIcon = child; + break; + case _DecorationSlot.suffixIcon: + renderObject.suffixIcon = child; + break; + case _DecorationSlot.helperError: + renderObject.helperError = child; + break; + case _DecorationSlot.counter: + renderObject.counter = child; + break; + case _DecorationSlot.container: + renderObject.container = child; + break; + } + } + + @override + void insertRenderObjectChild(RenderObject child, _DecorationSlot slot) { + assert(child is RenderBox); + _updateRenderObject(child as RenderBox, slot); + assert(renderObject.children.keys.contains(slot)); + } + + @override + void removeRenderObjectChild(RenderObject child, _DecorationSlot slot) { + assert(child is RenderBox); + assert(renderObject.children[slot] == child); + _updateRenderObject(null, slot); + assert(!renderObject.children.keys.contains(slot)); + } + + @override + void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) { + assert(false, 'not reachable'); + } +} + +class _Decorator extends RenderObjectWidget { const _Decorator({ Key? key, required this.textAlignVertical, @@ -1584,35 +1747,7 @@ class _Decorator extends RenderObjectWidget with SlottedMultiChildRenderObjectWi final bool expands; @override - Iterable<_DecorationSlot> get slots => _DecorationSlot.values; - - @override - Widget? childForSlot(_DecorationSlot slot) { - switch (slot) { - case _DecorationSlot.icon: - return decoration.icon; - case _DecorationSlot.input: - return decoration.input; - case _DecorationSlot.label: - return decoration.label; - case _DecorationSlot.hint: - return decoration.hint; - case _DecorationSlot.prefix: - return decoration.prefix; - case _DecorationSlot.suffix: - return decoration.suffix; - case _DecorationSlot.prefixIcon: - return decoration.prefixIcon; - case _DecorationSlot.suffixIcon: - return decoration.suffixIcon; - case _DecorationSlot.helperError: - return decoration.helperError; - case _DecorationSlot.counter: - return decoration.counter; - case _DecorationSlot.container: - return decoration.container; - } - } + _DecorationElement createElement() => _DecorationElement(this); @override _RenderDecoration createRenderObject(BuildContext context) { @@ -2308,7 +2443,6 @@ class _InputDecoratorState extends State with TickerProviderStat contentPadding: contentPadding, isCollapsed: decoration!.isCollapsed, floatingLabelHeight: floatingLabelHeight, - floatingLabelAlignment: decoration!.floatingLabelAlignment!, floatingLabelProgress: _floatingLabelController.value, border: border, borderGap: _borderGap, @@ -2394,7 +2528,7 @@ class _InputDecoratorState extends State with TickerProviderStat /// ** See code in examples/api/lib/material/input_decorator/input_decoration.3.dart ** /// {@end-tool} /// -/// {@tool dartpad} +/// {@tool dartpad --template=stateless_widget_scaffold} /// This sample shows how to style a `TextField` with a prefixIcon that changes color /// based on the `MaterialState`. The color defaults to gray, be blue while focused /// and red if in an error state. @@ -2402,7 +2536,7 @@ class _InputDecoratorState extends State with TickerProviderStat /// ** See code in examples/api/lib/material/input_decorator/input_decoration.material_state.0.dart ** /// {@end-tool} /// -/// {@tool dartpad} +/// {@tool dartpad --template=stateless_widget_scaffold} /// This sample shows how to style a `TextField` with a prefixIcon that changes color /// based on the `MaterialState` through the use of `ThemeData`. The color defaults /// to gray, be blue while focused and red if in an error state. @@ -2451,7 +2585,6 @@ class InputDecoration { this.errorStyle, this.errorMaxLines, this.floatingLabelBehavior, - this.floatingLabelAlignment, this.isCollapsed = false, this.isDense, this.contentPadding, @@ -2497,7 +2630,6 @@ class InputDecoration { const InputDecoration.collapsed({ required this.hintText, this.floatingLabelBehavior, - this.floatingLabelAlignment, this.hintStyle, this.hintTextDirection, this.filled = false, @@ -2577,9 +2709,8 @@ class InputDecoration { /// When the input field is empty and unfocused, the label is displayed on /// top of the input field (i.e., at the same location on the screen where /// text may be entered in the input field). When the input field receives - /// focus (or if the field is non-empty), depending on [floatingLabelAlignment], - /// the label moves above, either vertically adjacent to, or to the center of - /// the input field. + /// focus (or if the field is non-empty), the label moves above (i.e., + /// vertically adjacent to) the input field. /// {@endtemplate} /// /// This can be used, for example, to add multiple [TextStyle]'s to a label that would @@ -2603,65 +2734,28 @@ class InputDecoration { /// Only one of [label] and [labelText] can be specified. final String? labelText; - /// {@template flutter.material.inputDecoration.labelStyle} - /// The style to use for [InputDecoration.labelText] when the label is on top - /// of the input field. + /// The style to use for the [labelText] when the label is on top of the + /// input field. /// /// If [labelStyle] is a [MaterialStateTextStyle], then the effective /// text style can depend on the [MaterialState.focused] state, i.e. /// if the [TextField] is focused or not. /// - /// When the [InputDecoration.labelText] is above (i.e., vertically adjacent to) - /// the input field, the text uses the [floatingLabelStyle] instead. + /// When the [labelText] is above (i.e., vertically adjacent to) the input + /// field, the text uses the [floatingLabelStyle] instead. /// /// If null, defaults to a value derived from the base [TextStyle] for the /// input field and the current [Theme]. - /// - /// Note that if you specify this style it will override the default behavior - /// of [InputDecoration] that changes the color of the label to the - /// [InputDecoration.errorStyle] color or [ThemeData.errorColor]. - /// - /// {@tool dartpad} - /// It's possible to override the label style for just the error state, or - /// just the default state, or both. - /// - /// In this example the [labelStyle] is specified with a [MaterialStateProperty] - /// which resolves to a text style whose color depends on the decorator's - /// error state. - /// - /// ** See code in examples/api/lib/material/input_decorator/input_decoration.label_style_error.0.dart ** - /// {@end-tool} - /// {@endtemplate} final TextStyle? labelStyle; - /// {@template flutter.material.inputDecoration.floatingLabelStyle} - /// The style to use for [InputDecoration.labelText] when the label is - /// above (i.e., vertically adjacent to) the input field. - /// - /// When the [InputDecoration.labelText] is on top of the input field, the - /// text uses the [labelStyle] instead. + /// The style to use for the [labelText] when the label is above (i.e., + /// vertically adjacent to) the input field. /// /// If [floatingLabelStyle] is a [MaterialStateTextStyle], then the effective /// text style can depend on the [MaterialState.focused] state, i.e. /// if the [TextField] is focused or not. /// /// If null, defaults to [labelStyle]. - /// - /// Note that if you specify this style it will override the default behavior - /// of [InputDecoration] that changes the color of the label to the - /// [InputDecoration.errorStyle] color or [ThemeData.errorColor]. - /// - /// {@tool dartpad} - /// It's possible to override the label style for just the error state, or - /// just the default state, or both. - /// - /// In this example the [floatingLabelStyle] is specified with a - /// [MaterialStateProperty] which resolves to a text style whose color depends - /// on the decorator's error state. - /// - /// ** See code in examples/api/lib/material/input_decorator/input_decoration.floating_label_style_error.0.dart ** - /// {@end-tool} - /// {@endtemplate} final TextStyle? floatingLabelStyle; /// Text that provides context about the [InputDecorator.child]'s value, such @@ -2738,18 +2832,10 @@ class InputDecoration { /// [TextFormField.validator], if that is not null. final String? errorText; - /// {@template flutter.material.inputDecoration.errorStyle} - /// The style to use for the [InputDecoration.errorText]. + /// The style to use for the [errorText]. /// /// If null, defaults of a value derived from the base [TextStyle] for the /// input field and the current [Theme]. - /// - /// By default the color of style will be used by the label of - /// [InputDecoration] if [InputDecoration.errorText] is not null. See - /// [InputDecoration.labelStyle] or [InputDecoration.floatingLabelStyle] for - /// an example of how to replicate this behavior if you have specified either - /// style. - /// {@endtemplate} final TextStyle? errorStyle; @@ -2767,7 +2853,7 @@ class InputDecoration { final int? errorMaxLines; /// {@template flutter.material.inputDecoration.floatingLabelBehavior} - /// Defines **how** the floating label should behave. + /// Defines how the floating label should be displayed. /// /// When [FloatingLabelBehavior.auto] the label will float to the top only when /// the field is focused or has some text content, otherwise it will appear @@ -2781,33 +2867,8 @@ class InputDecoration { /// {@endtemplate} /// /// If null, [InputDecorationTheme.floatingLabelBehavior] will be used. - /// - /// See also: - /// - /// * [floatingLabelAlignment] which defines **where** the floating label - /// should be displayed. final FloatingLabelBehavior? floatingLabelBehavior; - /// {@template flutter.material.inputDecoration.floatingLabelAlignment} - /// Defines **where** the floating label should be displayed. - /// - /// [FloatingLabelAlignment.start] aligns the floating label to the leftmost - /// (when [TextDirection.ltr]) or rightmost (when [TextDirection.rtl]), - /// possible position, which is vertically adjacent to the label, on top of - /// the field. - /// - /// [FloatingLabelAlignment.center] aligns the floating label to the center on - /// top of the field. - /// {@endtemplate} - /// - /// If null, [InputDecorationTheme.floatingLabelAlignment] will be used. - /// - /// See also: - /// - /// * [floatingLabelBehavior] which defines **how** the floating label should - /// behave. - final FloatingLabelAlignment? floatingLabelAlignment; - /// Whether the [InputDecorator.child] is part of a dense form (i.e., uses less vertical /// space). /// @@ -3380,7 +3441,6 @@ class InputDecoration { TextStyle? errorStyle, int? errorMaxLines, FloatingLabelBehavior? floatingLabelBehavior, - FloatingLabelAlignment? floatingLabelAlignment, bool? isCollapsed, bool? isDense, EdgeInsetsGeometry? contentPadding, @@ -3432,7 +3492,6 @@ class InputDecoration { errorStyle: errorStyle ?? this.errorStyle, errorMaxLines: errorMaxLines ?? this.errorMaxLines, floatingLabelBehavior: floatingLabelBehavior ?? this.floatingLabelBehavior, - floatingLabelAlignment: floatingLabelAlignment ?? this.floatingLabelAlignment, isCollapsed: isCollapsed ?? this.isCollapsed, isDense: isDense ?? this.isDense, contentPadding: contentPadding ?? this.contentPadding, @@ -3483,7 +3542,6 @@ class InputDecoration { errorStyle: errorStyle ?? theme.errorStyle, errorMaxLines: errorMaxLines ?? theme.errorMaxLines, floatingLabelBehavior: floatingLabelBehavior ?? theme.floatingLabelBehavior, - floatingLabelAlignment: floatingLabelAlignment ?? theme.floatingLabelAlignment, isCollapsed: isCollapsed, isDense: isDense ?? theme.isDense, contentPadding: contentPadding ?? theme.contentPadding, @@ -3529,7 +3587,6 @@ class InputDecoration { && other.errorStyle == errorStyle && other.errorMaxLines == errorMaxLines && other.floatingLabelBehavior == floatingLabelBehavior - && other.floatingLabelAlignment == floatingLabelAlignment && other.isDense == isDense && other.contentPadding == contentPadding && other.isCollapsed == isCollapsed @@ -3584,7 +3641,6 @@ class InputDecoration { errorStyle, errorMaxLines, floatingLabelBehavior, - floatingLabelAlignment, isDense, contentPadding, isCollapsed, @@ -3639,7 +3695,6 @@ class InputDecoration { if (errorStyle != null) 'errorStyle: "$errorStyle"', if (errorMaxLines != null) 'errorMaxLines: "$errorMaxLines"', if (floatingLabelBehavior != null) 'floatingLabelBehavior: $floatingLabelBehavior', - if (floatingLabelAlignment != null) 'floatingLabelAlignment: $floatingLabelAlignment', if (isDense ?? false) 'isDense: $isDense', if (contentPadding != null) 'contentPadding: $contentPadding', if (isCollapsed) 'isCollapsed: $isCollapsed', @@ -3691,8 +3746,8 @@ class InputDecorationTheme with Diagnosticable { /// Creates a value for [ThemeData.inputDecorationTheme] that /// defines default values for [InputDecorator]. /// - /// The values of [isDense], [isCollapsed], [filled], [floatingLabelAlignment], - /// and [border] must not be null. + /// The values of [isDense], [isCollapsed], [filled], and [border] must + /// not be null. const InputDecorationTheme({ this.labelStyle, this.floatingLabelStyle, @@ -3702,7 +3757,6 @@ class InputDecorationTheme with Diagnosticable { this.errorStyle, this.errorMaxLines, this.floatingLabelBehavior = FloatingLabelBehavior.auto, - this.floatingLabelAlignment = FloatingLabelAlignment.start, this.isDense = false, this.contentPadding, this.isCollapsed = false, @@ -3726,14 +3780,34 @@ class InputDecorationTheme with Diagnosticable { this.constraints, }) : assert(isDense != null), assert(isCollapsed != null), - assert(floatingLabelAlignment != null), assert(filled != null), assert(alignLabelWithHint != null); - /// {@macro flutter.material.inputDecoration.labelStyle} + /// The style to use for [InputDecoration.labelText] when the label is on top + /// of the input field. + /// + /// When the [InputDecoration.labelText] is floating above the input field, + /// the text uses the [floatingLabelStyle] instead. + /// + /// If [labelStyle] is a [MaterialStateTextStyle], then the effective + /// text style can depend on the [MaterialState.focused] state, i.e. + /// if the [TextField] is focused or not. + /// + /// If null, defaults to a value derived from the base [TextStyle] for the + /// input field and the current [Theme]. final TextStyle? labelStyle; - /// {@macro flutter.material.inputDecoration.floatingLabelStyle} + /// The style to use for [InputDecoration.labelText] when the label is + /// above (i.e., vertically adjacent to) the input field. + /// + /// When the [InputDecoration.labelText] is on top of the input field, the + /// text uses the [labelStyle] instead. + /// + /// If [floatingLabelStyle] is a [MaterialStateTextStyle], then the effective + /// text style can depend on the [MaterialState.focused] state, i.e. + /// if the [TextField] is focused or not. + /// + /// If null, defaults to [labelStyle]. final TextStyle? floatingLabelStyle; /// The style to use for [InputDecoration.helperText]. @@ -3771,7 +3845,10 @@ class InputDecorationTheme with Diagnosticable { /// input field and the current [Theme]. final TextStyle? hintStyle; - /// {@macro flutter.material.inputDecoration.errorStyle} + /// The style to use for the [InputDecoration.errorText]. + /// + /// If null, defaults of a value derived from the base [TextStyle] for the + /// input field and the current [Theme]. final TextStyle? errorStyle; /// The maximum number of lines the [InputDecoration.errorText] can occupy. @@ -3792,11 +3869,6 @@ class InputDecorationTheme with Diagnosticable { /// Defaults to [FloatingLabelBehavior.auto]. final FloatingLabelBehavior floatingLabelBehavior; - /// {@macro flutter.material.inputDecoration.floatingLabelAlignment} - /// - /// Defaults to [FloatingLabelAlignment.start]. - final FloatingLabelAlignment floatingLabelAlignment; - /// Whether the input decorator's child is part of a dense form (i.e., uses /// less vertical space). /// @@ -4105,7 +4177,6 @@ class InputDecorationTheme with Diagnosticable { TextStyle? errorStyle, int? errorMaxLines, FloatingLabelBehavior? floatingLabelBehavior, - FloatingLabelAlignment? floatingLabelAlignment, bool? isDense, EdgeInsetsGeometry? contentPadding, bool? isCollapsed, @@ -4137,7 +4208,6 @@ class InputDecorationTheme with Diagnosticable { errorStyle: errorStyle ?? this.errorStyle, errorMaxLines: errorMaxLines ?? this.errorMaxLines, floatingLabelBehavior: floatingLabelBehavior ?? this.floatingLabelBehavior, - floatingLabelAlignment: floatingLabelAlignment ?? this.floatingLabelAlignment, isDense: isDense ?? this.isDense, contentPadding: contentPadding ?? this.contentPadding, iconColor: iconColor, @@ -4173,7 +4243,6 @@ class InputDecorationTheme with Diagnosticable { errorStyle, errorMaxLines, floatingLabelBehavior, - floatingLabelAlignment, isDense, contentPadding, isCollapsed, @@ -4222,7 +4291,6 @@ class InputDecorationTheme with Diagnosticable { && other.suffixIconColor == suffixIconColor && other.counterStyle == counterStyle && other.floatingLabelBehavior == floatingLabelBehavior - && other.floatingLabelAlignment == floatingLabelAlignment && other.filled == filled && other.fillColor == fillColor && other.focusColor == focusColor @@ -4250,7 +4318,6 @@ class InputDecorationTheme with Diagnosticable { properties.add(DiagnosticsProperty('errorStyle', errorStyle, defaultValue: defaultTheme.errorStyle)); properties.add(IntProperty('errorMaxLines', errorMaxLines, defaultValue: defaultTheme.errorMaxLines)); properties.add(DiagnosticsProperty('floatingLabelBehavior', floatingLabelBehavior, defaultValue: defaultTheme.floatingLabelBehavior)); - properties.add(DiagnosticsProperty('floatingLabelAlignment', floatingLabelAlignment, defaultValue: defaultTheme.floatingLabelAlignment)); properties.add(DiagnosticsProperty('isDense', isDense, defaultValue: defaultTheme.isDense)); properties.add(DiagnosticsProperty('contentPadding', contentPadding, defaultValue: defaultTheme.contentPadding)); properties.add(DiagnosticsProperty('isCollapsed', isCollapsed, defaultValue: defaultTheme.isCollapsed)); diff --git a/packages/flutter/lib/src/material/list_tile.dart b/packages/flutter/lib/src/material/list_tile.dart index 71032f987bc55..1c68b55c9c67e 100644 --- a/packages/flutter/lib/src/material/list_tile.dart +++ b/packages/flutter/lib/src/material/list_tile.dart @@ -1041,31 +1041,33 @@ class ListTile extends StatelessWidget { /// See also: /// /// * [Divider], which you can use to obtain this effect manually. - static Iterable divideTiles({ BuildContext? context, required Iterable tiles, Color? color }) { + static Iterable divideTiles({ BuildContext? context, required Iterable tiles, Color? color }) sync* { assert(tiles != null); assert(color != null || context != null); - tiles = tiles.toList(); - if (tiles.isEmpty || tiles.length == 1) { - return tiles; - } + final Iterator iterator = tiles.iterator; + final bool hasNext = iterator.moveNext(); + + if (!hasNext) + return; + + final Decoration decoration = BoxDecoration( + border: Border( + bottom: Divider.createBorderSide(context, color: color), + ), + ); - Widget wrapTile(Widget tile) { - return DecoratedBox( + Widget tile = iterator.current; + while (iterator.moveNext()) { + yield DecoratedBox( position: DecorationPosition.foreground, - decoration: BoxDecoration( - border: Border( - bottom: Divider.createBorderSide(context, color: color), - ), - ), + decoration: decoration, child: tile, ); + tile = iterator.current; } - - return [ - ...tiles.take(tiles.length - 1).map(wrapTile), - tiles.last, - ]; + if (hasNext) + yield tile; } Color? _iconColor(ThemeData theme, ListTileThemeData tileTheme) { @@ -1264,7 +1266,7 @@ enum _ListTileSlot { trailing, } -class _ListTile extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin<_ListTileSlot> { +class _ListTile extends RenderObjectWidget { const _ListTile({ Key? key, this.leading, @@ -1305,21 +1307,7 @@ class _ListTile extends RenderObjectWidget with SlottedMultiChildRenderObjectWid final double minLeadingWidth; @override - Iterable<_ListTileSlot> get slots => _ListTileSlot.values; - - @override - Widget? childForSlot(_ListTileSlot slot) { - switch (slot) { - case _ListTileSlot.leading: - return leading; - case _ListTileSlot.title: - return title; - case _ListTileSlot.subtitle: - return subtitle; - case _ListTileSlot.trailing: - return trailing; - } - } + _ListTileElement createElement() => _ListTileElement(this); @override _RenderListTile createRenderObject(BuildContext context) { @@ -1351,7 +1339,111 @@ class _ListTile extends RenderObjectWidget with SlottedMultiChildRenderObjectWid } } -class _RenderListTile extends RenderBox with SlottedContainerRenderObjectMixin<_ListTileSlot> { +class _ListTileElement extends RenderObjectElement { + _ListTileElement(_ListTile widget) : super(widget); + + final Map<_ListTileSlot, Element> slotToChild = <_ListTileSlot, Element>{}; + + @override + _ListTile get widget => super.widget as _ListTile; + + @override + _RenderListTile get renderObject => super.renderObject as _RenderListTile; + + @override + void visitChildren(ElementVisitor visitor) { + slotToChild.values.forEach(visitor); + } + + @override + void forgetChild(Element child) { + assert(slotToChild.containsValue(child)); + assert(child.slot is _ListTileSlot); + assert(slotToChild.containsKey(child.slot)); + slotToChild.remove(child.slot); + super.forgetChild(child); + } + + void _mountChild(Widget? widget, _ListTileSlot slot) { + final Element? oldChild = slotToChild[slot]; + final Element? newChild = updateChild(oldChild, widget, slot); + if (oldChild != null) { + slotToChild.remove(slot); + } + if (newChild != null) { + slotToChild[slot] = newChild; + } + } + + @override + void mount(Element? parent, Object? newSlot) { + super.mount(parent, newSlot); + _mountChild(widget.leading, _ListTileSlot.leading); + _mountChild(widget.title, _ListTileSlot.title); + _mountChild(widget.subtitle, _ListTileSlot.subtitle); + _mountChild(widget.trailing, _ListTileSlot.trailing); + } + + void _updateChild(Widget? widget, _ListTileSlot slot) { + final Element? oldChild = slotToChild[slot]; + final Element? newChild = updateChild(oldChild, widget, slot); + if (oldChild != null) { + slotToChild.remove(slot); + } + if (newChild != null) { + slotToChild[slot] = newChild; + } + } + + @override + void update(_ListTile newWidget) { + super.update(newWidget); + assert(widget == newWidget); + _updateChild(widget.leading, _ListTileSlot.leading); + _updateChild(widget.title, _ListTileSlot.title); + _updateChild(widget.subtitle, _ListTileSlot.subtitle); + _updateChild(widget.trailing, _ListTileSlot.trailing); + } + + void _updateRenderObject(RenderBox? child, _ListTileSlot slot) { + switch (slot) { + case _ListTileSlot.leading: + renderObject.leading = child; + break; + case _ListTileSlot.title: + renderObject.title = child; + break; + case _ListTileSlot.subtitle: + renderObject.subtitle = child; + break; + case _ListTileSlot.trailing: + renderObject.trailing = child; + break; + } + } + + @override + void insertRenderObjectChild(RenderObject child, _ListTileSlot slot) { + assert(child is RenderBox); + _updateRenderObject(child as RenderBox, slot); + assert(renderObject.children.keys.contains(slot)); + } + + @override + void removeRenderObjectChild(RenderObject child, _ListTileSlot slot) { + assert(child is RenderBox); + assert(renderObject.children[slot] == child); + _updateRenderObject(null, slot); + assert(!renderObject.children.keys.contains(slot)); + } + + @override + void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) { + assert(false, 'not reachable'); + } +} + +class _RenderListTile extends RenderBox { _RenderListTile({ required bool isDense, required VisualDensity visualDensity, @@ -1380,24 +1472,54 @@ class _RenderListTile extends RenderBox with SlottedContainerRenderObjectMixin<_ _minVerticalPadding = minVerticalPadding, _minLeadingWidth = minLeadingWidth; - RenderBox? get leading => childForSlot(_ListTileSlot.leading); - RenderBox? get title => childForSlot(_ListTileSlot.title); - RenderBox? get subtitle => childForSlot(_ListTileSlot.subtitle); - RenderBox? get trailing => childForSlot(_ListTileSlot.trailing); + final Map<_ListTileSlot, RenderBox> children = <_ListTileSlot, RenderBox>{}; + + RenderBox? _updateChild(RenderBox? oldChild, RenderBox? newChild, _ListTileSlot slot) { + if (oldChild != null) { + dropChild(oldChild); + children.remove(slot); + } + if (newChild != null) { + children[slot] = newChild; + adoptChild(newChild); + } + return newChild; + } + + RenderBox? _leading; + RenderBox? get leading => _leading; + set leading(RenderBox? value) { + _leading = _updateChild(_leading, value, _ListTileSlot.leading); + } + + RenderBox? _title; + RenderBox? get title => _title; + set title(RenderBox? value) { + _title = _updateChild(_title, value, _ListTileSlot.title); + } + + RenderBox? _subtitle; + RenderBox? get subtitle => _subtitle; + set subtitle(RenderBox? value) { + _subtitle = _updateChild(_subtitle, value, _ListTileSlot.subtitle); + } + + RenderBox? _trailing; + RenderBox? get trailing => _trailing; + set trailing(RenderBox? value) { + _trailing = _updateChild(_trailing, value, _ListTileSlot.trailing); + } // The returned list is ordered for hit testing. - @override - Iterable get children { - return [ - if (leading != null) - leading!, - if (title != null) - title!, - if (subtitle != null) - subtitle!, - if (trailing != null) - trailing!, - ]; + Iterable get _children sync* { + if (leading != null) + yield leading!; + if (title != null) + yield title!; + if (subtitle != null) + yield subtitle!; + if (trailing != null) + yield trailing!; } bool get isDense => _isDense; @@ -1493,6 +1615,44 @@ class _RenderListTile extends RenderBox with SlottedContainerRenderObjectMixin<_ markNeedsLayout(); } + @override + void attach(PipelineOwner owner) { + super.attach(owner); + for (final RenderBox child in _children) + child.attach(owner); + } + + @override + void detach() { + super.detach(); + for (final RenderBox child in _children) + child.detach(); + } + + @override + void redepthChildren() { + _children.forEach(redepthChild); + } + + @override + void visitChildren(RenderObjectVisitor visitor) { + _children.forEach(visitor); + } + + @override + List debugDescribeChildren() { + final List value = []; + void add(RenderBox? child, String name) { + if (child != null) + value.add(child.toDiagnosticsNode(name: name)); + } + add(leading, 'leading'); + add(title, 'title'); + add(subtitle, 'subtitle'); + add(trailing, 'trailing'); + return value; + } + @override bool get sizedByParent => false; @@ -1745,7 +1905,7 @@ class _RenderListTile extends RenderBox with SlottedContainerRenderObjectMixin<_ @override bool hitTestChildren(BoxHitTestResult result, { required Offset position }) { assert(position != null); - for (final RenderBox child in children) { + for (final RenderBox child in _children) { final BoxParentData parentData = child.parentData! as BoxParentData; final bool isHit = result.addWithPaintOffset( offset: parentData.offset, diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart index 12dd8f48704d2..2af28f7ae6951 100644 --- a/packages/flutter/lib/src/material/material.dart +++ b/packages/flutter/lib/src/material/material.dart @@ -91,7 +91,6 @@ abstract class MaterialInkController { /// 1. Clipping: If [clipBehavior] is not [Clip.none], Material clips its widget /// sub-tree to the shape specified by [shape], [type], and [borderRadius]. /// By default, [clipBehavior] is [Clip.none] for performance considerations. -/// See [Ink] for an example of how this affects clipping [Ink] widgets. /// 2. Elevation: Material elevates its widget sub-tree on the Z axis by /// [elevation] pixels, and draws the appropriate shadow. /// 3. Ink effects: Material shows ink effects implemented by [InkFeature]s diff --git a/packages/flutter/lib/src/material/material_state.dart b/packages/flutter/lib/src/material/material_state.dart index 91cc0da4c76a5..15878d9690644 100644 --- a/packages/flutter/lib/src/material/material_state.dart +++ b/packages/flutter/lib/src/material/material_state.dart @@ -19,7 +19,6 @@ import 'input_border.dart'; /// /// * [MaterialStateProperty], an interface for objects that "resolve" to /// different values depending on a widget's material state. -/// {@template flutter.material.MaterialStateProperty.implementations} /// * [MaterialStateColor], a [Color] that implements `MaterialStateProperty` /// which is used in APIs that need to accept either a [Color] or a /// `MaterialStateProperty`. @@ -29,19 +28,10 @@ import 'input_border.dart'; /// * [MaterialStateOutlinedBorder], an [OutlinedBorder] that implements /// `MaterialStateProperty` which is used in APIs that need to accept either /// an [OutlinedBorder] or a [MaterialStateProperty]. -/// * [MaterialStateOutlineInputBorder], an [OutlineInputBorder] that implements -/// `MaterialStateProperty` which is used in APIs that need to accept either -/// an [OutlineInputBorder] or a [MaterialStateProperty]. -/// * [MaterialStateUnderlineInputBorder], an [UnderlineInputBorder] that implements -/// `MaterialStateProperty` which is used in APIs that need to accept either -/// an [UnderlineInputBorder] or a [MaterialStateProperty]. /// * [MaterialStateBorderSide], a [BorderSide] that implements /// `MaterialStateProperty` which is used in APIs that need to accept either /// a [BorderSide] or a [MaterialStateProperty]. -/// * [MaterialStateTextStyle], a [TextStyle] that implements -/// `MaterialStateProperty` which is used in APIs that need to accept either -/// a [TextStyle] or a [MaterialStateProperty]. -/// {@endtemplate} + enum MaterialState { /// The state when the user drags their mouse cursor over the given widget. /// @@ -621,7 +611,12 @@ class _MaterialStateUnderlineInputBorder extends MaterialStateUnderlineInputBord /// /// See also: /// -/// {@macro flutter.material.MaterialStateProperty.implementations} +/// * [MaterialStateColor], a [Color] that implements `MaterialStateProperty` +/// which is used in APIs that need to accept either a [Color] or a +/// `MaterialStateProperty`. +/// * [MaterialStateMouseCursor], a [MouseCursor] that implements `MaterialStateProperty` +/// which is used in APIs that need to accept either a [MouseCursor] or a +/// [MaterialStateProperty]. abstract class MaterialStateProperty { /// Returns a value of type `T` that depends on [states]. diff --git a/packages/flutter/lib/src/material/mergeable_material.dart b/packages/flutter/lib/src/material/mergeable_material.dart index 4c206f567e974..0e32e8e694f21 100644 --- a/packages/flutter/lib/src/material/mergeable_material.dart +++ b/packages/flutter/lib/src/material/mergeable_material.dart @@ -151,13 +151,14 @@ class _AnimationTuple { required this.startAnimation, required this.endAnimation, required this.gapAnimation, + this.gapStart = 0.0, }); final AnimationController controller; final CurvedAnimation startAnimation; final CurvedAnimation endAnimation; final CurvedAnimation gapAnimation; - double gapStart = 0.0; + double gapStart; } class _MergeableMaterialState extends State with TickerProviderStateMixin { @@ -167,7 +168,7 @@ class _MergeableMaterialState extends State with TickerProvid @override void initState() { super.initState(); - _children = List.of(widget.children); + _children = List.from(widget.children); for (int i = 0; i < _children.length; i += 1) { final MergeableMaterialItem child = _children[i]; diff --git a/packages/flutter/lib/src/material/navigation_bar.dart b/packages/flutter/lib/src/material/navigation_bar.dart index 79d1691adb4df..4ebb4e7c28579 100644 --- a/packages/flutter/lib/src/material/navigation_bar.dart +++ b/packages/flutter/lib/src/material/navigation_bar.dart @@ -300,7 +300,7 @@ class NavigationDestination extends StatelessWidget { return Stack( alignment: Alignment.center, children: [ - NavigationIndicator( + _NavigationIndicator( animation: animation, color: navigationBarTheme.indicatorColor, ), @@ -507,24 +507,20 @@ class _NavigationDestinationInfo extends InheritedWidget { } } -/// Selection Indicator for the Material 3 [NavigationBar] and [NavigationRail] -/// components. +/// Selection Indicator for the Material 3 Navigation Bar component. /// /// When [animation] is 0, the indicator is not present. As [animation] grows /// from 0 to 1, the indicator scales in on the x axis. /// -/// Used in a [Stack] widget behind the icons in the Material 3 Navigation Bar +/// Useful in a [Stack] widget behind the icons in the Material 3 Navigation Bar /// to illuminate the selected destination. -class NavigationIndicator extends StatelessWidget { +class _NavigationIndicator extends StatelessWidget { /// Builds an indicator, usually used in a stack behind the icon of a /// navigation bar destination. - const NavigationIndicator({ + const _NavigationIndicator({ Key? key, required this.animation, this.color, - this.width = 64, - this.height = 32, - this.borderRadius = const BorderRadius.all(Radius.circular(16)), }) : super(key: key); /// Determines the scale of the indicator. @@ -538,21 +534,6 @@ class NavigationIndicator extends StatelessWidget { /// If null, defaults to [ColorScheme.secondary]. final Color? color; - /// The width of the container that holds in the indicator. - /// - /// Defaults to `64`. - final double width; - - /// The height of the container that holds in the indicator. - /// - /// Defaults to `32`. - final double height; - - /// The radius of the container that holds in the indicator. - /// - /// Defaults to `BorderRadius.circular(16)`. - final BorderRadius borderRadius; - @override Widget build(BuildContext context) { final ColorScheme colorScheme = Theme.of(context).colorScheme; @@ -592,10 +573,10 @@ class NavigationIndicator extends StatelessWidget { return FadeTransition( opacity: fadeAnimation, child: Container( - width: width, - height: height, + width: 64.0, + height: 32.0, decoration: BoxDecoration( - borderRadius: borderRadius, + borderRadius: const BorderRadius.all(Radius.circular(16.0)), color: color ?? colorScheme.secondary.withOpacity(.24), ), ), @@ -898,10 +879,18 @@ class _ClampTextScaleFactor extends StatelessWidget { /// surrounding [child]. const _ClampTextScaleFactor({ Key? key, + this.lowerLimit = 0, this.upperLimit = double.infinity, required this.child, }) : super(key: key); + /// The minimum amount that the text scale factor should be for the [child] + /// widget. + /// + /// If this is `.5`, the textScaleFactor for child widgets will never be + /// smaller than `.5`. + final double lowerLimit; + /// The maximum amount that the text scale factor should be for the [child] /// widget. /// @@ -918,7 +907,7 @@ class _ClampTextScaleFactor extends StatelessWidget { return MediaQuery( data: MediaQuery.of(context).copyWith( textScaleFactor: MediaQuery.of(context).textScaleFactor.clamp( - 0.0, + lowerLimit, upperLimit, ), ), diff --git a/packages/flutter/lib/src/material/navigation_rail.dart b/packages/flutter/lib/src/material/navigation_rail.dart index 5687d131729ac..99ae67dc8d722 100644 --- a/packages/flutter/lib/src/material/navigation_rail.dart +++ b/packages/flutter/lib/src/material/navigation_rail.dart @@ -10,7 +10,6 @@ import 'color_scheme.dart'; import 'ink_well.dart'; import 'material.dart'; import 'material_localizations.dart'; -import 'navigation_bar.dart'; import 'navigation_rail_theme.dart'; import 'theme.dart'; @@ -95,8 +94,6 @@ class NavigationRail extends StatefulWidget { this.selectedIconTheme, this.minWidth, this.minExtendedWidth, - this.useIndicator, - this.indicatorColor, }) : assert(destinations != null && destinations.length >= 2), assert(selectedIndex != null), assert(0 <= selectedIndex && selectedIndex < destinations.length), @@ -282,21 +279,6 @@ class NavigationRail extends StatefulWidget { /// The default value is 256. final double? minExtendedWidth; - /// If `true`, adds a rounded [NavigationIndicator] behind the selected - /// destination's icon. - /// - /// The indicator's shape will be circular if [labelType] is - /// [NavigationRailLabelType.none], or a [StadiumBorder] if [labelType] is - /// [NavigationRailLabelType.all] or [NavigationRailLabelType.selected]. - /// - /// If `null`, defaults to [NavigationRailThemeData.useIndicator]. If that is - /// `null`, defaults to [ThemeData.useMaterial3]. - final bool? useIndicator; - - /// Overrides the default value of [NavigationRail]'s selection indicator color, - /// when [useIndicator] is true. - final Color? indicatorColor; - /// Returns the animation that controls the [NavigationRail.extended] state. /// /// This can be used to synchronize animations in the [leading] or [trailing] @@ -431,8 +413,6 @@ class _NavigationRailState extends State with TickerProviderStat iconTheme: widget.selectedIndex == i ? selectedIconTheme : unselectedIconTheme, labelTextStyle: widget.selectedIndex == i ? selectedLabelTextStyle : unselectedLabelTextStyle, padding: widget.destinations[i].padding, - useIndicator: widget.useIndicator ?? navigationRailTheme.useIndicator ?? theme.useMaterial3, - indicatorColor: widget.indicatorColor ?? navigationRailTheme.indicatorColor, onTap: () { if (widget.onDestinationSelected != null) widget.onDestinationSelected!(i); @@ -518,8 +498,6 @@ class _RailDestination extends StatelessWidget { required this.onTap, required this.indexLabel, this.padding, - required this.useIndicator, - this.indicatorColor, }) : assert(minWidth != null), assert(minExtendedWidth != null), assert(icon != null), @@ -551,18 +529,11 @@ class _RailDestination extends StatelessWidget { final VoidCallback onTap; final String indexLabel; final EdgeInsetsGeometry? padding; - final bool useIndicator; - final Color? indicatorColor; final Animation _positionAnimation; @override Widget build(BuildContext context) { - assert( - useIndicator || indicatorColor == null, - '[NavigationRail.indicatorColor] does not have an effect when [NavigationRail.useIndicator] is false', - ); - final Widget themedIcon = IconTheme( data: iconTheme, child: icon, @@ -571,19 +542,13 @@ class _RailDestination extends StatelessWidget { style: labelTextStyle, child: label, ); - final Widget content; - switch (labelType) { case NavigationRailLabelType.none: final Widget iconPart = SizedBox( width: minWidth, height: minWidth, - child: _AddIndicator( - addIndicator: useIndicator, - indicatorColor: indicatorColor, - isCircular: true, - indicatorAnimation: destinationAnimation, + child: Align( child: themedIcon, ), ); @@ -641,7 +606,6 @@ class _RailDestination extends StatelessWidget { final double verticalPadding = lerpDouble(_verticalDestinationPaddingNoLabel, _verticalDestinationPaddingWithLabel, appearingAnimationValue)!; final Interval interval = selected ? const Interval(0.25, 0.75) : const Interval(0.75, 1.0); final Animation labelFadeAnimation = destinationAnimation.drive(CurveTween(curve: interval)); - content = Container( constraints: BoxConstraints( minWidth: minWidth, @@ -654,13 +618,7 @@ class _RailDestination extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox(height: verticalPadding), - _AddIndicator( - addIndicator: useIndicator, - indicatorColor: indicatorColor, - isCircular: false, - indicatorAnimation: destinationAnimation, - child: themedIcon, - ), + themedIcon, Align( alignment: Alignment.topCenter, heightFactor: appearingAnimationValue, @@ -687,13 +645,7 @@ class _RailDestination extends StatelessWidget { child: Column( children: [ const SizedBox(height: _verticalDestinationPaddingWithLabel), - _AddIndicator( - addIndicator: useIndicator, - indicatorColor: indicatorColor, - isCircular: false, - indicatorAnimation: destinationAnimation, - child: themedIcon, - ), + themedIcon, styledLabel, const SizedBox(height: _verticalDestinationPaddingWithLabel), ], @@ -730,62 +682,6 @@ class _RailDestination extends StatelessWidget { } } -/// When [addIndicator] is `true`, puts [child] center aligned in a [Stack] with -/// a [NavigationIndicator] behind it, otherwise returns [child]. -/// -/// When [isCircular] is true, the indicator will be a circle, otherwise the -/// indicator will be a stadium shape. -class _AddIndicator extends StatelessWidget { - const _AddIndicator({ - Key? key, - required this.addIndicator, - required this.isCircular, - required this.indicatorColor, - required this.indicatorAnimation, - required this.child, - }) : super(key: key); - - final bool addIndicator; - final bool isCircular; - final Color? indicatorColor; - final Animation indicatorAnimation; - final Widget child; - - @override - Widget build(BuildContext context) { - if (!addIndicator) { - return child; - } - late final Widget indicator; - if (isCircular) { - const double circularIndicatorDiameter = 56; - indicator = NavigationIndicator( - animation: indicatorAnimation, - height: circularIndicatorDiameter, - width: circularIndicatorDiameter, - borderRadius: BorderRadius.circular(circularIndicatorDiameter / 2), - color: indicatorColor, - ); - } else { - indicator = NavigationIndicator( - animation: indicatorAnimation, - width: 56, - borderRadius: BorderRadius.circular(16), - color: indicatorColor, - ); - } - - return Stack( - alignment: Alignment.center, - children: [ - indicator, - child, - ], - ); - } -} - - /// Defines the behavior of the labels of a [NavigationRail]. /// /// See also: diff --git a/packages/flutter/lib/src/material/navigation_rail_theme.dart b/packages/flutter/lib/src/material/navigation_rail_theme.dart index addc33ac5fd82..50d97e506b81f 100644 --- a/packages/flutter/lib/src/material/navigation_rail_theme.dart +++ b/packages/flutter/lib/src/material/navigation_rail_theme.dart @@ -44,8 +44,6 @@ class NavigationRailThemeData with Diagnosticable { this.selectedIconTheme, this.groupAlignment, this.labelType, - this.useIndicator, - this.indicatorColor, }); /// Color to be used for the [NavigationRail]'s background. @@ -78,14 +76,6 @@ class NavigationRailThemeData with Diagnosticable { /// [NavigationRail]. final NavigationRailLabelType? labelType; - /// Whether or not the selected [NavigationRailDestination] should include a - /// [NavigationIndicator]. - final bool? useIndicator; - - /// Overrides the default value of [NavigationRail]'s selection indicator color, - /// when [useIndicator] is true. - final Color? indicatorColor; - /// Creates a copy of this object with the given fields replaced with the /// new values. NavigationRailThemeData copyWith({ @@ -97,8 +87,6 @@ class NavigationRailThemeData with Diagnosticable { IconThemeData? selectedIconTheme, double? groupAlignment, NavigationRailLabelType? labelType, - bool? useIndicator, - Color? indicatorColor, }) { return NavigationRailThemeData( backgroundColor: backgroundColor ?? this.backgroundColor, @@ -109,8 +97,6 @@ class NavigationRailThemeData with Diagnosticable { selectedIconTheme: selectedIconTheme ?? this.selectedIconTheme, groupAlignment: groupAlignment ?? this.groupAlignment, labelType: labelType ?? this.labelType, - useIndicator: useIndicator ?? this.useIndicator, - indicatorColor: indicatorColor ?? this.indicatorColor, ); } @@ -132,8 +118,6 @@ class NavigationRailThemeData with Diagnosticable { selectedIconTheme: IconThemeData.lerp(a?.selectedIconTheme, b?.selectedIconTheme, t), groupAlignment: lerpDouble(a?.groupAlignment, b?.groupAlignment, t), labelType: t < 0.5 ? a?.labelType : b?.labelType, - useIndicator: t < 0.5 ? a?.useIndicator : b?.useIndicator, - indicatorColor: Color.lerp(a?.indicatorColor, b?.indicatorColor, t), ); } @@ -148,8 +132,6 @@ class NavigationRailThemeData with Diagnosticable { selectedIconTheme, groupAlignment, labelType, - useIndicator, - indicatorColor, ); } @@ -167,9 +149,7 @@ class NavigationRailThemeData with Diagnosticable { && other.unselectedIconTheme == unselectedIconTheme && other.selectedIconTheme == selectedIconTheme && other.groupAlignment == groupAlignment - && other.labelType == labelType - && other.useIndicator == useIndicator - && other.indicatorColor == indicatorColor; + && other.labelType == labelType; } @override @@ -185,8 +165,6 @@ class NavigationRailThemeData with Diagnosticable { properties.add(DiagnosticsProperty('selectedIconTheme', selectedIconTheme, defaultValue: defaultData.selectedIconTheme)); properties.add(DoubleProperty('groupAlignment', groupAlignment, defaultValue: defaultData.groupAlignment)); properties.add(DiagnosticsProperty('labelType', labelType, defaultValue: defaultData.labelType)); - properties.add(DiagnosticsProperty('useIndicator', useIndicator, defaultValue: defaultData.useIndicator)); - properties.add(ColorProperty('indicatorColor', indicatorColor, defaultValue: defaultData.indicatorColor)); } } diff --git a/packages/flutter/lib/src/material/outlined_button.dart b/packages/flutter/lib/src/material/outlined_button.dart index 5badea5f939a4..8fe0db4c3a977 100644 --- a/packages/flutter/lib/src/material/outlined_button.dart +++ b/packages/flutter/lib/src/material/outlined_button.dart @@ -31,7 +31,7 @@ import 'theme_data.dart'; /// widgets are displayed in the [style]'s /// [ButtonStyle.foregroundColor] and the outline's weight and color /// are defined by [ButtonStyle.side]. The button reacts to touches -/// by filling with the [style]'s [ButtonStyle.overlayColor]. +/// by filling with the [style]'s [ButtonStyle.backgroundColor]. /// /// The outlined button's default style is defined by [defaultStyleOf]. /// The style of this outline button can be overridden with its [style] @@ -240,7 +240,7 @@ class OutlinedButton extends ButtonStyleButton { /// * `side` - BorderSide(width: 1, color: Theme.colorScheme.onSurface(0.12)) /// * `shape` - RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)) /// * `mouseCursor` - /// * disabled - SystemMouseCursors.basic + /// * disabled - SystemMouseCursors.forbidden /// * others - SystemMouseCursors.click /// * `visualDensity` - theme.visualDensity /// * `tapTargetSize` - theme.materialTapTargetSize @@ -275,7 +275,7 @@ class OutlinedButton extends ButtonStyleButton { ), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), enabledMouseCursor: SystemMouseCursors.click, - disabledMouseCursor: SystemMouseCursors.basic, + disabledMouseCursor: SystemMouseCursors.forbidden, visualDensity: theme.visualDensity, tapTargetSize: theme.materialTapTargetSize, animationDuration: kThemeChangeDuration, diff --git a/packages/flutter/lib/src/material/paginated_data_table.dart b/packages/flutter/lib/src/material/paginated_data_table.dart index ab33cedbcad16..c0b36e25f198d 100644 --- a/packages/flutter/lib/src/material/paginated_data_table.dart +++ b/packages/flutter/lib/src/material/paginated_data_table.dart @@ -466,11 +466,11 @@ class PaginatedDataTableState extends State { ]); // CARD - return Card( - semanticContainer: false, - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Column( + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return Card( + semanticContainer: false, + child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (headerWidgets.isNotEmpty) @@ -547,9 +547,9 @@ class PaginatedDataTableState extends State { ), ), ], - ); - }, - ), + ), + ); + }, ); } } diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 171c77ddc2aaf..ca6f64cfb83b4 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -264,20 +264,15 @@ class PopupMenuItem extends PopupMenuEntry { /// of [ThemeData.textTheme] is used. final TextStyle? textStyle; - /// {@template flutter.material.popupmenu.mouseCursor} /// The cursor for a mouse pointer when it enters or is hovering over the /// widget. /// /// If [mouseCursor] is a [MaterialStateProperty], - /// [MaterialStateProperty.resolve] is used for the following [MaterialState]s: + /// [MaterialStateProperty.resolve] is used for the following [MaterialState]: /// - /// * [MaterialState.hovered]. - /// * [MaterialState.focused]. /// * [MaterialState.disabled]. - /// {@endtemplate} /// - /// If null, then the value of [PopupMenuThemeData.mouseCursor] is used. If - /// that is also null, then [MaterialStateMouseCursor.clickable] is used. + /// If this property is null, [MaterialStateMouseCursor.clickable] will be used. final MouseCursor? mouseCursor; /// The widget below this widget in the tree. @@ -360,6 +355,12 @@ class PopupMenuItemState> extends State { child: item, ); } + final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs( + widget.mouseCursor ?? MaterialStateMouseCursor.clickable, + { + if (!widget.enabled) MaterialState.disabled, + }, + ); return MergeSemantics( child: Semantics( @@ -368,7 +369,7 @@ class PopupMenuItemState> extends State { child: InkWell( onTap: widget.enabled ? handleTap : null, canRequestFocus: widget.enabled, - mouseCursor: _EffectiveMouseCursor(widget.mouseCursor, popupMenuTheme.mouseCursor), + mouseCursor: effectiveMouseCursor, child: item, ), ), @@ -528,12 +529,10 @@ class _PopupMenu extends StatelessWidget { Key? key, required this.route, required this.semanticLabel, - this.padding, }) : super(key: key); final _PopupMenuRoute route; final String? semanticLabel; - final EdgeInsetsGeometry? padding; @override Widget build(BuildContext context) { @@ -585,7 +584,9 @@ class _PopupMenu extends StatelessWidget { explicitChildNodes: true, label: semanticLabel, child: SingleChildScrollView( - padding: padding, + padding: const EdgeInsets.symmetric( + vertical: _kMenuVerticalPadding, + ), child: ListBody(children: children), ), ), @@ -727,7 +728,6 @@ class _PopupMenuRoute extends PopupRoute { _PopupMenuRoute({ required this.position, required this.items, - this.padding, this.initialValue, this.elevation, required this.barrierLabel, @@ -741,7 +741,6 @@ class _PopupMenuRoute extends PopupRoute { final List> items; final List itemSizes; final T? initialValue; - final EdgeInsetsGeometry? padding; final double? elevation; final String? semanticLabel; final ShapeBorder? shape; @@ -780,7 +779,7 @@ class _PopupMenuRoute extends PopupRoute { } } - final Widget menu = _PopupMenu(padding: padding, route: this, semanticLabel: semanticLabel); + final Widget menu = _PopupMenu(route: this, semanticLabel: semanticLabel); final MediaQueryData mediaQuery = MediaQuery.of(context); return MediaQuery.removePadding( context: context, @@ -852,11 +851,6 @@ class _PopupMenuRoute extends PopupRoute { /// label is not provided, it will default to /// [MaterialLocalizations.popupMenuLabel]. /// -/// The `padding` argument is used to add empty space around the outside -/// of the popup menu. If this property is not provided, then [PopupMenuThemeData.padding] -/// is used. If [PopupMenuThemeData.padding] is also null, then -/// EdgeInsets.symmetric(vertical: 8.0) is used. -/// /// See also: /// /// * [PopupMenuItem], a popup menu entry for a single value. @@ -871,7 +865,6 @@ Future showMenu({ required RelativeRect position, required List> items, T? initialValue, - EdgeInsetsGeometry? padding, double? elevation, String? semanticLabel, ShapeBorder? shape, @@ -900,7 +893,6 @@ Future showMenu({ position: position, items: items, initialValue: initialValue, - padding: padding, elevation: elevation, semanticLabel: semanticLabel, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, @@ -993,7 +985,6 @@ class PopupMenuButton extends StatefulWidget { this.tooltip, this.elevation, this.padding = const EdgeInsets.all(8.0), - this.menuPadding, this.child, this.icon, this.iconSize, @@ -1088,14 +1079,6 @@ class PopupMenuButton extends StatefulWidget { /// Theme.of(context).cardColor is used. final Color? color; - /// If provided, menu padding is used for empty space around the outside - /// of the popup menu. - /// - /// If this property is null, then [PopupMenuThemeData.padding] is used. - /// If [PopupMenuThemeData.padding] is also null, then - /// EdgeInsets.symmetric(vertical: 8.0) is used. - final EdgeInsetsGeometry? menuPadding; - /// Whether detected gestures should provide acoustic and/or haptic feedback. /// /// For example, on Android a tap will produce a clicking sound and a @@ -1139,11 +1122,6 @@ class PopupMenuButtonState extends State> { ), Offset.zero & overlay.size, ); - - final EdgeInsetsGeometry menuPadding = widget.menuPadding ?? - popupMenuTheme.padding ?? - const EdgeInsets.symmetric(vertical: _kMenuVerticalPadding); - final List> items = widget.itemBuilder(context); // Only show the menu if there is something to show if (items.isNotEmpty) { @@ -1152,7 +1130,6 @@ class PopupMenuButtonState extends State> { elevation: widget.elevation ?? popupMenuTheme.elevation, items: items, initialValue: widget.initialValue, - padding: menuPadding, position: position, shape: widget.shape ?? popupMenuTheme.shape, color: widget.color ?? popupMenuTheme.color, @@ -1208,23 +1185,3 @@ class PopupMenuButtonState extends State> { ); } } - -// This MaterialStateProperty is passed along to the menu item's InkWell which -// resolves the property against MaterialState.disabled, MaterialState.hovered, -// MaterialState.focused. -class _EffectiveMouseCursor extends MaterialStateMouseCursor { - const _EffectiveMouseCursor(this.widgetCursor, this.themeCursor); - - final MouseCursor? widgetCursor; - final MaterialStateProperty? themeCursor; - - @override - MouseCursor resolve(Set states) { - return MaterialStateProperty.resolveAs(widgetCursor, states) - ?? themeCursor?.resolve(states) - ?? MaterialStateMouseCursor.clickable.resolve(states); - } - - @override - String get debugDescription => 'MaterialStateMouseCursor(PopupMenuItemState)'; -} diff --git a/packages/flutter/lib/src/material/popup_menu_theme.dart b/packages/flutter/lib/src/material/popup_menu_theme.dart index 93b85cfcede76..a05ddd85093a6 100644 --- a/packages/flutter/lib/src/material/popup_menu_theme.dart +++ b/packages/flutter/lib/src/material/popup_menu_theme.dart @@ -7,7 +7,6 @@ import 'dart:ui' show lerpDouble; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'material_state.dart'; import 'theme.dart'; /// Defines the visual properties of the routes used to display popup menus @@ -39,8 +38,6 @@ class PopupMenuThemeData with Diagnosticable { this.elevation, this.textStyle, this.enableFeedback, - this.mouseCursor, - this.padding, }); /// The background color of the popup menu. @@ -60,16 +57,6 @@ class PopupMenuThemeData with Diagnosticable { /// If [PopupMenuButton.enableFeedback] is provided, [enableFeedback] is ignored. final bool? enableFeedback; - /// {@macro flutter.material.popupmenu.mouseCursor} - /// - /// If specified, overrides the default value of [PopupMenuItem.mouseCursor]. - final MaterialStateProperty? mouseCursor; - - /// If specified, defines the padding for the popup menu of [PopupMenuButton]. - /// - /// If [PopupMenuButton.menuPadding] is provided, [padding] is ignored. - final EdgeInsetsGeometry? padding; - /// Creates a copy of this object with the given fields replaced with the /// new values. PopupMenuThemeData copyWith({ @@ -78,8 +65,6 @@ class PopupMenuThemeData with Diagnosticable { double? elevation, TextStyle? textStyle, bool? enableFeedback, - MaterialStateProperty? mouseCursor, - EdgeInsets? padding, }) { return PopupMenuThemeData( color: color ?? this.color, @@ -87,8 +72,6 @@ class PopupMenuThemeData with Diagnosticable { elevation: elevation ?? this.elevation, textStyle: textStyle ?? this.textStyle, enableFeedback: enableFeedback ?? this.enableFeedback, - mouseCursor: mouseCursor ?? this.mouseCursor, - padding: padding ?? this.padding, ); } @@ -107,8 +90,6 @@ class PopupMenuThemeData with Diagnosticable { elevation: lerpDouble(a?.elevation, b?.elevation, t), textStyle: TextStyle.lerp(a?.textStyle, b?.textStyle, t), enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback, - mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor, - padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t), ); } @@ -120,8 +101,6 @@ class PopupMenuThemeData with Diagnosticable { elevation, textStyle, enableFeedback, - mouseCursor, - padding, ); } @@ -136,9 +115,7 @@ class PopupMenuThemeData with Diagnosticable { && other.color == color && other.shape == shape && other.textStyle == textStyle - && other.enableFeedback == enableFeedback - && other.mouseCursor == mouseCursor - && other.padding == padding; + && other.enableFeedback == enableFeedback; } @override @@ -149,8 +126,6 @@ class PopupMenuThemeData with Diagnosticable { properties.add(DoubleProperty('elevation', elevation, defaultValue: null)); properties.add(DiagnosticsProperty('text style', textStyle, defaultValue: null)); properties.add(DiagnosticsProperty('enableFeedback', enableFeedback, defaultValue: null)); - properties.add(DiagnosticsProperty>('mouseCursor', mouseCursor, defaultValue: null)); - properties.add(DiagnosticsProperty('padding', padding, defaultValue: null)); } } diff --git a/packages/flutter/lib/src/material/progress_indicator.dart b/packages/flutter/lib/src/material/progress_indicator.dart index ccff5367f7707..9805a914c8042 100644 --- a/packages/flutter/lib/src/material/progress_indicator.dart +++ b/packages/flutter/lib/src/material/progress_indicator.dart @@ -32,8 +32,8 @@ abstract class ProgressIndicator extends StatefulWidget { /// /// {@template flutter.material.ProgressIndicator.ProgressIndicator} /// The [value] argument can either be null for an indeterminate - /// progress indicator, or a non-null value between 0.0 and 1.0 for a - /// determinate progress indicator. + /// progress indicator, or non-null for a determinate progress + /// indicator. /// /// ## Accessibility /// @@ -54,7 +54,6 @@ abstract class ProgressIndicator extends StatefulWidget { /// If non-null, the value of this progress indicator. /// /// A value of 0.0 means no progress and 1.0 means that progress is complete. - /// The value will be clamped to be in the range 0.0-1.0. /// /// If null, this progress indicator is indeterminate, which means the /// indicator displays a predetermined animation that does not indicate how @@ -594,8 +593,7 @@ class _CircularProgressIndicatorState extends State w } Widget _buildCupertinoIndicator(BuildContext context) { - final Color? tickColor = widget.backgroundColor; - return CupertinoActivityIndicator(key: widget.key, color: tickColor); + return CupertinoActivityIndicator(key: widget.key); } Widget _buildMaterialIndicator(BuildContext context, double headValue, double tailValue, double offsetValue, double rotationValue) { diff --git a/packages/flutter/lib/src/material/radio.dart b/packages/flutter/lib/src/material/radio.dart index 444a1bc5b9d8f..d320f0d8c5be4 100644 --- a/packages/flutter/lib/src/material/radio.dart +++ b/packages/flutter/lib/src/material/radio.dart @@ -189,26 +189,6 @@ class Radio extends StatefulWidget { /// * [MaterialState.hovered]. /// * [MaterialState.focused]. /// * [MaterialState.disabled]. - /// - /// {@tool snippet} - /// This example resolves the [fillColor] based on the current [MaterialState] - /// of the [Radio], providing a different [Color] when it is - /// [MaterialState.disabled]. - /// - /// ```dart - /// Radio( - /// value: 1, - /// groupValue: 1, - /// onChanged: (_){}, - /// fillColor: MaterialStateProperty.resolveWith((states) { - /// if (states.contains(MaterialState.disabled)) { - /// return Colors.orange.withOpacity(.32); - /// } - /// return Colors.orange; - /// }) - /// ) - /// ``` - /// {@end-tool} /// {@endtemplate} /// /// If null, then the value of [activeColor] is used in the selected state. If diff --git a/packages/flutter/lib/src/material/refresh_indicator.dart b/packages/flutter/lib/src/material/refresh_indicator.dart index f76e6fe5e0e45..70e07955993d6 100644 --- a/packages/flutter/lib/src/material/refresh_indicator.dart +++ b/packages/flutter/lib/src/material/refresh_indicator.dart @@ -60,8 +60,6 @@ enum RefreshIndicatorTriggerMode { /// A widget that supports the Material "swipe to refresh" idiom. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=ORApMlzwMdM} -/// /// When the child's [Scrollable] descendant overscrolls, an animated circular /// progress indicator is faded into view. When the scroll ends, if the /// indicator has been dragged far enough for it to become completely opaque, diff --git a/packages/flutter/lib/src/material/reorderable_list.dart b/packages/flutter/lib/src/material/reorderable_list.dart index af056bbb8209b..9b05827521295 100644 --- a/packages/flutter/lib/src/material/reorderable_list.dart +++ b/packages/flutter/lib/src/material/reorderable_list.dart @@ -31,19 +31,9 @@ import 'theme.dart'; /// /// {@tool dartpad} /// -/// ** See code in examples/api/lib/material/reorderable_list/reorderable_list_view.0.dart ** -/// {@end-tool} -/// -/// This example demonstrates using the [proxyDecorator] callback to customize the appearance of -/// a list item while it's being dragged. -/// {@tool snippet} /// -/// While a drag is underway, the widget returned by the [proxyDecorator] serves as a "proxy" (a substitute) -/// for the item in the list. The proxy is created with the original list item as its child. The [proxyDecorator] -/// in this example is similar to the default one except that it changes the proxy item's background color. -/// -/// ** See code in examples/api/lib/material/reorderable_list/reorderable_list_view.1.dart ** -/// {@end-tool} +/// ** See code in examples/api/lib/material/reorderable_list/reorderable_list_view.0.dart ** +///{@end-tool} class ReorderableListView extends StatefulWidget { /// Creates a reorderable list from a pre-built list of widgets. /// diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index 4ad7ef7e4a916..a9cb134de20dc 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -2318,7 +2318,6 @@ class ScaffoldState extends State with TickerProviderStateMixin, Resto ShapeBorder? shape, Clip? clipBehavior, BoxConstraints? constraints, - bool? enableDrag, bool shouldDisposeAnimationController = true, }) { assert(() { @@ -2360,7 +2359,7 @@ class ScaffoldState extends State with TickerProviderStateMixin, Resto final LocalHistoryEntry? entry = isPersistent ? null : LocalHistoryEntry(onRemove: () { - if (!removedEntry && _currentBottomSheet?._widget == bottomSheet) { + if (!removedEntry) { _removeCurrentBottomSheet(); } }); @@ -2368,7 +2367,7 @@ class ScaffoldState extends State with TickerProviderStateMixin, Resto bottomSheet = _StandardBottomSheet( key: bottomSheetKey, animationController: animationController, - enableDrag: enableDrag ?? !isPersistent, + enableDrag: !isPersistent, onClosing: () { if (_currentBottomSheet == null) { return; @@ -2469,7 +2468,6 @@ class ScaffoldState extends State with TickerProviderStateMixin, Resto ShapeBorder? shape, Clip? clipBehavior, BoxConstraints? constraints, - bool? enableDrag, AnimationController? transitionAnimationController, }) { assert(() { @@ -2496,7 +2494,6 @@ class ScaffoldState extends State with TickerProviderStateMixin, Resto shape: shape, clipBehavior: clipBehavior, constraints: constraints, - enableDrag: enableDrag, shouldDisposeAnimationController: transitionAnimationController == null, ); }); diff --git a/packages/flutter/lib/src/material/scrollbar.dart b/packages/flutter/lib/src/material/scrollbar.dart index 98aac54e88d30..959ef700932b4 100644 --- a/packages/flutter/lib/src/material/scrollbar.dart +++ b/packages/flutter/lib/src/material/scrollbar.dart @@ -23,8 +23,6 @@ const Duration _kScrollbarTimeToFade = Duration(milliseconds: 600); /// To add a scrollbar to a [ScrollView], wrap the scroll view /// widget in a [Scrollbar] widget. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=DbkIQSvwnZc} -/// /// {@macro flutter.widgets.Scrollbar} /// /// Dynamically changes to an iOS style scrollbar that looks like @@ -79,7 +77,6 @@ class Scrollbar extends StatelessWidget { required this.child, this.controller, this.isAlwaysShown, - this.trackVisibility, this.showTrackOnHover, this.hoverThickness, this.thickness, @@ -98,26 +95,11 @@ class Scrollbar extends StatelessWidget { /// {@macro flutter.widgets.Scrollbar.isAlwaysShown} final bool? isAlwaysShown; - /// Controls the track visibility. - /// - /// If this property is null, then [ScrollbarThemeData.trackVisibility] of - /// [ThemeData.scrollbarTheme] is used. If that is also null, the default value - /// is false. - /// - /// If the track visibility is related to the scrollbar's material state, - /// use the global [ScrollbarThemeData.trackVisibility] or override the - /// sub-tree's theme data. - /// - /// [showTrackOnHover] can be replaced by this and will be deprecated. - final bool? trackVisibility; - /// Controls if the track will show on hover and remain, including during drag. /// /// If this property is null, then [ScrollbarThemeData.showTrackOnHover] of /// [ThemeData.scrollbarTheme] is used. If that is also null, the default value /// is false. - /// - /// This will be deprecated, and [trackVisibility] is recommended. final bool? showTrackOnHover; /// The thickness of the scrollbar when a hover state is active and @@ -171,7 +153,6 @@ class Scrollbar extends StatelessWidget { return _MaterialScrollbar( controller: controller, isAlwaysShown: isAlwaysShown, - trackVisibility: trackVisibility, showTrackOnHover: showTrackOnHover, hoverThickness: hoverThickness, thickness: thickness, @@ -190,7 +171,6 @@ class _MaterialScrollbar extends RawScrollbar { required Widget child, ScrollController? controller, bool? isAlwaysShown, - this.trackVisibility, this.showTrackOnHover, this.hoverThickness, double? thickness, @@ -213,7 +193,6 @@ class _MaterialScrollbar extends RawScrollbar { scrollbarOrientation: scrollbarOrientation, ); - final bool? trackVisibility; final bool? showTrackOnHover; final double? hoverThickness; @@ -238,13 +217,6 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { bool get _showTrackOnHover => widget.showTrackOnHover ?? _scrollbarTheme.showTrackOnHover ?? false; - MaterialStateProperty get _trackVisibility => MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.hovered) && _showTrackOnHover) { - return true; - } - return widget.trackVisibility ?? _scrollbarTheme.trackVisibility?.resolve(states) ?? false; - }); - Set get _states => { if (_dragIsActive) MaterialState.dragged, if (_hoverIsActive) MaterialState.hovered, @@ -279,7 +251,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { // If the track is visible, the thumb color hover animation is ignored and // changes immediately. - if (_trackVisibility.resolve(states)) + if (states.contains(MaterialState.hovered) && _showTrackOnHover) return _scrollbarTheme.thumbColor?.resolve(states) ?? hoverColor; return Color.lerp( @@ -294,7 +266,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { final Color onSurface = _colorScheme.onSurface; final Brightness brightness = _colorScheme.brightness; return MaterialStateProperty.resolveWith((Set states) { - if (_trackVisibility.resolve(states)) { + if (states.contains(MaterialState.hovered) && _showTrackOnHover) { return _scrollbarTheme.trackColor?.resolve(states) ?? (brightness == Brightness.light ? onSurface.withOpacity(0.03) @@ -308,7 +280,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { final Color onSurface = _colorScheme.onSurface; final Brightness brightness = _colorScheme.brightness; return MaterialStateProperty.resolveWith((Set states) { - if (_trackVisibility.resolve(states)) { + if (states.contains(MaterialState.hovered) && _showTrackOnHover) { return _scrollbarTheme.trackBorderColor?.resolve(states) ?? (brightness == Brightness.light ? onSurface.withOpacity(0.1) @@ -320,7 +292,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { MaterialStateProperty get _thickness { return MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.hovered) && _trackVisibility.resolve(states)) + if (states.contains(MaterialState.hovered) && _showTrackOnHover) return widget.hoverThickness ?? _scrollbarTheme.thickness?.resolve(states) ?? _kScrollbarThicknessWithTrack; @@ -376,8 +348,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { ..mainAxisMargin = _scrollbarTheme.mainAxisMargin ?? 0.0 ..minLength = _scrollbarTheme.minThumbLength ?? _kScrollbarMinLength ..padding = MediaQuery.of(context).padding - ..scrollbarOrientation = widget.scrollbarOrientation - ..ignorePointer = !enableGestures; + ..scrollbarOrientation = widget.scrollbarOrientation; } @override diff --git a/packages/flutter/lib/src/material/scrollbar_theme.dart b/packages/flutter/lib/src/material/scrollbar_theme.dart index b16b3bf074d9e..02c9414d37acf 100644 --- a/packages/flutter/lib/src/material/scrollbar_theme.dart +++ b/packages/flutter/lib/src/material/scrollbar_theme.dart @@ -32,7 +32,6 @@ class ScrollbarThemeData with Diagnosticable { /// Creates a theme that can be used for [ThemeData.scrollbarTheme]. const ScrollbarThemeData({ this.thickness, - this.trackVisibility, this.showTrackOnHover, this.isAlwaysShown, this.radius, @@ -52,10 +51,6 @@ class ScrollbarThemeData with Diagnosticable { /// * [MaterialState.hovered] on web and desktop platforms. final MaterialStateProperty? thickness; - /// Overrides the default value of [Scrollbar.trackVisibility] in all - /// descendant [Scrollbar] widgets. - final MaterialStateProperty? trackVisibility; - /// Overrides the default value of [Scrollbar.showTrackOnHover] in all /// descendant [Scrollbar] widgets. final bool? showTrackOnHover; @@ -127,7 +122,6 @@ class ScrollbarThemeData with Diagnosticable { /// new values. ScrollbarThemeData copyWith({ MaterialStateProperty? thickness, - MaterialStateProperty? trackVisibility, bool? showTrackOnHover, bool? isAlwaysShown, bool? interactive, @@ -141,7 +135,6 @@ class ScrollbarThemeData with Diagnosticable { }) { return ScrollbarThemeData( thickness: thickness ?? this.thickness, - trackVisibility: trackVisibility ?? this.trackVisibility, showTrackOnHover: showTrackOnHover ?? this.showTrackOnHover, isAlwaysShown: isAlwaysShown ?? this.isAlwaysShown, interactive: interactive ?? this.interactive, @@ -164,10 +157,9 @@ class ScrollbarThemeData with Diagnosticable { assert(t != null); return ScrollbarThemeData( thickness: _lerpProperties(a?.thickness, b?.thickness, t, lerpDouble), - trackVisibility: _lerpProperties(a?.trackVisibility, b?.trackVisibility, t, _lerpBool), - showTrackOnHover: _lerpBool(a?.showTrackOnHover, b?.showTrackOnHover, t), - isAlwaysShown: _lerpBool(a?.isAlwaysShown, b?.isAlwaysShown, t), - interactive: _lerpBool(a?.interactive, b?.interactive, t), + showTrackOnHover: t < 0.5 ? a?.showTrackOnHover : b?.showTrackOnHover, + isAlwaysShown: t < 0.5 ? a?.isAlwaysShown : b?.isAlwaysShown, + interactive: t < 0.5 ? a?.interactive : b?.interactive, radius: Radius.lerp(a?.radius, b?.radius, t), thumbColor: _lerpProperties(a?.thumbColor, b?.thumbColor, t, Color.lerp), trackColor: _lerpProperties(a?.trackColor, b?.trackColor, t, Color.lerp), @@ -182,7 +174,6 @@ class ScrollbarThemeData with Diagnosticable { int get hashCode { return hashValues( thickness, - trackVisibility, showTrackOnHover, isAlwaysShown, interactive, @@ -204,7 +195,6 @@ class ScrollbarThemeData with Diagnosticable { return false; return other is ScrollbarThemeData && other.thickness == thickness - && other.trackVisibility == trackVisibility && other.showTrackOnHover == showTrackOnHover && other.isAlwaysShown == isAlwaysShown && other.interactive == interactive @@ -221,7 +211,6 @@ class ScrollbarThemeData with Diagnosticable { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty>('thickness', thickness, defaultValue: null)); - properties.add(DiagnosticsProperty>('trackVisibility', trackVisibility, defaultValue: null)); properties.add(DiagnosticsProperty('showTrackOnHover', showTrackOnHover, defaultValue: null)); properties.add(DiagnosticsProperty('isAlwaysShown', isAlwaysShown, defaultValue: null)); properties.add(DiagnosticsProperty('interactive', interactive, defaultValue: null)); @@ -263,8 +252,6 @@ class _LerpProperties implements MaterialStateProperty { } } -bool? _lerpBool(bool? a, bool? b, double t) => t < 0.5 ? a : b; - /// Applies a scrollbar theme to descendant [Scrollbar] widgets. /// /// Descendant widgets obtain the current theme's [ScrollbarThemeData] using diff --git a/packages/flutter/lib/src/material/selectable_text.dart b/packages/flutter/lib/src/material/selectable_text.dart index bf09e043ceaf8..6178ed5556811 100644 --- a/packages/flutter/lib/src/material/selectable_text.dart +++ b/packages/flutter/lib/src/material/selectable_text.dart @@ -123,8 +123,6 @@ class _SelectableTextSelectionGestureDetectorBuilder extends TextSelectionGestur /// behavior is useful, for example, to make the text bold while using the /// default font family and size. /// -/// {@macro flutter.material.textfield.wantKeepAlive} -/// /// {@tool snippet} /// /// ```dart @@ -416,7 +414,7 @@ class SelectableText extends StatefulWidget { /// {@macro flutter.widgets.Text.semanticsLabel} final String? semanticsLabel; - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} final TextHeightBehavior? textHeightBehavior; /// {@macro flutter.painting.textPainter.textWidthBasis} @@ -453,7 +451,7 @@ class SelectableText extends StatefulWidget { } } -class _SelectableTextState extends State implements TextSelectionGestureDetectorBuilderDelegate { +class _SelectableTextState extends State with AutomaticKeepAliveClientMixin implements TextSelectionGestureDetectorBuilderDelegate { EditableTextState? get _editableText => editableTextKey.currentState; late _TextSpanEditingController _controller; @@ -581,8 +579,12 @@ class _SelectableTextState extends State implements TextSelectio return false; } + @override + bool get wantKeepAlive => true; + @override Widget build(BuildContext context) { + super.build(context); // See AutomaticKeepAliveClientMixin. // TODO(garyq): Assert to block WidgetSpans from being used here are removed, // but we still do not yet have nice handling of things like carets, clipboard, // and other features. We should add proper support. Currently, caret handling diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index 6b21f6d931c28..515cc49d3c6e5 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -152,7 +152,7 @@ class Slider extends StatefulWidget { /// Material design's /// [Cross-platform guidelines](https://material.io/design/platform-guidance/cross-platform-adaptation.html). /// - /// Creates a [CupertinoSlider] if the target platform is iOS or macOS, creates a + /// Creates a [CupertinoSlider] if the target platform is iOS, creates a /// Material Design slider otherwise. /// /// If a [CupertinoSlider] is created, the following parameters are @@ -373,26 +373,17 @@ class Slider extends StatefulWidget { /// (like the native default iOS slider). final Color? thumbColor; - /// {@template flutter.material.slider.mouseCursor} /// The cursor for a mouse pointer when it enters or is hovering over the /// widget. /// /// If [mouseCursor] is a [MaterialStateProperty], /// [MaterialStateProperty.resolve] is used for the following [MaterialState]s: /// - /// * [MaterialState.dragged]. /// * [MaterialState.hovered]. /// * [MaterialState.focused]. /// * [MaterialState.disabled]. - /// {@endtemplate} /// - /// If null, then the value of [SliderThemeData.mouseCursor] is used. If that - /// is also null, then [MaterialStateMouseCursor.clickable] is used. - /// - /// See also: - /// - /// * [MaterialStateMouseCursor], which can be used to create a [MouseCursor] - /// that is also a [MaterialStateProperty]. + /// If this property is null, [MaterialStateMouseCursor.clickable] will be used. final MouseCursor? mouseCursor; /// The callback used to create a semantic value from a slider value. @@ -490,11 +481,6 @@ class _SliderState extends State with TickerProviderStateMixin { // Value Indicator Animation that appears on the Overlay. PaintValueIndicator? paintValueIndicator; - bool _dragging = false; - - FocusNode? _focusNode; - FocusNode get focusNode => widget.focusNode ?? _focusNode!; - @override void initState() { super.initState(); @@ -521,10 +507,6 @@ class _SliderState extends State with TickerProviderStateMixin { onInvoke: _actionHandler, ), }; - if (widget.focusNode == null) { - // Only create a new node if the widget doesn't have one. - _focusNode ??= FocusNode(); - } } @override @@ -538,7 +520,6 @@ class _SliderState extends State with TickerProviderStateMixin { overlayEntry!.remove(); overlayEntry = null; } - _focusNode?.dispose(); super.dispose(); } @@ -551,13 +532,13 @@ class _SliderState extends State with TickerProviderStateMixin { } void _handleDragStart(double value) { - _dragging = true; - widget.onChangeStart?.call(_lerp(value)); + assert(widget.onChangeStart != null); + widget.onChangeStart!(_lerp(value)); } void _handleDragEnd(double value) { - _dragging = false; - widget.onChangeEnd?.call(_lerp(value)); + assert(widget.onChangeEnd != null); + widget.onChangeEnd!(_lerp(value)); } void _actionHandler(_AdjustSliderIntent intent) { @@ -703,47 +684,27 @@ class _SliderState extends State with TickerProviderStateMixin { color: theme.colorScheme.onPrimary, ), ); - final Set states = { - if (!_enabled) MaterialState.disabled, - if (_hovering) MaterialState.hovered, - if (_focused) MaterialState.focused, - if (_dragging) MaterialState.dragged, - }; - final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs(widget.mouseCursor, states) - ?? sliderTheme.mouseCursor?.resolve(states) - ?? MaterialStateMouseCursor.clickable.resolve(states); + final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs( + widget.mouseCursor ?? MaterialStateMouseCursor.clickable, + { + if (!_enabled) MaterialState.disabled, + if (_hovering) MaterialState.hovered, + if (_focused) MaterialState.focused, + }, + ); // This size is used as the max bounds for the painting of the value // indicators It must be kept in sync with the function with the same name // in range_slider.dart. Size _screenSize() => MediaQuery.of(context).size; - VoidCallback? handleDidGainAccessibilityFocus; - switch (theme.platform) { - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.iOS: - case TargetPlatform.linux: - case TargetPlatform.macOS: - break; - case TargetPlatform.windows: - handleDidGainAccessibilityFocus = () { - // Automatically activate the slider when it receives a11y focus. - if (!focusNode.hasFocus && focusNode.canRequestFocus) { - focusNode.requestFocus(); - } - }; - break; - } - return Semantics( container: true, slider: true, - onDidGainAccessibilityFocus: handleDidGainAccessibilityFocus, child: FocusableActionDetector( actions: _actionMap, shortcuts: _shortcutMap, - focusNode: focusNode, + focusNode: widget.focusNode, autofocus: widget.autofocus, enabled: _enabled, onShowFocusHighlight: _handleFocusHighlightChanged, @@ -760,8 +721,8 @@ class _SliderState extends State with TickerProviderStateMixin { textScaleFactor: MediaQuery.of(context).textScaleFactor, screenSize: _screenSize(), onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null, - onChangeStart: _handleDragStart, - onChangeEnd: _handleDragEnd, + onChangeStart: widget.onChangeStart != null ? _handleDragStart : null, + onChangeEnd: widget.onChangeEnd != null ? _handleDragEnd : null, state: this, semanticFormatterCallback: widget.semanticFormatterCallback, hasFocus: _focused, diff --git a/packages/flutter/lib/src/material/slider_theme.dart b/packages/flutter/lib/src/material/slider_theme.dart index 9b42d095327de..0f5adca59ad73 100644 --- a/packages/flutter/lib/src/material/slider_theme.dart +++ b/packages/flutter/lib/src/material/slider_theme.dart @@ -10,7 +10,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'colors.dart'; -import 'material_state.dart'; import 'theme.dart'; /// Applies a slider theme to descendant [Slider] widgets. @@ -31,21 +30,35 @@ import 'theme.dart'; /// /// * [SliderThemeData], which describes the actual configuration of a slider /// theme. +/// {@template flutter.material.SliderTheme.sliderComponentShape} /// * [SliderComponentShape], which can be used to create custom shapes for /// the [Slider]'s thumb, overlay, and value indicator and the /// [RangeSlider]'s overlay. +/// {@endtemplate} +/// {@template flutter.material.SliderTheme.sliderTrackShape} /// * [SliderTrackShape], which can be used to create custom shapes for the /// [Slider]'s track. +/// {@endtemplate} +/// {@template flutter.material.SliderTheme.sliderTickMarkShape} /// * [SliderTickMarkShape], which can be used to create custom shapes for the /// [Slider]'s tick marks. +/// {@endtemplate} +/// {@template flutter.material.SliderTheme.rangeSliderThumbShape} /// * [RangeSliderThumbShape], which can be used to create custom shapes for /// the [RangeSlider]'s thumb. +/// {@endtemplate} +/// {@template flutter.material.SliderTheme.rangeSliderValueIndicatorShape} /// * [RangeSliderValueIndicatorShape], which can be used to create custom /// shapes for the [RangeSlider]'s value indicator. +/// {@endtemplate} +/// {@template flutter.material.SliderTheme.rangeSliderTrackShape} /// * [RangeSliderTrackShape], which can be used to create custom shapes for /// the [RangeSlider]'s track. +/// {@endtemplate} +/// {@template flutter.material.SliderTheme.rangeSliderTickMarkShape} /// * [RangeSliderTickMarkShape], which can be used to create custom shapes for /// the [RangeSlider]'s tick marks. +/// {@endtemplate} class SliderTheme extends InheritedTheme { /// Applies the given theme [data] to [child]. /// @@ -211,21 +224,13 @@ enum Thumb { /// * [Theme] widget, which performs a similar function to [SliderTheme], /// but for overall themes. /// * [ThemeData], which has a default [SliderThemeData]. -/// * [SliderComponentShape], which can be used to create custom shapes for -/// the [Slider]'s thumb, overlay, and value indicator and the -/// [RangeSlider]'s overlay. -/// * [SliderTrackShape], which can be used to create custom shapes for the -/// [Slider]'s track. -/// * [SliderTickMarkShape], which can be used to create custom shapes for the -/// [Slider]'s tick marks. -/// * [RangeSliderThumbShape], which can be used to create custom shapes for -/// the [RangeSlider]'s thumb. -/// * [RangeSliderValueIndicatorShape], which can be used to create custom -/// shapes for the [RangeSlider]'s value indicator. -/// * [RangeSliderTrackShape], which can be used to create custom shapes for -/// the [RangeSlider]'s track. -/// * [RangeSliderTickMarkShape], which can be used to create custom shapes for -/// the [RangeSlider]'s tick marks. +/// {@macro flutter.material.SliderTheme.sliderComponentShape} +/// {@macro flutter.material.SliderTheme.sliderTrackShape} +/// {@macro flutter.material.SliderTheme.sliderTickMarkShape} +/// {@macro flutter.material.SliderTheme.rangeSliderThumbShape} +/// {@macro flutter.material.SliderTheme.rangeSliderValueIndicatorShape} +/// {@macro flutter.material.SliderTheme.rangeSliderTrackShape} +/// {@macro flutter.material.SliderTheme.rangeSliderTickMarkShape} @immutable class SliderThemeData with Diagnosticable { /// Create a [SliderThemeData] given a set of exact values. @@ -291,7 +296,6 @@ class SliderThemeData with Diagnosticable { this.valueIndicatorTextStyle, this.minThumbSeparation, this.thumbSelector, - this.mouseCursor, }); /// Generates a SliderThemeData from three main colors. @@ -563,11 +567,6 @@ class SliderThemeData with Diagnosticable { /// Override this for custom thumb selection. final RangeThumbSelector? thumbSelector; - /// {@macro flutter.material.slider.mouseCursor} - /// - /// If specified, overrides the default value of [Slider.mouseCursor]. - final MaterialStateProperty? mouseCursor; - /// Creates a copy of this object but with the given fields replaced with the /// new values. SliderThemeData copyWith({ @@ -598,7 +597,6 @@ class SliderThemeData with Diagnosticable { TextStyle? valueIndicatorTextStyle, double? minThumbSeparation, RangeThumbSelector? thumbSelector, - MaterialStateProperty? mouseCursor, }) { return SliderThemeData( trackHeight: trackHeight ?? this.trackHeight, @@ -628,7 +626,6 @@ class SliderThemeData with Diagnosticable { valueIndicatorTextStyle: valueIndicatorTextStyle ?? this.valueIndicatorTextStyle, minThumbSeparation: minThumbSeparation ?? this.minThumbSeparation, thumbSelector: thumbSelector ?? this.thumbSelector, - mouseCursor: mouseCursor ?? this.mouseCursor, ); } @@ -669,7 +666,6 @@ class SliderThemeData with Diagnosticable { valueIndicatorTextStyle: TextStyle.lerp(a.valueIndicatorTextStyle, b.valueIndicatorTextStyle, t), minThumbSeparation: lerpDouble(a.minThumbSeparation, b.minThumbSeparation, t), thumbSelector: t < 0.5 ? a.thumbSelector : b.thumbSelector, - mouseCursor: t < 0.5 ? a.mouseCursor : b.mouseCursor, ); } @@ -703,7 +699,6 @@ class SliderThemeData with Diagnosticable { valueIndicatorTextStyle, minThumbSeparation, thumbSelector, - mouseCursor, ]); } @@ -742,8 +737,7 @@ class SliderThemeData with Diagnosticable { && other.showValueIndicator == showValueIndicator && other.valueIndicatorTextStyle == valueIndicatorTextStyle && other.minThumbSeparation == minThumbSeparation - && other.thumbSelector == thumbSelector - && other.mouseCursor == mouseCursor; + && other.thumbSelector == thumbSelector; } @override @@ -777,7 +771,6 @@ class SliderThemeData with Diagnosticable { properties.add(DiagnosticsProperty('valueIndicatorTextStyle', valueIndicatorTextStyle, defaultValue: defaultData.valueIndicatorTextStyle)); properties.add(DoubleProperty('minThumbSeparation', minThumbSeparation, defaultValue: defaultData.minThumbSeparation)); properties.add(DiagnosticsProperty('thumbSelector', thumbSelector, defaultValue: defaultData.thumbSelector)); - properties.add(DiagnosticsProperty>('mouseCursor', mouseCursor, defaultValue: defaultData.mouseCursor)); } } @@ -917,11 +910,8 @@ abstract class SliderComponentShape { /// /// * [RoundSliderTickMarkShape], which is the default [Slider]'s tick mark /// shape that paints a solid circle. -/// * [SliderTrackShape], which can be used to create custom shapes for the -/// [Slider]'s track. -/// * [SliderComponentShape], which can be used to create custom shapes for -/// the [Slider]'s thumb, overlay, and value indicator and the -/// [RangeSlider]'s overlay. +/// {@macro flutter.material.SliderTheme.sliderTrackShape} +/// {@macro flutter.material.SliderTheme.sliderComponentShape} abstract class SliderTickMarkShape { /// This abstract const constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -996,11 +986,8 @@ abstract class SliderTickMarkShape { /// /// * [RoundedRectSliderTrackShape] for the default [Slider]'s track shape that /// paints a stadium-like track. -/// * [SliderTickMarkShape], which can be used to create custom shapes for the -/// [Slider]'s tick marks. -/// * [SliderComponentShape], which can be used to create custom shapes for -/// the [Slider]'s thumb, overlay, and value indicator and the -/// [RangeSlider]'s overlay. +/// {@macro flutter.material.SliderTheme.sliderTickMarkShape} +/// {@macro flutter.material.SliderTheme.sliderComponentShape} abstract class SliderTrackShape { /// This abstract const constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -1081,15 +1068,10 @@ abstract class SliderTrackShape { /// /// * [RoundRangeSliderThumbShape] for the default [RangeSlider]'s thumb shape /// that paints a solid circle. -/// * [RangeSliderTickMarkShape], which can be used to create custom shapes for -/// the [RangeSlider]'s tick marks. -/// * [RangeSliderTrackShape], which can be used to create custom shapes for -/// the [RangeSlider]'s track. -/// * [RangeSliderValueIndicatorShape], which can be used to create custom -/// shapes for the [RangeSlider]'s value indicator. -/// * [SliderComponentShape], which can be used to create custom shapes for -/// the [Slider]'s thumb, overlay, and value indicator and the -/// [RangeSlider]'s overlay. +/// {@macro flutter.material.SliderTheme.rangeSliderTickMarkShape} +/// {@macro flutter.material.SliderTheme.rangeSliderTrackShape} +/// {@macro flutter.material.SliderTheme.rangeSliderValueIndicatorShape} +/// {@macro flutter.material.SliderTheme.sliderComponentShape} abstract class RangeSliderThumbShape { /// This abstract const constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -1176,15 +1158,10 @@ abstract class RangeSliderThumbShape { /// /// * [PaddleRangeSliderValueIndicatorShape] for the default [RangeSlider]'s /// value indicator shape that paints a custom path with text in it. -/// * [RangeSliderTickMarkShape], which can be used to create custom shapes for -/// the [RangeSlider]'s tick marks. -/// * [RangeSliderThumbShape], which can be used to create custom shapes for -/// the [RangeSlider]'s thumb. -/// * [RangeSliderTrackShape], which can be used to create custom shapes for -/// the [RangeSlider]'s track. -/// * [SliderComponentShape], which can be used to create custom shapes for -/// the [Slider]'s thumb, overlay, and value indicator and the -/// [RangeSlider]'s overlay. +/// {@macro flutter.material.SliderTheme.rangeSliderTickMarkShape} +/// {@macro flutter.material.SliderTheme.rangeSliderThumbShape} +/// {@macro flutter.material.SliderTheme.rangeSliderTrackShape} +/// {@macro flutter.material.SliderTheme.sliderComponentShape} abstract class RangeSliderValueIndicatorShape { /// This abstract const constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -1286,15 +1263,10 @@ abstract class RangeSliderValueIndicatorShape { /// /// * [RoundRangeSliderTickMarkShape] for the default [RangeSlider]'s tick mark /// shape that paints a solid circle. -/// * [RangeSliderThumbShape], which can be used to create custom shapes for -/// the [RangeSlider]'s thumb. -/// * [RangeSliderTrackShape], which can be used to create custom shapes for -/// the [RangeSlider]'s track. -/// * [RangeSliderValueIndicatorShape], which can be used to create custom -/// shapes for the [RangeSlider]'s value indicator. -/// * [SliderComponentShape], which can be used to create custom shapes for -/// the [Slider]'s thumb, overlay, and value indicator and the -/// [RangeSlider]'s overlay. +/// {@macro flutter.material.SliderTheme.rangeSliderThumbShape} +/// {@macro flutter.material.SliderTheme.rangeSliderTrackShape} +/// {@macro flutter.material.SliderTheme.rangeSliderValueIndicatorShape} +/// {@macro flutter.material.SliderTheme.sliderComponentShape} abstract class RangeSliderTickMarkShape { /// This abstract const constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -1361,15 +1333,10 @@ abstract class RangeSliderTickMarkShape { /// /// * [RoundedRectRangeSliderTrackShape] for the default [RangeSlider]'s track /// shape that paints a stadium-like track. -/// * [RangeSliderTickMarkShape], which can be used to create custom shapes for -/// the [RangeSlider]'s tick marks. -/// * [RangeSliderThumbShape], which can be used to create custom shapes for -/// the [RangeSlider]'s thumb. -/// * [RangeSliderValueIndicatorShape], which can be used to create custom -/// shapes for the [RangeSlider]'s value indicator. -/// * [SliderComponentShape], which can be used to create custom shapes for -/// the [Slider]'s thumb, overlay, and value indicator and the -/// [RangeSlider]'s overlay. +/// {@macro flutter.material.SliderTheme.rangeSliderTickMarkShape} +/// {@macro flutter.material.SliderTheme.rangeSliderThumbShape} +/// {@macro flutter.material.SliderTheme.rangeSliderValueIndicatorShape} +/// {@macro flutter.material.SliderTheme.sliderComponentShape} abstract class RangeSliderTrackShape { /// This abstract const constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -1519,8 +1486,7 @@ mixin BaseSliderTrackShape { /// * [Slider], for the component that is meant to display this shape. /// * [SliderThemeData], where an instance of this class is set to inform the /// slider of the visual details of the its track. -/// * [SliderTrackShape], which can be used to create custom shapes for the -/// [Slider]'s track. +/// {@macro flutter.material.SliderTheme.sliderTrackShape} /// * [RoundedRectSliderTrackShape], for a similar track with rounded edges. class RectangularSliderTrackShape extends SliderTrackShape with BaseSliderTrackShape { /// Creates a slider track that draws 2 rectangles. @@ -1636,8 +1602,7 @@ class RectangularSliderTrackShape extends SliderTrackShape with BaseSliderTrackS /// * [Slider], for the component that is meant to display this shape. /// * [SliderThemeData], where an instance of this class is set to inform the /// slider of the visual details of the its track. -/// * [SliderTrackShape], which can be used to create custom shapes for the -/// [Slider]'s track. +/// {@macro flutter.material.SliderTheme.sliderTrackShape} /// * [RectangularSliderTrackShape], for a similar track with sharp edges. class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackShape { /// Create a slider track that draws two rectangles with rounded outer edges. @@ -1752,8 +1717,7 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS /// * [RangeSlider], for the component that is meant to display this shape. /// * [SliderThemeData], where an instance of this class is set to inform the /// slider of the visual details of the its track. -/// * [RangeSliderTrackShape], which can be used to create custom shapes for -/// the [RangeSlider]'s track. +/// {@macro flutter.material.SliderTheme.rangeSliderTrackShape} /// * [RoundedRectRangeSliderTrackShape], for a similar track with rounded /// edges. class RectangularRangeSliderTrackShape extends RangeSliderTrackShape { @@ -1881,8 +1845,7 @@ class RectangularRangeSliderTrackShape extends RangeSliderTrackShape { /// * [RangeSlider], for the component that is meant to display this shape. /// * [SliderThemeData], where an instance of this class is set to inform the /// slider of the visual details of the its track. -/// * [RangeSliderTrackShape], which can be used to create custom shapes for -/// the [RangeSlider]'s track. +/// {@macro flutter.material.SliderTheme.rangeSliderTrackShape} /// * [RectangularRangeSliderTrackShape], for a similar track with sharp edges. class RoundedRectRangeSliderTrackShape extends RangeSliderTrackShape { /// Create a slider track with rounded outer edges. diff --git a/packages/flutter/lib/src/material/snack_bar.dart b/packages/flutter/lib/src/material/snack_bar.dart index 6da305aa199c1..a37085330b5f8 100644 --- a/packages/flutter/lib/src/material/snack_bar.dart +++ b/packages/flutter/lib/src/material/snack_bar.dart @@ -612,7 +612,7 @@ class _SnackBarState extends State { return Hero( tag: '', - child: snackBarTransition, + child: ClipRect(child: snackBarTransition), ); } } diff --git a/packages/flutter/lib/src/material/switch.dart b/packages/flutter/lib/src/material/switch.dart index 6a71b7f78294e..b3eb1c84aa9b5 100644 --- a/packages/flutter/lib/src/material/switch.dart +++ b/packages/flutter/lib/src/material/switch.dart @@ -229,25 +229,6 @@ class Switch extends StatelessWidget { /// * [MaterialState.hovered]. /// * [MaterialState.focused]. /// * [MaterialState.disabled]. - /// - /// {@tool snippet} - /// This example resolves the [thumbColor] based on the current - /// [MaterialState] of the [Switch], providing a different [Color] when it is - /// [MaterialState.disabled]. - /// - /// ```dart - /// Switch( - /// value: true, - /// onChanged: (_) => true, - /// thumbColor: MaterialStateProperty.resolveWith((states) { - /// if (states.contains(MaterialState.disabled)) { - /// return Colors.orange.withOpacity(.48); - /// } - /// return Colors.orange; - /// }), - /// ) - /// ``` - /// {@end-tool} /// {@endtemplate} /// /// If null, then the value of [activeColor] is used in the selected @@ -270,25 +251,6 @@ class Switch extends StatelessWidget { /// * [MaterialState.hovered]. /// * [MaterialState.focused]. /// * [MaterialState.disabled]. - /// - /// {@tool snippet} - /// This example resolves the [trackColor] based on the current - /// [MaterialState] of the [Switch], providing a different [Color] when it is - /// [MaterialState.disabled]. - /// - /// ```dart - /// Switch( - /// value: true, - /// onChanged: (_) => true, - /// thumbColor: MaterialStateProperty.resolveWith((states) { - /// if (states.contains(MaterialState.disabled)) { - /// return Colors.orange.withOpacity(.48); - /// } - /// return Colors.orange; - /// }), - /// ) - /// ``` - /// {@end-tool} /// {@endtemplate} /// /// If null, then the value of [activeTrackColor] is used in the selected diff --git a/packages/flutter/lib/src/material/tab_bar_theme.dart b/packages/flutter/lib/src/material/tab_bar_theme.dart index ff442fea33040..49a95fe5a8d87 100644 --- a/packages/flutter/lib/src/material/tab_bar_theme.dart +++ b/packages/flutter/lib/src/material/tab_bar_theme.dart @@ -5,8 +5,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'ink_well.dart'; -import 'material_state.dart'; import 'tabs.dart'; import 'theme.dart'; @@ -35,8 +33,6 @@ class TabBarTheme with Diagnosticable { this.labelStyle, this.unselectedLabelColor, this.unselectedLabelStyle, - this.overlayColor, - this.splashFactory, }); /// Default value for [TabBar.indicator]. @@ -64,12 +60,6 @@ class TabBarTheme with Diagnosticable { /// Default value for [TabBar.unselectedLabelStyle]. final TextStyle? unselectedLabelStyle; - /// Default value for [TabBar.overlayColor]. - final MaterialStateProperty? overlayColor; - - /// Default value for [TabBar.splashFactory]. - final InteractiveInkFeatureFactory? splashFactory; - /// Creates a copy of this object but with the given fields replaced with the /// new values. TabBarTheme copyWith({ @@ -80,8 +70,6 @@ class TabBarTheme with Diagnosticable { TextStyle? labelStyle, Color? unselectedLabelColor, TextStyle? unselectedLabelStyle, - MaterialStateProperty? overlayColor, - InteractiveInkFeatureFactory? splashFactory, }) { return TabBarTheme( indicator: indicator ?? this.indicator, @@ -91,8 +79,6 @@ class TabBarTheme with Diagnosticable { labelStyle: labelStyle ?? this.labelStyle, unselectedLabelColor: unselectedLabelColor ?? this.unselectedLabelColor, unselectedLabelStyle: unselectedLabelStyle ?? this.unselectedLabelStyle, - overlayColor: overlayColor ?? this.overlayColor, - splashFactory: splashFactory ?? this.splashFactory, ); } @@ -118,8 +104,6 @@ class TabBarTheme with Diagnosticable { labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t), unselectedLabelColor: Color.lerp(a.unselectedLabelColor, b.unselectedLabelColor, t), unselectedLabelStyle: TextStyle.lerp(a.unselectedLabelStyle, b.unselectedLabelStyle, t), - overlayColor: _LerpColors(a.overlayColor, b.overlayColor, t), - splashFactory: t < 0.5 ? a.splashFactory : b.splashFactory, ); } @@ -133,8 +117,6 @@ class TabBarTheme with Diagnosticable { labelStyle, unselectedLabelColor, unselectedLabelStyle, - overlayColor, - splashFactory, ); } @@ -151,42 +133,6 @@ class TabBarTheme with Diagnosticable { && other.labelPadding == labelPadding && other.labelStyle == labelStyle && other.unselectedLabelColor == unselectedLabelColor - && other.unselectedLabelStyle == unselectedLabelStyle - && other.overlayColor == overlayColor - && other.splashFactory == splashFactory; - } -} - - -@immutable -class _LerpColors implements MaterialStateProperty { - const _LerpColors(this.a, this.b, this.t); - - final MaterialStateProperty? a; - final MaterialStateProperty? b; - final double t; - - @override - Color? resolve(Set states) { - final Color? resolvedA = a?.resolve(states); - final Color? resolvedB = b?.resolve(states); - return Color.lerp(resolvedA, resolvedB, t); - } - - @override - int get hashCode { - return hashValues(a, b, t); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) - return true; - if (other.runtimeType != runtimeType) - return false; - return other is _LerpColors - && other.a == a - && other.b == b - && other.t == t; + && other.unselectedLabelStyle == unselectedLabelStyle; } } diff --git a/packages/flutter/lib/src/material/tab_controller.dart b/packages/flutter/lib/src/material/tab_controller.dart index df84c196dff50..fd20e091a5bb1 100644 --- a/packages/flutter/lib/src/material/tab_controller.dart +++ b/packages/flutter/lib/src/material/tab_controller.dart @@ -101,12 +101,11 @@ class TabController extends ChangeNotifier { /// /// The `initialIndex` must be valid given [length] and must not be null. If /// [length] is zero, then `initialIndex` must be 0 (the default). - TabController({ int initialIndex = 0, Duration? animationDuration, required this.length, required TickerProvider vsync}) + TabController({ int initialIndex = 0, required this.length, required TickerProvider vsync }) : assert(length != null && length >= 0), assert(initialIndex != null && initialIndex >= 0 && (length == 0 || initialIndex < length)), _index = initialIndex, _previousIndex = initialIndex, - _animationDuration = animationDuration ?? kTabScrollDuration, _animationController = AnimationController.unbounded( value: initialIndex.toDouble(), vsync: vsync, @@ -118,16 +117,14 @@ class TabController extends ChangeNotifier { required int index, required int previousIndex, required AnimationController? animationController, - required Duration animationDuration, required this.length, }) : _index = index, _previousIndex = previousIndex, - _animationController = animationController, - _animationDuration = animationDuration; + _animationController = animationController; - /// Creates a new [TabController] with `index`, `previousIndex`, `length`, and - /// `animationDuration` if they are non-null. + /// Creates a new [TabController] with `index`, `previousIndex`, and `length` + /// if they are non-null. /// /// This method is used by [DefaultTabController]. /// @@ -137,7 +134,6 @@ class TabController extends ChangeNotifier { required int? index, required int? length, required int? previousIndex, - required Duration? animationDuration, }) { if (index != null) { _animationController!.value = index.toDouble(); @@ -147,7 +143,6 @@ class TabController extends ChangeNotifier { length: length ?? this.length, animationController: _animationController, previousIndex: previousIndex ?? _previousIndex, - animationDuration: animationDuration ?? _animationDuration, ); } @@ -164,12 +159,6 @@ class TabController extends ChangeNotifier { Animation? get animation => _animationController?.view; AnimationController? _animationController; - /// Controls the duration of TabController and TabBarView animations. - /// - /// Defaults to kTabScrollDuration. - Duration get animationDuration => _animationDuration; - final Duration _animationDuration; - /// The total number of tabs. /// /// Typically greater than one. Must match [TabBar.tabs]'s and @@ -185,7 +174,7 @@ class TabController extends ChangeNotifier { return; _previousIndex = index; _index = value; - if (duration != null && duration > Duration.zero) { + if (duration != null) { _indexIsChangingCount += 1; notifyListeners(); // Because the value of indexIsChanging may have changed. _animationController! @@ -239,8 +228,8 @@ class TabController extends ChangeNotifier { /// /// While the animation is running [indexIsChanging] is true. When the /// animation completes [offset] will be 0.0. - void animateTo(int value, { Duration? duration, Curve curve = Curves.ease }) { - _changeIndex(value, duration: duration ?? _animationDuration, curve: curve); + void animateTo(int value, { Duration duration = kTabScrollDuration, Curve curve = Curves.ease }) { + _changeIndex(value, duration: duration, curve: curve); } /// The difference between the [animation]'s value and [index]. @@ -344,7 +333,6 @@ class DefaultTabController extends StatefulWidget { required this.length, this.initialIndex = 0, required this.child, - this.animationDuration, }) : assert(initialIndex != null), assert(length >= 0), assert(length == 0 || (initialIndex >= 0 && initialIndex < length)), @@ -361,11 +349,6 @@ class DefaultTabController extends StatefulWidget { /// Defaults to zero. final int initialIndex; - /// Controls the duration of DefaultTabController and TabBarView animations. - /// - /// Defaults to kTabScrollDuration. - final Duration? animationDuration; - /// The widget below this widget in the tree. /// /// Typically a [Scaffold] whose [AppBar] includes a [TabBar]. @@ -401,7 +384,6 @@ class _DefaultTabControllerState extends State with Single vsync: this, length: widget.length, initialIndex: widget.initialIndex, - animationDuration: widget.animationDuration, ); } @@ -434,19 +416,9 @@ class _DefaultTabControllerState extends State with Single } _controller = _controller._copyWith( length: widget.length, - animationDuration: widget.animationDuration, index: newIndex, previousIndex: previousIndex, ); } - - if (oldWidget.animationDuration != widget.animationDuration) { - _controller = _controller._copyWith( - length: widget.length, - animationDuration: widget.animationDuration, - index: _controller.index, - previousIndex: _controller.previousIndex, - ); - } } } diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 469c254b4f0b3..34023dfd53e7c 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -643,7 +643,6 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { this.enableFeedback, this.onTap, this.physics, - this.splashFactory, }) : assert(tabs != null), assert(isScrollable != null), assert(dragStartBehavior != null), @@ -787,11 +786,14 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { /// [MaterialState.hovered], and [MaterialState.pressed]. /// /// [MaterialState.pressed] triggers a ripple (an ink splash), per - /// the current Material Design spec. + /// the current Material Design spec. The [overlayColor] doesn't map + /// a state to [InkResponse.highlightColor] because a separate highlight + /// is not used by the current design guidelines. See + /// https://material.io/design/interaction/states.html#pressed /// /// If the overlay color is null or resolves to null, then the default values - /// for [InkResponse.focusColor], [InkResponse.hoverColor], [InkResponse.splashColor], - /// and [InkResponse.highlightColor] will be used instead. + /// for [InkResponse.focusColor], [InkResponse.hoverColor], [InkResponse.splashColor] + /// will be used instead. final MaterialStateProperty? overlayColor; /// {@macro flutter.widgets.scrollable.dragStartBehavior} @@ -830,25 +832,6 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { /// Defaults to matching platform conventions. final ScrollPhysics? physics; - /// Creates the tab bar's [InkWell] splash factory, which defines - /// the appearance of "ink" splashes that occur in response to taps. - /// - /// Use [NoSplash.splashFactory] to defeat ink splash rendering. For example - /// to defeat both the splash and the hover/pressed overlay, but not the - /// keyboard focused overlay: - /// ```dart - /// TabBar( - /// splashFactory: NoSplash.splashFactory, - /// overlayColor: MaterialStateProperty.resolveWith( - /// (Set states) { - /// return states.contains(MaterialState.focused) ? null : Colors.transparent; - /// }, - /// ), - /// ... - /// ) - /// ``` - final InteractiveInkFeatureFactory? splashFactory; - /// A size whose height depends on if the tabs have both icons and text. /// /// [AppBar] uses this size to compute its own preferred size. @@ -999,11 +982,11 @@ class _TabBarState extends State { _initIndicatorPainter(); } - if (widget.tabs.length > _tabKeys.length) { - final int delta = widget.tabs.length - _tabKeys.length; + if (widget.tabs.length > oldWidget.tabs.length) { + final int delta = widget.tabs.length - oldWidget.tabs.length; _tabKeys.addAll(List.generate(delta, (int n) => GlobalKey())); - } else if (widget.tabs.length < _tabKeys.length) { - _tabKeys.removeRange(widget.tabs.length, _tabKeys.length); + } else if (widget.tabs.length < oldWidget.tabs.length) { + _tabKeys.removeRange(widget.tabs.length, oldWidget.tabs.length); } } @@ -1204,8 +1187,7 @@ class _TabBarState extends State { mouseCursor: widget.mouseCursor ?? SystemMouseCursors.click, onTap: () { _handleTap(index); }, enableFeedback: widget.enableFeedback ?? true, - overlayColor: widget.overlayColor ?? tabBarTheme.overlayColor, - splashFactory: widget.splashFactory ?? tabBarTheme.splashFactory, + overlayColor: widget.overlayColor, child: Padding( padding: EdgeInsets.only(bottom: widget.indicatorWeight), child: Stack( @@ -1366,18 +1348,15 @@ class _TabBarViewState extends State { void didChangeDependencies() { super.didChangeDependencies(); _updateTabController(); - _currentIndex = _controller!.index; - _pageController = PageController(initialPage: _currentIndex!); + _currentIndex = _controller?.index; + _pageController = PageController(initialPage: _currentIndex ?? 0); } @override void didUpdateWidget(TabBarView oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.controller != oldWidget.controller) { + if (widget.controller != oldWidget.controller) _updateTabController(); - _currentIndex = _controller!.index; - _pageController.jumpToPage(_currentIndex!); - } if (widget.children != oldWidget.children && _warpUnderwayCount == 0) _updateChildren(); } @@ -1413,18 +1392,10 @@ class _TabBarViewState extends State { if (_pageController.page == _currentIndex!.toDouble()) return Future.value(); - final Duration duration = _controller!.animationDuration; - - if (duration == Duration.zero) { - _pageController.jumpToPage(_currentIndex!); - return Future.value(); - } - final int previousIndex = _controller!.previousIndex; - if ((_currentIndex! - previousIndex).abs() == 1) { _warpUnderwayCount += 1; - await _pageController.animateToPage(_currentIndex!, duration: duration, curve: Curves.ease); + await _pageController.animateToPage(_currentIndex!, duration: kTabScrollDuration, curve: Curves.ease); _warpUnderwayCount -= 1; return Future.value(); } @@ -1437,14 +1408,14 @@ class _TabBarViewState extends State { setState(() { _warpUnderwayCount += 1; - _childrenWithKey = List.of(_childrenWithKey, growable: false); + _childrenWithKey = List.from(_childrenWithKey, growable: false); final Widget temp = _childrenWithKey[initialPage]; _childrenWithKey[initialPage] = _childrenWithKey[previousIndex]; _childrenWithKey[previousIndex] = temp; }); _pageController.jumpToPage(initialPage); - await _pageController.animateToPage(_currentIndex!, duration: duration, curve: Curves.ease); + await _pageController.animateToPage(_currentIndex!, duration: kTabScrollDuration, curve: Curves.ease); if (!mounted) return Future.value(); setState(() { @@ -1551,8 +1522,6 @@ class TabPageSelectorIndicator extends StatelessWidget { /// Displays a row of small circular indicators, one per tab. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=Q628ue9Cq7U} -/// /// The selected tab's indicator is highlighted. Often used in conjunction with /// a [TabBarView]. /// diff --git a/packages/flutter/lib/src/material/text_button.dart b/packages/flutter/lib/src/material/text_button.dart index fcb27dc3554e7..fb3aa74024413 100644 --- a/packages/flutter/lib/src/material/text_button.dart +++ b/packages/flutter/lib/src/material/text_button.dart @@ -244,7 +244,7 @@ class TextButton extends ButtonStyleButton { /// * `side` - null /// * `shape` - RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)) /// * `mouseCursor` - /// * disabled - SystemMouseCursors.basic + /// * disabled - SystemMouseCursors.forbidden /// * others - SystemMouseCursors.click /// * `visualDensity` - theme.visualDensity /// * `tapTargetSize` - theme.materialTapTargetSize @@ -288,7 +288,7 @@ class TextButton extends ButtonStyleButton { maximumSize: Size.infinite, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), enabledMouseCursor: SystemMouseCursors.click, - disabledMouseCursor: SystemMouseCursors.basic, + disabledMouseCursor: SystemMouseCursors.forbidden, visualDensity: theme.visualDensity, tapTargetSize: theme.materialTapTargetSize, animationDuration: kThemeChangeDuration, diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 19bff038e981e..102ecb28d1761 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -86,7 +86,33 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete @override void onSingleTapUp(TapUpDetails details) { editableText.hideToolbar(); - super.onSingleTapUp(details); + if (delegate.selectionEnabled) { + switch (Theme.of(_state.context).platform) { + case TargetPlatform.iOS: + case TargetPlatform.macOS: + switch (details.kind) { + case PointerDeviceKind.mouse: + case PointerDeviceKind.stylus: + case PointerDeviceKind.invertedStylus: + // Precise devices should place the cursor at a precise position. + renderEditable.selectPosition(cause: SelectionChangedCause.tap); + break; + case PointerDeviceKind.touch: + case PointerDeviceKind.unknown: + // On macOS/iOS/iPadOS a touch tap places the cursor at the edge + // of the word. + renderEditable.selectWordEdge(cause: SelectionChangedCause.tap); + break; + } + break; + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + renderEditable.selectPosition(cause: SelectionChangedCause.tap); + break; + } + } _state._requestKeyboard(); _state.widget.onTap?.call(); } @@ -142,13 +168,6 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete /// To integrate the [TextField] into a [Form] with other [FormField] widgets, /// consider using [TextFormField]. /// -/// {@template flutter.material.textfield.wantKeepAlive} -/// When the widget has focus, it will prevent itself from disposing via its -/// underlying [EditableText]'s [AutomaticKeepAliveClientMixin.wantKeepAlive] in -/// order to avoid losing the selection. Removing the focus will allow it to be -/// disposed. -/// {@endtemplate} -/// /// Remember to call [TextEditingController.dispose] of the [TextEditingController] /// when it is no longer needed. This will ensure we discard any resources used /// by the object. @@ -320,7 +339,7 @@ class TextField extends StatefulWidget { this.keyboardAppearance, this.scrollPadding = const EdgeInsets.all(20.0), this.dragStartBehavior = DragStartBehavior.start, - bool? enableInteractiveSelection, + this.enableInteractiveSelection = true, this.selectionControls, this.onTap, this.mouseCursor, @@ -341,6 +360,7 @@ class TextField extends StatefulWidget { smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), smartQuotesType = smartQuotesType ?? (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), assert(enableSuggestions != null), + assert(enableInteractiveSelection != null), assert(maxLengthEnforced != null), assert( maxLengthEnforced || maxLengthEnforcement == null, @@ -374,31 +394,17 @@ class TextField extends StatefulWidget { assert(enableIMEPersonalizedLearning != null), assert(contentCommitMimeTypes != null), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), - enableInteractiveSelection = enableInteractiveSelection ?? (!readOnly || !obscureText), - toolbarOptions = toolbarOptions ?? - (obscureText - ? (readOnly - // No point in even offering "Select All" in a read-only obscured - // field. - ? const ToolbarOptions() - // Writable, but obscured. - : const ToolbarOptions( - selectAll: true, - paste: true, - )) - : (readOnly - // Read-only, not obscured. - ? const ToolbarOptions( - selectAll: true, - copy: true, - ) - // Writable, not obscured. - : const ToolbarOptions( - copy: true, - cut: true, - selectAll: true, - paste: true, - ))), + toolbarOptions = toolbarOptions ?? (obscureText ? + const ToolbarOptions( + selectAll: true, + paste: true, + ) : + const ToolbarOptions( + copy: true, + cut: true, + selectAll: true, + paste: true, + )), super(key: key); /// Controls the text being edited. @@ -708,7 +714,7 @@ class TextField extends StatefulWidget { /// /// This setting is only honored on iOS devices. /// - /// If unset, defaults to [ThemeData.brightness]. + /// If unset, defaults to the brightness of [ThemeData.primaryColorBrightness]. final Brightness? keyboardAppearance; /// {@macro flutter.widgets.editableText.scrollPadding} @@ -1163,19 +1169,15 @@ class _TextFieldState extends State with RestorationMixin implements switch (Theme.of(context).platform) { case TargetPlatform.iOS: case TargetPlatform.macOS: - if (cause == SelectionChangedCause.longPress - || cause == SelectionChangedCause.drag) { - _editableText?.bringIntoView(selection.extent); + if (cause == SelectionChangedCause.longPress) { + _editableText?.bringIntoView(selection.base); } return; + case TargetPlatform.android: + case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - case TargetPlatform.fuchsia: - case TargetPlatform.android: - if (cause == SelectionChangedCause.drag) { - _editableText?.bringIntoView(selection.extent); - } - return; + // Do nothing. } } @@ -1231,7 +1233,7 @@ class _TextFieldState extends State with RestorationMixin implements final ThemeData theme = Theme.of(context); final TextSelectionThemeData selectionTheme = TextSelectionTheme.of(context); final TextStyle style = theme.textTheme.subtitle1!.merge(widget.style); - final Brightness keyboardAppearance = widget.keyboardAppearance ?? theme.brightness; + final Brightness keyboardAppearance = widget.keyboardAppearance ?? theme.primaryColorBrightness; final TextEditingController controller = _effectiveController; final FocusNode focusNode = _effectiveFocusNode; final List formatters = [ @@ -1278,7 +1280,8 @@ class _TextFieldState extends State with RestorationMixin implements cursorRadius ??= const Radius.circular(2.0); cursorOffset = Offset(iOSHorizontalOffset / MediaQuery.of(context).devicePixelRatio, 0); handleDidGainAccessibilityFocus = () { - // Automatically activate the TextField when it receives accessibility focus. + // macOS automatically activated the TextField when it receives + // accessibility focus. if (!_effectiveFocusNode.hasFocus && _effectiveFocusNode.canRequestFocus) { _effectiveFocusNode.requestFocus(); } @@ -1296,14 +1299,6 @@ class _TextFieldState extends State with RestorationMixin implements break; case TargetPlatform.linux: - forcePressEnabled = false; - textSelectionControls ??= desktopTextSelectionControls; - paintCursorAboveText = false; - cursorOpacityAnimates = false; - cursorColor ??= selectionTheme.cursorColor ?? theme.colorScheme.primary; - selectionColor = selectionTheme.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40); - break; - case TargetPlatform.windows: forcePressEnabled = false; textSelectionControls ??= desktopTextSelectionControls; @@ -1311,12 +1306,6 @@ class _TextFieldState extends State with RestorationMixin implements cursorOpacityAnimates = false; cursorColor ??= selectionTheme.cursorColor ?? theme.colorScheme.primary; selectionColor = selectionTheme.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40); - handleDidGainAccessibilityFocus = () { - // Automatically activate the TextField when it receives accessibility focus. - if (!_effectiveFocusNode.hasFocus && _effectiveFocusNode.canRequestFocus) { - _effectiveFocusNode.requestFocus(); - } - }; break; } diff --git a/packages/flutter/lib/src/material/text_form_field.dart b/packages/flutter/lib/src/material/text_form_field.dart index 9c63c2c0d9fd4..3b1c810814314 100644 --- a/packages/flutter/lib/src/material/text_form_field.dart +++ b/packages/flutter/lib/src/material/text_form_field.dart @@ -31,8 +31,6 @@ export 'package:flutter/services.dart' show SmartQuotesType, SmartDashesType; /// If a [controller] is not specified, [initialValue] can be used to give /// the automatically generated controller an initial value. /// -/// {@macro flutter.material.textfield.wantKeepAlive} -/// /// Remember to call [TextEditingController.dispose] of the [TextEditingController] /// when it is no longer needed. This will ensure we discard any resources used /// by the object. @@ -143,7 +141,7 @@ class TextFormField extends FormField { Color? cursorColor, Brightness? keyboardAppearance, EdgeInsets scrollPadding = const EdgeInsets.all(20.0), - bool? enableInteractiveSelection, + bool enableInteractiveSelection = true, TextSelectionControls? selectionControls, InputCounterWidgetBuilder? buildCounter, ScrollPhysics? scrollPhysics, @@ -179,6 +177,7 @@ class TextFormField extends FormField { ), assert(!obscureText || maxLines == 1, 'Obscured fields cannot be multiline.'), assert(maxLength == null || maxLength == TextField.noMaxLength || maxLength > 0), + assert(enableInteractiveSelection != null), assert(enableIMEPersonalizedLearning != null), super( key: key, @@ -242,7 +241,7 @@ class TextFormField extends FormField { scrollPadding: scrollPadding, scrollPhysics: scrollPhysics, keyboardAppearance: keyboardAppearance, - enableInteractiveSelection: enableInteractiveSelection ?? (!obscureText || !readOnly), + enableInteractiveSelection: enableInteractiveSelection, selectionControls: selectionControls, buildCounter: buildCounter, autofillHints: autofillHints, diff --git a/packages/flutter/lib/src/material/text_theme.dart b/packages/flutter/lib/src/material/text_theme.dart index de0a958e0a8c4..f351b6fd801e8 100644 --- a/packages/flutter/lib/src/material/text_theme.dart +++ b/packages/flutter/lib/src/material/text_theme.dart @@ -17,20 +17,17 @@ import 'typography.dart'; /// [BuildContext] and read the [ThemeData.textTheme] property. /// /// The names of the TextTheme properties match this table from the -/// [Material Design spec](https://m3.material.io/styles/typography/tokens). -/// -/// ![](https://lh3.googleusercontent.com/Yvngs5mQSjXa_9T4X3JDucO62c5hdZHPDa7qeRH6DsJQvGr_q7EBrTkhkPiQd9OeR1v_Uk38Cjd9nUpP3nevDyHpKWuXSfQ1Gq78bOnBN7sr=s0) -/// -/// The Material Design typography scheme was significantly changed in the -/// current (2021) version of the specification -/// ([https://m3.material.io/styles/typography/tokens](https://m3.material.io/styles/typography/tokens)). -/// -/// The names of the 2018 TextTheme properties match this table from the /// [Material Design spec](https://material.io/design/typography/the-type-system.html#type-scale) /// with two exceptions: the styles called H1-H6 in the spec are /// headline1-headline6 in the API, and body1,body2 are called /// bodyText1 and bodyText2. /// +/// ![](https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1W8kyGVruuG_O8psvyiOaCf1lLFIMzB-N%2Ftypesystem-typescale.png) +/// +/// The Material Design typography scheme was significantly changed in the +/// current (2018) version of the specification +/// ([https://material.io/design/typography](https://material.io/design/typography)). +/// /// The 2018 spec has thirteen text styles: /// ``` /// NAME SIZE WEIGHT SPACING @@ -81,200 +78,66 @@ class TextTheme with Diagnosticable { /// /// If you do decide to create your own text theme, consider using one of /// those predefined themes as a starting point for [copyWith] or [apply]. - /// - /// Please note that you can not mix and match the 2018 styles with the 2021 - /// styles. Only one or the other is allowed in this constructor. The 2018 - /// styles will be deprecated and removed eventually. const TextTheme({ - TextStyle? displayLarge, - TextStyle? displayMedium, - TextStyle? displaySmall, - this.headlineLarge, - TextStyle? headlineMedium, - TextStyle? headlineSmall, - TextStyle? titleLarge, - TextStyle? titleMedium, - TextStyle? titleSmall, - TextStyle? bodyLarge, - TextStyle? bodyMedium, - TextStyle? bodySmall, - TextStyle? labelLarge, - this.labelMedium, - TextStyle? labelSmall, - TextStyle? headline1, - TextStyle? headline2, - TextStyle? headline3, - TextStyle? headline4, - TextStyle? headline5, - TextStyle? headline6, - TextStyle? subtitle1, - TextStyle? subtitle2, - TextStyle? bodyText1, - TextStyle? bodyText2, - TextStyle? caption, - TextStyle? button, - TextStyle? overline, - }) : assert( - (displayLarge == null && displayMedium == null && displaySmall == null && headlineMedium == null && - headlineSmall == null && titleLarge == null && titleMedium == null && titleSmall == null && - bodyLarge == null && bodyMedium == null && bodySmall == null && labelLarge == null && labelSmall == null) || - (headline1 == null && headline2 == null && headline3 == null && headline4 == null && - headline5 == null && headline6 == null && subtitle1 == null && subtitle2 == null && - bodyText1 == null && bodyText2 == null && caption == null && button == null && overline == null), - 'Cannot mix 2018 and 2021 terms in call to TextTheme() constructor.' - ), - displayLarge = displayLarge ?? headline1, - displayMedium = displayMedium ?? headline2, - displaySmall = displaySmall ?? headline3, - headlineMedium = headlineMedium ?? headline4, - headlineSmall = headlineSmall ?? headline5, - titleLarge = titleLarge ?? headline6, - titleMedium = titleMedium ?? subtitle1, - titleSmall = titleSmall ?? subtitle2, - bodyLarge = bodyLarge ?? bodyText1, - bodyMedium = bodyMedium ?? bodyText2, - bodySmall = bodySmall ?? caption, - labelLarge = labelLarge ?? button, - labelSmall = labelSmall ?? overline; - - /// Largest of the display styles. - /// - /// As the largest text on the screen, display styles are reserved for short, - /// important text or numerals. They work best on large screens. - final TextStyle? displayLarge; - - /// Middle size of the display styles. - /// - /// As the largest text on the screen, display styles are reserved for short, - /// important text or numerals. They work best on large screens. - final TextStyle? displayMedium; - - /// Smallest of the display styles. - /// - /// As the largest text on the screen, display styles are reserved for short, - /// important text or numerals. They work best on large screens. - final TextStyle? displaySmall; - - /// Largest of the headline styles. - /// - /// Headline styles are smaller than display styles. They're best-suited for - /// short, high-emphasis text on smaller screens. - final TextStyle? headlineLarge; - - /// Middle size of the headline styles. - /// - /// Headline styles are smaller than display styles. They're best-suited for - /// short, high-emphasis text on smaller screens. - final TextStyle? headlineMedium; - - /// Smallest of the headline styles. - /// - /// Headline styles are smaller than display styles. They're best-suited for - /// short, high-emphasis text on smaller screens. - final TextStyle? headlineSmall; - - /// Largest of the title styles. - /// - /// Titles are smaller than headline styles and should be used for shorter, - /// medium-emphasis text. - final TextStyle? titleLarge; - - /// Middle size of the title styles. - /// - /// Titles are smaller than headline styles and should be used for shorter, - /// medium-emphasis text. - final TextStyle? titleMedium; - - /// Smallest of the title styles. - /// - /// Titles are smaller than headline styles and should be used for shorter, - /// medium-emphasis text. - final TextStyle? titleSmall; - - /// Largest of the body styles. - /// - /// Body styles are used for longer passages of text. - final TextStyle? bodyLarge; - - /// Middle size of the body styles. - /// - /// Body styles are used for longer passages of text. - /// - /// The default text style for [Material]. - final TextStyle? bodyMedium; - - /// Smallest of the body styles. - /// - /// Body styles are used for longer passages of text. - final TextStyle? bodySmall; - - /// Largest of the label styles. - /// - /// Label styles are smaller, utilitarian styles, used for areas of the UI - /// such as text inside of components or very small supporting text in the - /// content body, like captions. - /// - /// Used for text on [ElevatedButton], [TextButton] and [OutlinedButton]. - final TextStyle? labelLarge; - - /// Middle size of the label styles. - /// - /// Label styles are smaller, utilitarian styles, used for areas of the UI - /// such as text inside of components or very small supporting text in the - /// content body, like captions. - final TextStyle? labelMedium; - - /// Smallest of the label styles. - /// - /// Label styles are smaller, utilitarian styles, used for areas of the UI - /// such as text inside of components or very small supporting text in the - /// content body, like captions. - final TextStyle? labelSmall; + this.headline1, + this.headline2, + this.headline3, + this.headline4, + this.headline5, + this.headline6, + this.subtitle1, + this.subtitle2, + this.bodyText1, + this.bodyText2, + this.caption, + this.button, + this.overline, + }); /// Extremely large text. - TextStyle? get headline1 => displayLarge; + final TextStyle? headline1; /// Very, very large text. /// /// Used for the date in the dialog shown by [showDatePicker]. - TextStyle? get headline2 => displayMedium; + final TextStyle? headline2; /// Very large text. - TextStyle? get headline3 => displaySmall; + final TextStyle? headline3; /// Large text. - TextStyle? get headline4 => headlineMedium; + final TextStyle? headline4; /// Used for large text in dialogs (e.g., the month and year in the dialog /// shown by [showDatePicker]). - TextStyle? get headline5 => headlineSmall; + final TextStyle? headline5; /// Used for the primary text in app bars and dialogs (e.g., [AppBar.title] /// and [AlertDialog.title]). - TextStyle? get headline6 => titleLarge; + final TextStyle? headline6; /// Used for the primary text in lists (e.g., [ListTile.title]). - TextStyle? get subtitle1 => titleMedium; + final TextStyle? subtitle1; /// For medium emphasis text that's a little smaller than [subtitle1]. - TextStyle? get subtitle2 => titleSmall; + final TextStyle? subtitle2; /// Used for emphasizing text that would otherwise be [bodyText2]. - TextStyle? get bodyText1 => bodyLarge; + final TextStyle? bodyText1; /// The default text style for [Material]. - TextStyle? get bodyText2 => bodyMedium; + final TextStyle? bodyText2; /// Used for auxiliary text associated with images. - TextStyle? get caption => bodySmall; + final TextStyle? caption; /// Used for text on [ElevatedButton], [TextButton] and [OutlinedButton]. - TextStyle? get button => labelLarge; + final TextStyle? button; /// The smallest style. /// /// Typically used for captions or to introduce a (larger) headline. - TextStyle? get overline => labelSmall; + final TextStyle? overline; /// Creates a copy of this text theme but with the given fields replaced with /// the new values. @@ -300,7 +163,7 @@ class TextTheme with Diagnosticable { /// return Theme( /// data: theme.copyWith( /// textTheme: theme.textTheme.copyWith( - /// titleLarge: theme.textTheme.titleLarge!.copyWith( + /// headline6: theme.textTheme.headline6!.copyWith( /// color: titleColor, /// ), /// ), @@ -317,21 +180,6 @@ class TextTheme with Diagnosticable { /// * [merge] is used instead of [copyWith] when you want to merge all /// of the fields of a TextTheme instead of individual fields. TextTheme copyWith({ - TextStyle? displayLarge, - TextStyle? displayMedium, - TextStyle? displaySmall, - TextStyle? headlineLarge, - TextStyle? headlineMedium, - TextStyle? headlineSmall, - TextStyle? titleLarge, - TextStyle? titleMedium, - TextStyle? titleSmall, - TextStyle? bodyLarge, - TextStyle? bodyMedium, - TextStyle? bodySmall, - TextStyle? labelLarge, - TextStyle? labelMedium, - TextStyle? labelSmall, TextStyle? headline1, TextStyle? headline2, TextStyle? headline3, @@ -346,31 +194,20 @@ class TextTheme with Diagnosticable { TextStyle? button, TextStyle? overline, }) { - assert( - (displayLarge == null && displayMedium == null && displaySmall == null && headlineMedium == null && - headlineSmall == null && titleLarge == null && titleMedium == null && titleSmall == null && - bodyLarge == null && bodyMedium == null && bodySmall == null && labelLarge == null && labelSmall == null) || - (headline1 == null && headline2 == null && headline3 == null && headline4 == null && - headline5 == null && headline6 == null && subtitle1 == null && subtitle2 == null && - bodyText1 == null && bodyText2 == null && caption == null && button == null && overline == null), - 'Cannot mix 2018 and 2021 terms in call to TextTheme() constructor.' - ); return TextTheme( - displayLarge: displayLarge ?? headline1 ?? this.displayLarge, - displayMedium: displayMedium ?? headline2 ?? this.displayMedium, - displaySmall: displaySmall ?? headline3 ?? this.displaySmall, - headlineLarge: headlineLarge ?? this.headlineLarge, - headlineMedium: headlineMedium ?? headline4 ?? this.headlineMedium, - headlineSmall: headlineSmall ?? headline5 ?? this.headlineSmall, - titleLarge: titleLarge ?? headline6 ?? this.titleLarge, - titleMedium: titleMedium ?? subtitle1 ?? this.titleMedium, - titleSmall: titleSmall ?? subtitle2 ?? this.titleSmall, - bodyLarge: bodyLarge ?? bodyText1 ?? this.bodyLarge, - bodyMedium: bodyMedium ?? bodyText2 ?? this.bodyMedium, - bodySmall: bodySmall ?? caption ?? this.bodySmall, - labelLarge: labelLarge ?? button ?? this.labelLarge, - labelMedium: labelMedium ?? this.labelMedium, - labelSmall: labelSmall ?? overline ?? this.labelSmall, + headline1: headline1 ?? this.headline1, + headline2: headline2 ?? this.headline2, + headline3: headline3 ?? this.headline3, + headline4: headline4 ?? this.headline4, + headline5: headline5 ?? this.headline5, + headline6: headline6 ?? this.headline6, + subtitle1: subtitle1 ?? this.subtitle1, + subtitle2: subtitle2 ?? this.subtitle2, + bodyText1: bodyText1 ?? this.bodyText1, + bodyText2: bodyText2 ?? this.bodyText2, + caption: caption ?? this.caption, + button: button ?? this.button, + overline: overline ?? this.overline, ); } @@ -412,7 +249,7 @@ class TextTheme with Diagnosticable { /// // set the title, but everything else would be null. This isn't very /// // useful, so merge it with the existing theme to keep all of the /// // preexisting definitions for the other styles. - /// final TextTheme partialTheme = TextTheme(titleLarge: TextStyle(color: titleColor)); + /// final TextTheme partialTheme = TextTheme(headline6: TextStyle(color: titleColor)); /// theme = theme.copyWith(textTheme: theme.textTheme.merge(partialTheme)); /// return Theme(data: theme, child: child); /// } @@ -429,30 +266,28 @@ class TextTheme with Diagnosticable { if (other == null) return this; return copyWith( - displayLarge: displayLarge?.merge(other.displayLarge) ?? other.displayLarge, - displayMedium: displayMedium?.merge(other.displayMedium) ?? other.displayMedium, - displaySmall: displaySmall?.merge(other.displaySmall) ?? other.displaySmall, - headlineLarge: headlineLarge?.merge(other.headlineLarge) ?? other.headlineLarge, - headlineMedium: headlineMedium?.merge(other.headlineMedium) ?? other.headlineMedium, - headlineSmall: headlineSmall?.merge(other.headlineSmall) ?? other.headlineSmall, - titleLarge: titleLarge?.merge(other.titleLarge) ?? other.titleLarge, - titleMedium: titleMedium?.merge(other.titleMedium) ?? other.titleMedium, - titleSmall: titleSmall?.merge(other.titleSmall) ?? other.titleSmall, - bodyLarge: bodyLarge?.merge(other.bodyLarge) ?? other.bodyLarge, - bodyMedium: bodyMedium?.merge(other.bodyMedium) ?? other.bodyMedium, - bodySmall: bodySmall?.merge(other.bodySmall) ?? other.bodySmall, - labelLarge: labelLarge?.merge(other.labelLarge) ?? other.labelLarge, - labelMedium: labelMedium?.merge(other.labelMedium) ?? other.labelMedium, - labelSmall: labelSmall?.merge(other.labelSmall) ?? other.labelSmall, + headline1: headline1?.merge(other.headline1) ?? other.headline1, + headline2: headline2?.merge(other.headline2) ?? other.headline2, + headline3: headline3?.merge(other.headline3) ?? other.headline3, + headline4: headline4?.merge(other.headline4) ?? other.headline4, + headline5: headline5?.merge(other.headline5) ?? other.headline5, + headline6: headline6?.merge(other.headline6) ?? other.headline6, + subtitle1: subtitle1?.merge(other.subtitle1) ?? other.subtitle1, + subtitle2: subtitle2?.merge(other.subtitle2) ?? other.subtitle2, + bodyText1: bodyText1?.merge(other.bodyText1) ?? other.bodyText1, + bodyText2: bodyText2?.merge(other.bodyText2) ?? other.bodyText2, + caption: caption?.merge(other.caption) ?? other.caption, + button: button?.merge(other.button) ?? other.button, + overline: overline?.merge(other.overline) ?? other.overline, ); } /// Creates a copy of this text theme but with the given field replaced in /// each of the individual text styles. /// - /// The `displayColor` is applied to [displayLarge], [displayMedium], - /// [displaySmall], [headlineLarge], [headlineMedium], and [bodySmall]. The - /// `bodyColor` is applied to the remaining text styles. + /// The `displayColor` is applied to [headline4], [headline3], [headline2], + /// [headline1], and [caption]. The `bodyColor` is applied to the remaining + /// text styles. /// /// Consider using [Typography.black] or [Typography.white], which implement /// the typography styles in the material design specification, as a starting @@ -468,16 +303,7 @@ class TextTheme with Diagnosticable { TextDecorationStyle? decorationStyle, }) { return TextTheme( - displayLarge: displayLarge?.apply( - color: displayColor, - decoration: decoration, - decorationColor: decorationColor, - decorationStyle: decorationStyle, - fontFamily: fontFamily, - fontSizeFactor: fontSizeFactor, - fontSizeDelta: fontSizeDelta, - ), - displayMedium: displayMedium?.apply( + headline1: headline1?.apply( color: displayColor, decoration: decoration, decorationColor: decorationColor, @@ -486,7 +312,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - displaySmall: displaySmall?.apply( + headline2: headline2?.apply( color: displayColor, decoration: decoration, decorationColor: decorationColor, @@ -495,7 +321,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - headlineLarge: headlineLarge?.apply( + headline3: headline3?.apply( color: displayColor, decoration: decoration, decorationColor: decorationColor, @@ -504,7 +330,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - headlineMedium: headlineMedium?.apply( + headline4: headline4?.apply( color: displayColor, decoration: decoration, decorationColor: decorationColor, @@ -513,7 +339,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - headlineSmall: headlineSmall?.apply( + headline5: headline5?.apply( color: bodyColor, decoration: decoration, decorationColor: decorationColor, @@ -522,7 +348,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - titleLarge: titleLarge?.apply( + headline6: headline6?.apply( color: bodyColor, decoration: decoration, decorationColor: decorationColor, @@ -531,7 +357,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - titleMedium: titleMedium?.apply( + subtitle1: subtitle1?.apply( color: bodyColor, decoration: decoration, decorationColor: decorationColor, @@ -540,7 +366,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - titleSmall: titleSmall?.apply( + subtitle2: subtitle2?.apply( color: bodyColor, decoration: decoration, decorationColor: decorationColor, @@ -549,7 +375,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - bodyLarge: bodyLarge?.apply( + bodyText1: bodyText1?.apply( color: bodyColor, decoration: decoration, decorationColor: decorationColor, @@ -558,7 +384,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - bodyMedium: bodyMedium?.apply( + bodyText2: bodyText2?.apply( color: bodyColor, decoration: decoration, decorationColor: decorationColor, @@ -567,7 +393,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - bodySmall: bodySmall?.apply( + caption: caption?.apply( color: displayColor, decoration: decoration, decorationColor: decorationColor, @@ -576,16 +402,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - labelLarge: labelLarge?.apply( - color: bodyColor, - decoration: decoration, - decorationColor: decorationColor, - decorationStyle: decorationStyle, - fontFamily: fontFamily, - fontSizeFactor: fontSizeFactor, - fontSizeDelta: fontSizeDelta, - ), - labelMedium: labelMedium?.apply( + button: button?.apply( color: bodyColor, decoration: decoration, decorationColor: decorationColor, @@ -594,7 +411,7 @@ class TextTheme with Diagnosticable { fontSizeFactor: fontSizeFactor, fontSizeDelta: fontSizeDelta, ), - labelSmall: labelSmall?.apply( + overline: overline?.apply( color: bodyColor, decoration: decoration, decorationColor: decorationColor, @@ -612,21 +429,19 @@ class TextTheme with Diagnosticable { static TextTheme lerp(TextTheme? a, TextTheme? b, double t) { assert(t != null); return TextTheme( - displayLarge: TextStyle.lerp(a?.displayLarge, b?.displayLarge, t), - displayMedium: TextStyle.lerp(a?.displayMedium, b?.displayMedium, t), - displaySmall: TextStyle.lerp(a?.displaySmall, b?.displaySmall, t), - headlineLarge: TextStyle.lerp(a?.headlineLarge, b?.headlineLarge, t), - headlineMedium: TextStyle.lerp(a?.headlineMedium, b?.headlineMedium, t), - headlineSmall: TextStyle.lerp(a?.headlineSmall, b?.headlineSmall, t), - titleLarge: TextStyle.lerp(a?.titleLarge, b?.titleLarge, t), - titleMedium: TextStyle.lerp(a?.titleMedium, b?.titleMedium, t), - titleSmall: TextStyle.lerp(a?.titleSmall, b?.titleSmall, t), - bodyLarge: TextStyle.lerp(a?.bodyLarge, b?.bodyLarge, t), - bodyMedium: TextStyle.lerp(a?.bodyMedium, b?.bodyMedium, t), - bodySmall: TextStyle.lerp(a?.bodySmall, b?.bodySmall, t), - labelLarge: TextStyle.lerp(a?.labelLarge, b?.labelLarge, t), - labelMedium: TextStyle.lerp(a?.labelMedium, b?.labelMedium, t), - labelSmall: TextStyle.lerp(a?.labelSmall, b?.labelSmall, t), + headline1: TextStyle.lerp(a?.headline1, b?.headline1, t), + headline2: TextStyle.lerp(a?.headline2, b?.headline2, t), + headline3: TextStyle.lerp(a?.headline3, b?.headline3, t), + headline4: TextStyle.lerp(a?.headline4, b?.headline4, t), + headline5: TextStyle.lerp(a?.headline5, b?.headline5, t), + headline6: TextStyle.lerp(a?.headline6, b?.headline6, t), + subtitle1: TextStyle.lerp(a?.subtitle1, b?.subtitle1, t), + subtitle2: TextStyle.lerp(a?.subtitle2, b?.subtitle2, t), + bodyText1: TextStyle.lerp(a?.bodyText1, b?.bodyText1, t), + bodyText2: TextStyle.lerp(a?.bodyText2, b?.bodyText2, t), + caption: TextStyle.lerp(a?.caption, b?.caption, t), + button: TextStyle.lerp(a?.button, b?.button, t), + overline: TextStyle.lerp(a?.overline, b?.overline, t), ); } @@ -637,42 +452,38 @@ class TextTheme with Diagnosticable { if (other.runtimeType != runtimeType) return false; return other is TextTheme - && displayLarge == other.displayLarge - && displayMedium == other.displayMedium - && displaySmall == other.displaySmall - && headlineLarge == other.headlineLarge - && headlineMedium == other.headlineMedium - && headlineSmall == other.headlineSmall - && titleLarge == other.titleLarge - && titleMedium == other.titleMedium - && titleSmall == other.titleSmall - && bodyLarge == other.bodyLarge - && bodyMedium == other.bodyMedium - && bodySmall == other.bodySmall - && labelLarge == other.labelLarge - && labelMedium == other.labelMedium - && labelSmall == other.labelSmall; + && headline1 == other.headline1 + && headline2 == other.headline2 + && headline3 == other.headline3 + && headline4 == other.headline4 + && headline5 == other.headline5 + && headline6 == other.headline6 + && subtitle1 == other.subtitle1 + && subtitle2 == other.subtitle2 + && bodyText1 == other.bodyText1 + && bodyText2 == other.bodyText2 + && caption == other.caption + && button == other.button + && overline == other.overline; } @override int get hashCode { // The hashValues() function supports up to 20 arguments. return hashValues( - displayLarge, - displayMedium, - displaySmall, - headlineLarge, - headlineMedium, - headlineSmall, - titleLarge, - titleMedium, - titleSmall, - bodyLarge, - bodyMedium, - bodySmall, - labelLarge, - labelMedium, - labelSmall, + headline1, + headline2, + headline3, + headline4, + headline5, + headline6, + subtitle1, + subtitle2, + bodyText1, + bodyText2, + caption, + button, + overline, ); } @@ -680,20 +491,18 @@ class TextTheme with Diagnosticable { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); final TextTheme defaultTheme = Typography.material2018(platform: defaultTargetPlatform).black; - properties.add(DiagnosticsProperty('displayLarge', displayLarge, defaultValue: defaultTheme.displayLarge)); - properties.add(DiagnosticsProperty('displayMedium', displayMedium, defaultValue: defaultTheme.displayMedium)); - properties.add(DiagnosticsProperty('displaySmall', displaySmall, defaultValue: defaultTheme.displaySmall)); - properties.add(DiagnosticsProperty('headlineLarge', headlineLarge, defaultValue: defaultTheme.headlineLarge)); - properties.add(DiagnosticsProperty('headlineMedium', headlineMedium, defaultValue: defaultTheme.headlineMedium)); - properties.add(DiagnosticsProperty('headlineSmall', headlineSmall, defaultValue: defaultTheme.headlineSmall)); - properties.add(DiagnosticsProperty('titleLarge', titleLarge, defaultValue: defaultTheme.titleLarge)); - properties.add(DiagnosticsProperty('titleMedium', titleMedium, defaultValue: defaultTheme.titleMedium)); - properties.add(DiagnosticsProperty('titleSmall', titleSmall, defaultValue: defaultTheme.titleSmall)); - properties.add(DiagnosticsProperty('bodyLarge', bodyLarge, defaultValue: defaultTheme.bodyLarge)); - properties.add(DiagnosticsProperty('bodyMedium', bodyMedium, defaultValue: defaultTheme.bodyMedium)); - properties.add(DiagnosticsProperty('bodySmall', bodySmall, defaultValue: defaultTheme.bodySmall)); - properties.add(DiagnosticsProperty('labelLarge', labelLarge, defaultValue: defaultTheme.labelLarge)); - properties.add(DiagnosticsProperty('labelMedium', labelMedium, defaultValue: defaultTheme.labelMedium)); - properties.add(DiagnosticsProperty('labelSmall', labelSmall, defaultValue: defaultTheme.labelSmall)); + properties.add(DiagnosticsProperty('headline1', headline1, defaultValue: defaultTheme.headline1)); + properties.add(DiagnosticsProperty('headline2', headline2, defaultValue: defaultTheme.headline2)); + properties.add(DiagnosticsProperty('headline3', headline3, defaultValue: defaultTheme.headline3)); + properties.add(DiagnosticsProperty('headline4', headline4, defaultValue: defaultTheme.headline4)); + properties.add(DiagnosticsProperty('headline5', headline5, defaultValue: defaultTheme.headline5)); + properties.add(DiagnosticsProperty('headline6', headline6, defaultValue: defaultTheme.headline6)); + properties.add(DiagnosticsProperty('subtitle1', subtitle1, defaultValue: defaultTheme.subtitle1)); + properties.add(DiagnosticsProperty('subtitle2', subtitle2, defaultValue: defaultTheme.subtitle2)); + properties.add(DiagnosticsProperty('bodyText1', bodyText1, defaultValue: defaultTheme.bodyText1)); + properties.add(DiagnosticsProperty('bodyText2', bodyText2, defaultValue: defaultTheme.bodyText2)); + properties.add(DiagnosticsProperty('caption', caption, defaultValue: defaultTheme.caption)); + properties.add(DiagnosticsProperty('button', button, defaultValue: defaultTheme.button)); + properties.add(DiagnosticsProperty('overline', overline, defaultValue: defaultTheme.overline)); } } diff --git a/packages/flutter/lib/src/material/theme.dart b/packages/flutter/lib/src/material/theme.dart index aec9612d1f816..4e717eda28b89 100644 --- a/packages/flutter/lib/src/material/theme.dart +++ b/packages/flutter/lib/src/material/theme.dart @@ -18,8 +18,6 @@ const Duration kThemeAnimationDuration = Duration(milliseconds: 200); /// /// A theme describes the colors and typographic choices of an application. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=oTvQDJOBXmM} -/// /// Descendant widgets obtain the current theme's [ThemeData] object using /// [Theme.of]. When a widget uses [Theme.of], it is automatically rebuilt if /// the theme later changes, so that the changes can be applied. diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index 6a40f3d93d41c..b4b5b5d8a7523 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -200,30 +200,13 @@ enum MaterialTapTargetSize { class ThemeData with Diagnosticable { /// Create a [ThemeData] that's used to configure a [Theme]. /// + /// Typically, only the [brightness], [primaryColor], or [primarySwatch] are + /// specified. That pair of values are used to construct the [colorScheme]. + /// /// The [colorScheme] and [textTheme] are used by the Material components to /// compute default values for visual properties. The API documentation for /// each component widget explains exactly how the defaults are computed. /// - /// When providing a [ColorScheme], apps can either provide one directly - /// with the [colorScheme] parameter, or have one generated for them by - /// using the [colorSchemeSeed] and [brightness] parameters. A generated - /// color scheme will be based on the tones of [colorSchemeSeed] and all of - /// its contrasting color will meet accessibility guidelines for readability. - /// (See [ColorScheme.fromSeed] for more details.) - /// - /// If the app wants to customize a generated color scheme, it can use - /// [ColorScheme.fromSeed] directly and then [ColorScheme.copyWith] on the - /// result to override any colors that need to be replaced. The result of - /// this can be used as the [colorScheme] directly. - /// - /// For historical reasons, instead of using a [colorSchemeSeed] or - /// [colorScheme], you can provide either a [primaryColor] or [primarySwatch] - /// to construct the [colorScheme], but the results will not be as complete - /// as when using generation from a seed color. - /// - /// If [colorSchemeSeed] is non-null then [colorScheme], [primaryColor] and - /// [primarySwatch] must all be null. - /// /// The [textTheme] [TextStyle] colors are black if the color scheme's /// brightness is [Brightness.light], and white for [Brightness.dark]. /// @@ -236,97 +219,50 @@ class ThemeData with Diagnosticable { /// * [ThemeData.from], which creates a ThemeData from a [ColorScheme]. /// * [ThemeData.light], which creates a light blue theme. /// * [ThemeData.dark], which creates dark theme with a teal secondary [ColorScheme] color. - /// * [ColorScheme.fromSeed], which is used to create a [ColorScheme] from a seed color. factory ThemeData({ - // GENERAL CONFIGURATION - AndroidOverscrollIndicator? androidOverscrollIndicator, - bool? applyElevationOverlayColor, - NoDefaultCupertinoThemeData? cupertinoOverrideTheme, - InputDecorationTheme? inputDecorationTheme, - MaterialTapTargetSize? materialTapTargetSize, - PageTransitionsTheme? pageTransitionsTheme, - TargetPlatform? platform, - ScrollbarThemeData? scrollbarTheme, - InteractiveInkFeatureFactory? splashFactory, - VisualDensity? visualDensity, - bool? useMaterial3, - // COLOR - // [colorScheme] is the preferred way to configure colors. The other color - // properties (as well as primaryColorBrightness, and primarySwatch) - // will gradually be phased out, see https://github.com/flutter/flutter/issues/91772. - ColorScheme? colorScheme, - Color? colorSchemeSeed, Brightness? brightness, + VisualDensity? visualDensity, MaterialColor? primarySwatch, Color? primaryColor, + Brightness? primaryColorBrightness, Color? primaryColorLight, Color? primaryColorDark, - Color? focusColor, - Color? hoverColor, - Color? shadowColor, + @Deprecated( + 'Use colorScheme.secondary instead. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + Color? accentColor, + @Deprecated( + 'No longer used by the framework, please remove any reference to it. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + Brightness? accentColorBrightness, Color? canvasColor, + Color? shadowColor, Color? scaffoldBackgroundColor, Color? bottomAppBarColor, Color? cardColor, Color? dividerColor, + Color? focusColor, + Color? hoverColor, Color? highlightColor, Color? splashColor, + InteractiveInkFeatureFactory? splashFactory, Color? selectedRowColor, Color? unselectedWidgetColor, Color? disabledColor, - Color? secondaryHeaderColor, - Color? backgroundColor, - Color? dialogBackgroundColor, - Color? indicatorColor, - Color? hintColor, - Color? errorColor, - Color? toggleableActiveColor, - // TYPOGRAPHY & ICONOGRAPHY - String? fontFamily, - Typography? typography, - TextTheme? textTheme, - TextTheme? primaryTextTheme, - IconThemeData? iconTheme, - IconThemeData? primaryIconTheme, - // COMPONENT THEMES - AppBarTheme? appBarTheme, - MaterialBannerThemeData? bannerTheme, - BottomAppBarTheme? bottomAppBarTheme, - BottomNavigationBarThemeData? bottomNavigationBarTheme, - BottomSheetThemeData? bottomSheetTheme, - ButtonBarThemeData? buttonBarTheme, - ButtonThemeData? buttonTheme, - CardTheme? cardTheme, - CheckboxThemeData? checkboxTheme, - ChipThemeData? chipTheme, - DataTableThemeData? dataTableTheme, - DialogTheme? dialogTheme, - DividerThemeData? dividerTheme, - DrawerThemeData? drawerTheme, - ElevatedButtonThemeData? elevatedButtonTheme, - FloatingActionButtonThemeData? floatingActionButtonTheme, - ListTileThemeData? listTileTheme, - NavigationBarThemeData? navigationBarTheme, - NavigationRailThemeData? navigationRailTheme, - OutlinedButtonThemeData? outlinedButtonTheme, - PopupMenuThemeData? popupMenuTheme, - ProgressIndicatorThemeData? progressIndicatorTheme, - RadioThemeData? radioTheme, - SliderThemeData? sliderTheme, - SnackBarThemeData? snackBarTheme, - SwitchThemeData? switchTheme, - TabBarTheme? tabBarTheme, - TextButtonThemeData? textButtonTheme, - TextSelectionThemeData? textSelectionTheme, - TimePickerThemeData? timePickerTheme, - ToggleButtonsThemeData? toggleButtonsTheme, - TooltipThemeData? tooltipTheme, - // DEPRECATED (newest deprecations at the bottom) @Deprecated( 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v1.23.0-4.0.pre.', + 'This feature was deprecated after v2.3.0-0.2.pre.', ) - bool? useTextSelectionTheme, + Color? buttonColor, + ButtonThemeData? buttonTheme, + ToggleButtonsThemeData? toggleButtonsTheme, + Color? secondaryHeaderColor, @Deprecated( 'Use TextSelectionThemeData.selectionColor instead. ' 'This feature was deprecated after v1.26.0-18.0.pre.', @@ -342,20 +278,15 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v1.26.0-18.0.pre.', ) Color? textSelectionHandleColor, - @Deprecated( - 'Use colorScheme.secondary instead. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - Color? accentColor, - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - Brightness? accentColorBrightness, + Color? backgroundColor, + Color? dialogBackgroundColor, + Color? indicatorColor, + Color? hintColor, + Color? errorColor, + Color? toggleableActiveColor, + String? fontFamily, + TextTheme? textTheme, + TextTheme? primaryTextTheme, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' 'For more information, consult the migration guide at ' @@ -363,6 +294,9 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v2.3.0-0.1.pre.', ) TextTheme? accentTextTheme, + InputDecorationTheme? inputDecorationTheme, + IconThemeData? iconTheme, + IconThemeData? primaryIconTheme, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' 'For more information, consult the migration guide at ' @@ -370,11 +304,44 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v2.3.0-0.1.pre.', ) IconThemeData? accentIconTheme, - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v2.3.0-0.2.pre.', - ) - Color? buttonColor, + SliderThemeData? sliderTheme, + TabBarTheme? tabBarTheme, + TooltipThemeData? tooltipTheme, + CardTheme? cardTheme, + ChipThemeData? chipTheme, + TargetPlatform? platform, + MaterialTapTargetSize? materialTapTargetSize, + bool? applyElevationOverlayColor, + PageTransitionsTheme? pageTransitionsTheme, + AppBarTheme? appBarTheme, + ScrollbarThemeData? scrollbarTheme, + BottomAppBarTheme? bottomAppBarTheme, + ColorScheme? colorScheme, + DialogTheme? dialogTheme, + FloatingActionButtonThemeData? floatingActionButtonTheme, + NavigationBarThemeData? navigationBarTheme, + NavigationRailThemeData? navigationRailTheme, + Typography? typography, + NoDefaultCupertinoThemeData? cupertinoOverrideTheme, + SnackBarThemeData? snackBarTheme, + BottomSheetThemeData? bottomSheetTheme, + PopupMenuThemeData? popupMenuTheme, + MaterialBannerThemeData? bannerTheme, + DividerThemeData? dividerTheme, + ButtonBarThemeData? buttonBarTheme, + BottomNavigationBarThemeData? bottomNavigationBarTheme, + TimePickerThemeData? timePickerTheme, + TextButtonThemeData? textButtonTheme, + ElevatedButtonThemeData? elevatedButtonTheme, + OutlinedButtonThemeData? outlinedButtonTheme, + TextSelectionThemeData? textSelectionTheme, + DataTableThemeData? dataTableTheme, + CheckboxThemeData? checkboxTheme, + RadioThemeData? radioTheme, + SwitchThemeData? switchTheme, + ProgressIndicatorThemeData? progressIndicatorTheme, + DrawerThemeData? drawerTheme, + ListTileThemeData? listTileTheme, @Deprecated( 'This "fix" is now enabled by default. ' 'This feature was deprecated after v2.5.0-1.0.pre.', @@ -382,81 +349,32 @@ class ThemeData with Diagnosticable { bool? fixTextFieldOutlineLabel, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v2.6.0-11.0.pre.', + 'This feature was deprecated after v1.23.0-4.0.pre.', ) - Brightness? primaryColorBrightness, + bool? useTextSelectionTheme, + AndroidOverscrollIndicator? androidOverscrollIndicator, }) { - // GENERAL CONFIGURATION - cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault(); - inputDecorationTheme ??= const InputDecorationTheme(); - platform ??= defaultTargetPlatform; - switch (platform) { - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.iOS: - materialTapTargetSize ??= MaterialTapTargetSize.padded; - break; - case TargetPlatform.linux: - case TargetPlatform.macOS: - case TargetPlatform.windows: - materialTapTargetSize ??= MaterialTapTargetSize.shrinkWrap; - break; - } - pageTransitionsTheme ??= const PageTransitionsTheme(); - scrollbarTheme ??= const ScrollbarThemeData(); - splashFactory ??= InkSplash.splashFactory; - visualDensity ??= VisualDensity.adaptivePlatformDensity; - useMaterial3 ??= false; - - // COLOR assert(colorScheme?.brightness == null || brightness == null || colorScheme!.brightness == brightness); - assert(colorSchemeSeed == null || colorScheme == null); - assert(colorSchemeSeed == null || primarySwatch == null); - assert(colorSchemeSeed == null || primaryColor == null); final Brightness _brightness = brightness ?? colorScheme?.brightness ?? Brightness.light; final bool isDark = _brightness == Brightness.dark; - if (colorSchemeSeed != null) { - colorScheme = ColorScheme.fromSeed(seedColor: colorSchemeSeed, brightness: _brightness); - - // For surfaces that use primary color in light themes and surface color in dark - final Color primarySurfaceColor = isDark ? colorScheme.surface : colorScheme.primary; - final Color onPrimarySurfaceColor = isDark ? colorScheme.onSurface : colorScheme.onPrimary; - - // Default some of the color settings to values from the color scheme - primaryColor = primarySurfaceColor; - primaryColorBrightness = ThemeData.estimateBrightnessForColor(primarySurfaceColor); - canvasColor ??= colorScheme.background; - accentColor ??= colorScheme.secondary; - accentColorBrightness ??= ThemeData.estimateBrightnessForColor(colorScheme.secondary); - scaffoldBackgroundColor ??= colorScheme.background; - bottomAppBarColor ??= colorScheme.surface; - cardColor ??= colorScheme.surface; - dividerColor ??= colorScheme.outline; - backgroundColor ??= colorScheme.background; - dialogBackgroundColor ??= colorScheme.background; - indicatorColor ??= onPrimarySurfaceColor; - errorColor ??= colorScheme.error; - applyElevationOverlayColor ??= isDark; - } - applyElevationOverlayColor ??= false; + visualDensity ??= VisualDensity.adaptivePlatformDensity; primarySwatch ??= Colors.blue; primaryColor ??= isDark ? Colors.grey[900]! : primarySwatch; - final Brightness _primaryColorBrightness = estimateBrightnessForColor(primaryColor); + primaryColorBrightness ??= estimateBrightnessForColor(primaryColor); primaryColorLight ??= isDark ? Colors.grey[500]! : primarySwatch[100]!; primaryColorDark ??= isDark ? Colors.black : primarySwatch[700]!; - final bool primaryIsDark = _primaryColorBrightness == Brightness.dark; + final bool primaryIsDark = primaryColorBrightness == Brightness.dark; toggleableActiveColor ??= isDark ? Colors.tealAccent[200]! : (accentColor ?? primarySwatch[600]!); accentColor ??= isDark ? Colors.tealAccent[200]! : primarySwatch[500]!; accentColorBrightness ??= estimateBrightnessForColor(accentColor); final bool accentIsDark = accentColorBrightness == Brightness.dark; - focusColor ??= isDark ? Colors.white.withOpacity(0.12) : Colors.black.withOpacity(0.12); - hoverColor ??= isDark ? Colors.white.withOpacity(0.04) : Colors.black.withOpacity(0.04); - shadowColor ??= Colors.black; canvasColor ??= isDark ? Colors.grey[850]! : Colors.grey[50]!; + shadowColor ??= Colors.black; scaffoldBackgroundColor ??= canvasColor; bottomAppBarColor ??= isDark ? Colors.grey[800]! : Colors.white; cardColor ??= isDark ? Colors.grey[800]! : Colors.white; dividerColor ??= isDark ? const Color(0x1FFFFFFF) : const Color(0x1F000000); + // Create a ColorScheme that is backwards compatible as possible // with the existing default ThemeData color values. colorScheme ??= ColorScheme.fromSwatch( @@ -468,21 +386,60 @@ class ThemeData with Diagnosticable { errorColor: errorColor, brightness: _brightness, ); + + splashFactory ??= InkSplash.splashFactory; selectedRowColor ??= Colors.grey[100]!; unselectedWidgetColor ??= isDark ? Colors.white70 : Colors.black54; // Spec doesn't specify a dark theme secondaryHeaderColor, this is a guess. secondaryHeaderColor ??= isDark ? Colors.grey[700]! : primarySwatch[50]!; + textSelectionColor ??= isDark ? accentColor : primarySwatch[200]!; + cursorColor = cursorColor ?? const Color.fromRGBO(66, 133, 244, 1.0); + textSelectionHandleColor ??= isDark ? Colors.tealAccent[400]! : primarySwatch[300]!; backgroundColor ??= isDark ? Colors.grey[700]! : primarySwatch[200]!; dialogBackgroundColor ??= isDark ? Colors.grey[800]! : Colors.white; indicatorColor ??= accentColor == primaryColor ? Colors.white : accentColor; hintColor ??= isDark ? Colors.white60 : Colors.black.withOpacity(0.6); errorColor ??= Colors.red[700]!; - // The default [buttonTheme] is here because it doesn't use the defaults for - // [disabledColor], [highlightColor], and [splashColor]. + inputDecorationTheme ??= const InputDecorationTheme(); + pageTransitionsTheme ??= const PageTransitionsTheme(); + primaryIconTheme ??= primaryIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black); + accentIconTheme ??= accentIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black); + iconTheme ??= isDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black87); + platform ??= defaultTargetPlatform; + typography ??= Typography.material2014(platform: platform); + TextTheme defaultTextTheme = isDark ? typography.white : typography.black; + TextTheme defaultPrimaryTextTheme = primaryIsDark ? typography.white : typography.black; + TextTheme defaultAccentTextTheme = accentIsDark ? typography.white : typography.black; + if (fontFamily != null) { + defaultTextTheme = defaultTextTheme.apply(fontFamily: fontFamily); + defaultPrimaryTextTheme = defaultPrimaryTextTheme.apply(fontFamily: fontFamily); + defaultAccentTextTheme = defaultAccentTextTheme.apply(fontFamily: fontFamily); + } + textTheme = defaultTextTheme.merge(textTheme); + primaryTextTheme = defaultPrimaryTextTheme.merge(primaryTextTheme); + accentTextTheme = defaultAccentTextTheme.merge(accentTextTheme); + switch (platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.iOS: + materialTapTargetSize ??= MaterialTapTargetSize.padded; + break; + case TargetPlatform.linux: + case TargetPlatform.macOS: + case TargetPlatform.windows: + materialTapTargetSize ??= MaterialTapTargetSize.shrinkWrap; + break; + } + applyElevationOverlayColor ??= false; + + // Used as the default color (fill color) for RaisedButtons. Computing the + // default for ButtonThemeData for the sake of backwards compatibility. + buttonColor ??= isDark ? primarySwatch[600]! : Colors.grey[300]!; + focusColor ??= isDark ? Colors.white.withOpacity(0.12) : Colors.black.withOpacity(0.12); + hoverColor ??= isDark ? Colors.white.withOpacity(0.04) : Colors.black.withOpacity(0.04); buttonTheme ??= ButtonThemeData( colorScheme: colorScheme, - // Defaults to the fill color for RaisedButtons for backwards compatibility. - buttonColor: buttonColor ?? (isDark ? primarySwatch[600]! : Colors.grey[300]!), + buttonColor: buttonColor, disabledColor: disabledColor, focusColor: focusColor, hoverColor: hoverColor, @@ -490,158 +447,134 @@ class ThemeData with Diagnosticable { splashColor: splashColor, materialTapTargetSize: materialTapTargetSize, ); + toggleButtonsTheme ??= const ToggleButtonsThemeData(); disabledColor ??= isDark ? Colors.white38 : Colors.black38; highlightColor ??= isDark ? _kDarkThemeHighlightColor : _kLightThemeHighlightColor; splashColor ??= isDark ? _kDarkThemeSplashColor : _kLightThemeSplashColor; - // TYPOGRAPHY & ICONOGRAPHY - typography ??= Typography.material2014(platform: platform); - TextTheme defaultTextTheme = isDark ? typography.white : typography.black; - TextTheme defaultPrimaryTextTheme = primaryIsDark ? typography.white : typography.black; - TextTheme defaultAccentTextTheme = accentIsDark ? typography.white : typography.black; - if (fontFamily != null) { - defaultTextTheme = defaultTextTheme.apply(fontFamily: fontFamily); - defaultPrimaryTextTheme = defaultPrimaryTextTheme.apply(fontFamily: fontFamily); - defaultAccentTextTheme = defaultAccentTextTheme.apply(fontFamily: fontFamily); - } - textTheme = defaultTextTheme.merge(textTheme); - primaryTextTheme = defaultPrimaryTextTheme.merge(primaryTextTheme); - iconTheme ??= isDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black87); - primaryIconTheme ??= primaryIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black); - - // COMPONENT THEMES + sliderTheme ??= const SliderThemeData(); + tabBarTheme ??= const TabBarTheme(); + tooltipTheme ??= const TooltipThemeData(); appBarTheme ??= const AppBarTheme(); - bannerTheme ??= const MaterialBannerThemeData(); + scrollbarTheme ??= const ScrollbarThemeData(); bottomAppBarTheme ??= const BottomAppBarTheme(); - bottomNavigationBarTheme ??= const BottomNavigationBarThemeData(); - bottomSheetTheme ??= const BottomSheetThemeData(); - buttonBarTheme ??= const ButtonBarThemeData(); cardTheme ??= const CardTheme(); - chipTheme ??= const ChipThemeData(); - checkboxTheme ??= const CheckboxThemeData(); - dataTableTheme ??= const DataTableThemeData(); + chipTheme ??= ChipThemeData.fromDefaults( + secondaryColor: isDark ? Colors.tealAccent[200]! : primaryColor, + brightness: colorScheme.brightness, + labelStyle: textTheme.bodyText1!, + ); dialogTheme ??= const DialogTheme(); - dividerTheme ??= const DividerThemeData(); - drawerTheme ??= const DrawerThemeData(); - elevatedButtonTheme ??= const ElevatedButtonThemeData(); floatingActionButtonTheme ??= const FloatingActionButtonThemeData(); - listTileTheme ??= const ListTileThemeData(); navigationBarTheme ??= const NavigationBarThemeData(); navigationRailTheme ??= const NavigationRailThemeData(); - outlinedButtonTheme ??= const OutlinedButtonThemeData(); - popupMenuTheme ??= const PopupMenuThemeData(); - progressIndicatorTheme ??= const ProgressIndicatorThemeData(); - radioTheme ??= const RadioThemeData(); - sliderTheme ??= const SliderThemeData(); + cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault(); snackBarTheme ??= const SnackBarThemeData(); - switchTheme ??= const SwitchThemeData(); - tabBarTheme ??= const TabBarTheme(); + bottomSheetTheme ??= const BottomSheetThemeData(); + popupMenuTheme ??= const PopupMenuThemeData(); + bannerTheme ??= const MaterialBannerThemeData(); + dividerTheme ??= const DividerThemeData(); + buttonBarTheme ??= const ButtonBarThemeData(); + bottomNavigationBarTheme ??= const BottomNavigationBarThemeData(); + timePickerTheme ??= const TimePickerThemeData(); textButtonTheme ??= const TextButtonThemeData(); + elevatedButtonTheme ??= const ElevatedButtonThemeData(); + outlinedButtonTheme ??= const OutlinedButtonThemeData(); textSelectionTheme ??= const TextSelectionThemeData(); - timePickerTheme ??= const TimePickerThemeData(); - toggleButtonsTheme ??= const ToggleButtonsThemeData(); - tooltipTheme ??= const TooltipThemeData(); + dataTableTheme ??= const DataTableThemeData(); + checkboxTheme ??= const CheckboxThemeData(); + radioTheme ??= const RadioThemeData(); + switchTheme ??= const SwitchThemeData(); + progressIndicatorTheme ??= const ProgressIndicatorThemeData(); + drawerTheme ??= const DrawerThemeData(); + listTileTheme ??= const ListTileThemeData(); - // DEPRECATED (newest deprecations at the bottom) - useTextSelectionTheme ??= true; - textSelectionColor ??= isDark ? accentColor : primarySwatch[200]!; - cursorColor = cursorColor ?? const Color.fromRGBO(66, 133, 244, 1.0); - textSelectionHandleColor ??= isDark ? Colors.tealAccent[400]! : primarySwatch[300]!; - accentTextTheme = defaultAccentTextTheme.merge(accentTextTheme); - accentIconTheme ??= accentIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black); - buttonColor ??= isDark ? primarySwatch[600]! : Colors.grey[300]!; fixTextFieldOutlineLabel ??= true; - primaryColorBrightness = _primaryColorBrightness; + useTextSelectionTheme ??= true; return ThemeData.raw( - // GENERAL CONFIGURATION - androidOverscrollIndicator: androidOverscrollIndicator, - applyElevationOverlayColor: applyElevationOverlayColor, - cupertinoOverrideTheme: cupertinoOverrideTheme, - inputDecorationTheme: inputDecorationTheme, - materialTapTargetSize: materialTapTargetSize, - pageTransitionsTheme: pageTransitionsTheme, - platform: platform, - scrollbarTheme: scrollbarTheme, - splashFactory: splashFactory, visualDensity: visualDensity, - useMaterial3: useMaterial3, - // COLOR - colorScheme: colorScheme, primaryColor: primaryColor, + primaryColorBrightness: primaryColorBrightness, primaryColorLight: primaryColorLight, primaryColorDark: primaryColorDark, - focusColor: focusColor, - hoverColor: hoverColor, - shadowColor: shadowColor, + accentColor: accentColor, + accentColorBrightness: accentColorBrightness, canvasColor: canvasColor, + shadowColor: shadowColor, scaffoldBackgroundColor: scaffoldBackgroundColor, bottomAppBarColor: bottomAppBarColor, cardColor: cardColor, dividerColor: dividerColor, + focusColor: focusColor, + hoverColor: hoverColor, highlightColor: highlightColor, splashColor: splashColor, + splashFactory: splashFactory, selectedRowColor: selectedRowColor, unselectedWidgetColor: unselectedWidgetColor, disabledColor: disabledColor, + buttonTheme: buttonTheme, + buttonColor: buttonColor, + toggleButtonsTheme: toggleButtonsTheme, + toggleableActiveColor: toggleableActiveColor, secondaryHeaderColor: secondaryHeaderColor, + textSelectionColor: textSelectionColor, + cursorColor: cursorColor, + textSelectionHandleColor: textSelectionHandleColor, backgroundColor: backgroundColor, dialogBackgroundColor: dialogBackgroundColor, indicatorColor: indicatorColor, hintColor: hintColor, errorColor: errorColor, - toggleableActiveColor: toggleableActiveColor, - // TYPOGRAPHY & ICONOGRAPHY - typography: typography, textTheme: textTheme, primaryTextTheme: primaryTextTheme, + accentTextTheme: accentTextTheme, + inputDecorationTheme: inputDecorationTheme, iconTheme: iconTheme, primaryIconTheme: primaryIconTheme, - // COMPONENT THEMES - appBarTheme: appBarTheme, - bannerTheme: bannerTheme, - bottomAppBarTheme: bottomAppBarTheme, - bottomNavigationBarTheme: bottomNavigationBarTheme, - bottomSheetTheme: bottomSheetTheme, - buttonBarTheme: buttonBarTheme, - buttonTheme: buttonTheme, + accentIconTheme: accentIconTheme, + sliderTheme: sliderTheme, + tabBarTheme: tabBarTheme, + tooltipTheme: tooltipTheme, cardTheme: cardTheme, - checkboxTheme: checkboxTheme, chipTheme: chipTheme, - dataTableTheme: dataTableTheme, + platform: platform, + materialTapTargetSize: materialTapTargetSize, + applyElevationOverlayColor: applyElevationOverlayColor, + pageTransitionsTheme: pageTransitionsTheme, + appBarTheme: appBarTheme, + scrollbarTheme: scrollbarTheme, + bottomAppBarTheme: bottomAppBarTheme, + colorScheme: colorScheme, dialogTheme: dialogTheme, - dividerTheme: dividerTheme, - drawerTheme: drawerTheme, - elevatedButtonTheme: elevatedButtonTheme, floatingActionButtonTheme: floatingActionButtonTheme, - listTileTheme: listTileTheme, navigationBarTheme: navigationBarTheme, navigationRailTheme: navigationRailTheme, - outlinedButtonTheme: outlinedButtonTheme, - popupMenuTheme: popupMenuTheme, - progressIndicatorTheme: progressIndicatorTheme, - radioTheme: radioTheme, - sliderTheme: sliderTheme, + typography: typography, + cupertinoOverrideTheme: cupertinoOverrideTheme, snackBarTheme: snackBarTheme, - switchTheme: switchTheme, - tabBarTheme: tabBarTheme, + bottomSheetTheme: bottomSheetTheme, + popupMenuTheme: popupMenuTheme, + bannerTheme: bannerTheme, + dividerTheme: dividerTheme, + buttonBarTheme: buttonBarTheme, + bottomNavigationBarTheme: bottomNavigationBarTheme, + timePickerTheme: timePickerTheme, textButtonTheme: textButtonTheme, + elevatedButtonTheme: elevatedButtonTheme, + outlinedButtonTheme: outlinedButtonTheme, textSelectionTheme: textSelectionTheme, - timePickerTheme: timePickerTheme, - toggleButtonsTheme: toggleButtonsTheme, - tooltipTheme: tooltipTheme, - // DEPRECATED (newest deprecations at the bottom) - useTextSelectionTheme: useTextSelectionTheme, - textSelectionColor: textSelectionColor, - cursorColor: cursorColor, - textSelectionHandleColor: textSelectionHandleColor, - accentColor: accentColor, - accentColorBrightness: accentColorBrightness, - accentTextTheme: accentTextTheme, - accentIconTheme: accentIconTheme, - buttonColor: buttonColor, + dataTableTheme: dataTableTheme, + checkboxTheme: checkboxTheme, + radioTheme: radioTheme, + switchTheme: switchTheme, + progressIndicatorTheme: progressIndicatorTheme, + drawerTheme: drawerTheme, + listTileTheme: listTileTheme, fixTextFieldOutlineLabel: fixTextFieldOutlineLabel, - primaryColorBrightness: primaryColorBrightness, + useTextSelectionTheme: useTextSelectionTheme, + androidOverscrollIndicator: androidOverscrollIndicator, ); } @@ -656,91 +589,47 @@ class ThemeData with Diagnosticable { // Warning: make sure these properties are in the exact same order as in // operator == and in the hashValues method and in the order of fields // in this class, and in the lerp() method. - // GENERAL CONFIGURATION - required this.androidOverscrollIndicator, - required this.applyElevationOverlayColor, - required this.cupertinoOverrideTheme, - required this.inputDecorationTheme, - required this.materialTapTargetSize, - required this.pageTransitionsTheme, - required this.platform, - required this.scrollbarTheme, - required this.splashFactory, required this.visualDensity, - required this.useMaterial3, - // COLOR - // [colorScheme] is the preferred way to configure colors. The other color - // properties will gradually be phased out, see - // https://github.com/flutter/flutter/issues/91772. - required this.colorScheme, required this.primaryColor, + required this.primaryColorBrightness, required this.primaryColorLight, required this.primaryColorDark, - required this.focusColor, - required this.hoverColor, - required this.shadowColor, required this.canvasColor, + required this.shadowColor, + @Deprecated( + 'Use colorScheme.secondary instead. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + required this.accentColor, + @Deprecated( + 'No longer used by the framework, please remove any reference to it. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + required this.accentColorBrightness, required this.scaffoldBackgroundColor, required this.bottomAppBarColor, required this.cardColor, required this.dividerColor, + required this.focusColor, + required this.hoverColor, required this.highlightColor, required this.splashColor, + required this.splashFactory, required this.selectedRowColor, required this.unselectedWidgetColor, required this.disabledColor, - required this.secondaryHeaderColor, - required this.backgroundColor, - required this.dialogBackgroundColor, - required this.indicatorColor, - required this.hintColor, - required this.errorColor, - required this.toggleableActiveColor, - // TYPOGRAPHY & ICONOGRAPHY - required this.typography, - required this.textTheme, - required this.primaryTextTheme, - required this.iconTheme, - required this.primaryIconTheme, - // COMPONENT THEMES - required this.appBarTheme, - required this.bannerTheme, - required this.bottomAppBarTheme, - required this.bottomNavigationBarTheme, - required this.bottomSheetTheme, - required this.buttonBarTheme, required this.buttonTheme, - required this.cardTheme, - required this.checkboxTheme, - required this.chipTheme, - required this.dataTableTheme, - required this.dialogTheme, - required this.dividerTheme, - required this.drawerTheme, - required this.elevatedButtonTheme, - required this.floatingActionButtonTheme, - required this.listTileTheme, - required this.navigationBarTheme, - required this.navigationRailTheme, - required this.outlinedButtonTheme, - required this.popupMenuTheme, - required this.progressIndicatorTheme, - required this.radioTheme, - required this.sliderTheme, - required this.snackBarTheme, - required this.switchTheme, - required this.tabBarTheme, - required this.textButtonTheme, - required this.textSelectionTheme, - required this.timePickerTheme, - required this.toggleButtonsTheme, - required this.tooltipTheme, - // DEPRECATED (newest deprecations at the bottom) @Deprecated( 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v1.23.0-4.0.pre.', + 'This feature was deprecated after v2.3.0-0.2.pre.', ) - required this.useTextSelectionTheme, + required this.buttonColor, + required this.toggleButtonsTheme, + required this.secondaryHeaderColor, @Deprecated( 'Use TextSelectionThemeData.selectionColor instead. ' 'This feature was deprecated after v1.26.0-18.0.pre.', @@ -756,20 +645,14 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v1.26.0-18.0.pre.', ) required this.textSelectionHandleColor, - @Deprecated( - 'Use colorScheme.secondary instead. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - required this.accentColor, - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - required this.accentColorBrightness, + required this.backgroundColor, + required this.dialogBackgroundColor, + required this.indicatorColor, + required this.hintColor, + required this.errorColor, + required this.toggleableActiveColor, + required this.textTheme, + required this.primaryTextTheme, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' 'For more information, consult the migration guide at ' @@ -777,6 +660,9 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v2.3.0-0.1.pre.', ) required this.accentTextTheme, + required this.inputDecorationTheme, + required this.iconTheme, + required this.primaryIconTheme, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' 'For more information, consult the migration guide at ' @@ -784,107 +670,133 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v2.3.0-0.1.pre.', ) required this.accentIconTheme, - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v2.3.0-0.2.pre.', - ) - required this.buttonColor, - @Deprecated( - 'This "fix" is now enabled by default. ' - 'This feature was deprecated after v2.5.0-1.0.pre.', - ) - required this.fixTextFieldOutlineLabel, - @Deprecated( + required this.sliderTheme, + required this.tabBarTheme, + required this.tooltipTheme, + required this.cardTheme, + required this.chipTheme, + required this.platform, + required this.materialTapTargetSize, + required this.applyElevationOverlayColor, + required this.pageTransitionsTheme, + required this.appBarTheme, + required this.scrollbarTheme, + required this.bottomAppBarTheme, + required this.colorScheme, + required this.dialogTheme, + required this.floatingActionButtonTheme, + required this.navigationBarTheme, + required this.navigationRailTheme, + required this.typography, + required this.cupertinoOverrideTheme, + required this.snackBarTheme, + required this.bottomSheetTheme, + required this.popupMenuTheme, + required this.bannerTheme, + required this.dividerTheme, + required this.buttonBarTheme, + required this.bottomNavigationBarTheme, + required this.timePickerTheme, + required this.textButtonTheme, + required this.elevatedButtonTheme, + required this.outlinedButtonTheme, + required this.textSelectionTheme, + required this.dataTableTheme, + required this.checkboxTheme, + required this.radioTheme, + required this.switchTheme, + required this.progressIndicatorTheme, + required this.drawerTheme, + required this.listTileTheme, + @Deprecated( + 'This "fix" is now enabled by default. ' + 'This feature was deprecated after v2.5.0-1.0.pre.', + ) + required this.fixTextFieldOutlineLabel, + @Deprecated( 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v2.6.0-11.0.pre.', + 'This feature was deprecated after v1.23.0-4.0.pre.', ) - required this.primaryColorBrightness, - }) : // GENERAL CONFIGURATION - assert(applyElevationOverlayColor != null), - assert(inputDecorationTheme != null), - assert(materialTapTargetSize != null), - assert(pageTransitionsTheme != null), - assert(platform != null), - assert(scrollbarTheme != null), - assert(splashFactory != null), - assert(visualDensity != null), - assert(useMaterial3 != null), - // COLOR - assert(colorScheme != null), + required this.useTextSelectionTheme, + required this.androidOverscrollIndicator, + }) : assert(visualDensity != null), assert(primaryColor != null), + assert(primaryColorBrightness != null), assert(primaryColorLight != null), assert(primaryColorDark != null), - assert(focusColor != null), - assert(hoverColor != null), - assert(shadowColor != null), + assert(accentColor != null), + assert(accentColorBrightness != null), assert(canvasColor != null), + assert(shadowColor != null), assert(scaffoldBackgroundColor != null), assert(bottomAppBarColor != null), assert(cardColor != null), assert(dividerColor != null), + assert(focusColor != null), + assert(hoverColor != null), assert(highlightColor != null), assert(splashColor != null), + assert(splashFactory != null), assert(selectedRowColor != null), assert(unselectedWidgetColor != null), assert(disabledColor != null), + assert(toggleableActiveColor != null), + assert(buttonTheme != null), + assert(toggleButtonsTheme != null), assert(secondaryHeaderColor != null), + assert(textSelectionColor != null), + assert(cursorColor != null), + assert(textSelectionHandleColor != null), assert(backgroundColor != null), assert(dialogBackgroundColor != null), assert(indicatorColor != null), assert(hintColor != null), assert(errorColor != null), - assert(toggleableActiveColor != null), - // TYPOGRAPHY & ICONOGRAPHY - assert(typography != null), assert(textTheme != null), assert(primaryTextTheme != null), + assert(accentTextTheme != null), + assert(inputDecorationTheme != null), assert(iconTheme != null), assert(primaryIconTheme != null), - // COMPONENT THEMES - assert(appBarTheme != null), - assert(bannerTheme != null), - assert(bottomAppBarTheme != null), - assert(bottomNavigationBarTheme != null), - assert(bottomSheetTheme != null), - assert(buttonBarTheme != null), - assert(buttonTheme != null), + assert(accentIconTheme != null), + assert(sliderTheme != null), + assert(tabBarTheme != null), + assert(tooltipTheme != null), assert(cardTheme != null), - assert(checkboxTheme != null), assert(chipTheme != null), - assert(dataTableTheme != null), + assert(platform != null), + assert(materialTapTargetSize != null), + assert(pageTransitionsTheme != null), + assert(appBarTheme != null), + assert(scrollbarTheme != null), + assert(bottomAppBarTheme != null), + assert(colorScheme != null), assert(dialogTheme != null), - assert(dividerTheme != null), - assert(drawerTheme != null), - assert(elevatedButtonTheme != null), assert(floatingActionButtonTheme != null), - assert(listTileTheme != null), assert(navigationBarTheme != null), assert(navigationRailTheme != null), - assert(outlinedButtonTheme != null), - assert(popupMenuTheme != null), - assert(progressIndicatorTheme != null), - assert(radioTheme != null), - assert(sliderTheme != null), + assert(typography != null), assert(snackBarTheme != null), - assert(switchTheme != null), - assert(tabBarTheme != null), + assert(bottomSheetTheme != null), + assert(popupMenuTheme != null), + assert(bannerTheme != null), + assert(dividerTheme != null), + assert(buttonBarTheme != null), + assert(bottomNavigationBarTheme != null), + assert(timePickerTheme != null), assert(textButtonTheme != null), + assert(elevatedButtonTheme != null), + assert(outlinedButtonTheme != null), assert(textSelectionTheme != null), - assert(timePickerTheme != null), - assert(toggleButtonsTheme != null), - assert(tooltipTheme != null), - // DEPRECATED (newest deprecations at the bottom) - assert(useTextSelectionTheme != null), - assert(textSelectionColor != null), - assert(cursorColor != null), - assert(textSelectionHandleColor != null), - assert(accentColor != null), - assert(accentColorBrightness != null), - assert(accentTextTheme != null), - assert(accentIconTheme != null), - assert(buttonColor != null), + assert(dataTableTheme != null), + assert(checkboxTheme != null), + assert(radioTheme != null), + assert(switchTheme != null), + assert(progressIndicatorTheme != null), + assert(drawerTheme != null), + assert(listTileTheme != null), assert(fixTextFieldOutlineLabel != null), - assert(primaryColorBrightness != null); + assert(useTextSelectionTheme != null); /// Create a [ThemeData] based on the colors in the given [colorScheme] and /// text styles of the optional [textTheme]. @@ -918,6 +830,8 @@ class ThemeData with Diagnosticable { required ColorScheme colorScheme, TextTheme? textTheme, }) { + assert(colorScheme != null); + final bool isDark = colorScheme.brightness == Brightness.dark; // For surfaces that use primary color in light themes and surface color in dark @@ -925,7 +839,6 @@ class ThemeData with Diagnosticable { final Color onPrimarySurfaceColor = isDark ? colorScheme.onSurface : colorScheme.onPrimary; return ThemeData( - colorScheme: colorScheme, brightness: colorScheme.brightness, primaryColor: primarySurfaceColor, primaryColorBrightness: ThemeData.estimateBrightnessForColor(primarySurfaceColor), @@ -938,10 +851,11 @@ class ThemeData with Diagnosticable { dividerColor: colorScheme.onSurface.withOpacity(0.12), backgroundColor: colorScheme.background, dialogBackgroundColor: colorScheme.background, - indicatorColor: onPrimarySurfaceColor, errorColor: colorScheme.error, textTheme: textTheme, + indicatorColor: onPrimarySurfaceColor, applyElevationOverlayColor: isDark, + colorScheme: colorScheme, ); } @@ -968,6 +882,10 @@ class ThemeData with Diagnosticable { /// text geometry. factory ThemeData.fallback() => ThemeData.light(); + // Warning: make sure these properties are in the exact same order as in + // hashValues() and in the raw constructor and in the order of fields in + // the class and in the lerp() method. + /// The overall theme brightness. /// /// The default [TextStyle] color for the [textTheme] is black if the @@ -975,220 +893,59 @@ class ThemeData with Diagnosticable { /// theme is constructed with [Brightness.dark]. Brightness get brightness => colorScheme.brightness; - // Warning: make sure these properties are in the exact same order as in - // hashValues() and in the raw constructor and in the order of fields in - // the class and in the lerp() method. - - // GENERAL CONFIGURATION - - /// Specifies which overscroll indicator to use on [TargetPlatform.android]. - /// - /// When null, the default value of - /// [MaterialScrollBehavior.androidOverscrollIndicator] is - /// [AndroidOverscrollIndicator.glow]. - /// - /// See also: - /// - /// * [StretchingOverscrollIndicator], a material design edge effect - /// that transforms the contents of a scrollable when overscrolled. - /// * [GlowingOverscrollIndicator], an edge effect that paints a glow - /// over the contents of a scrollable when overscrolled. - final AndroidOverscrollIndicator? androidOverscrollIndicator; - - /// Apply a semi-transparent overlay color on Material surfaces to indicate - /// elevation for dark themes. - /// - /// Material drop shadows can be difficult to see in a dark theme, so the - /// elevation of a surface should be portrayed with an "overlay" in addition - /// to the shadow. As the elevation of the component increases, the - /// overlay increases in opacity. [applyElevationOverlayColor] turns the - /// application of this overlay on or off for dark themes. + /// The density value for specifying the compactness of various UI components. /// - /// If true and [brightness] is [Brightness.dark], a - /// semi-transparent version of [ColorScheme.onSurface] will be - /// applied on top of [Material] widgets that have a [ColorScheme.surface] - /// color. The level of transparency is based on [Material.elevation] as - /// per the Material Dark theme specification. + /// {@template flutter.material.themedata.visualDensity} + /// Density, in the context of a UI, is the vertical and horizontal + /// "compactness" of the elements in the UI. It is unitless, since it means + /// different things to different UI elements. For buttons, it affects the + /// spacing around the centered label of the button. For lists, it affects the + /// distance between baselines of entries in the list. /// - /// If false the surface color will be used unmodified. + /// Typically, density values are integral, but any value in range may be + /// used. The range includes values from [VisualDensity.minimumDensity] (which + /// is -4), to [VisualDensity.maximumDensity] (which is 4), inclusive, where + /// negative values indicate a denser, more compact, UI, and positive values + /// indicate a less dense, more expanded, UI. If a component doesn't support + /// the value given, it will clamp to the nearest supported value. /// - /// Defaults to false in order to maintain backwards compatibility with - /// apps that were built before the Material Dark theme specification - /// was published. New apps should set this to true for any themes - /// where [brightness] is [Brightness.dark]. + /// The default for visual densities is zero for both vertical and horizontal + /// densities, which corresponds to the default visual density of components + /// in the Material Design specification. /// - /// See also: + /// As a rule of thumb, a change of 1 or -1 in density corresponds to 4 + /// logical pixels. However, this is not a strict relationship since + /// components interpret the density values appropriately for their needs. /// - /// * [Material.elevation], which effects the level of transparency of the - /// overlay color. - /// * [ElevationOverlay.applyOverlay], which is used by [Material] to apply - /// the overlay color to its surface color. - /// * , which specifies how - /// the overlay should be applied. - final bool applyElevationOverlayColor; + /// A larger value translates to a spacing increase (less dense), and a + /// smaller value translates to a spacing decrease (more dense). + /// {@endtemplate} + final VisualDensity visualDensity; - /// Components of the [CupertinoThemeData] to override from the Material - /// [ThemeData] adaptation. - /// - /// By default, [cupertinoOverrideTheme] is null and Cupertino widgets - /// descendant to the Material [Theme] will adhere to a [CupertinoTheme] - /// derived from the Material [ThemeData]. e.g. [ThemeData]'s [ColorScheme] - /// will also inform the [CupertinoThemeData]'s `primaryColor` etc. + /// The background color for major parts of the app (toolbars, tab bars, etc) /// - /// This cascading effect for individual attributes of the [CupertinoThemeData] - /// can be overridden using attributes of this [cupertinoOverrideTheme]. - final NoDefaultCupertinoThemeData? cupertinoOverrideTheme; + /// The theme's [colorScheme] property contains [ColorScheme.primary], as + /// well as a color that contrasts well with the primary color called + /// [ColorScheme.onPrimary]. It might be simpler to just configure an app's + /// visuals in terms of the theme's [colorScheme]. + final Color primaryColor; - /// The default [InputDecoration] values for [InputDecorator], [TextField], - /// and [TextFormField] are based on this theme. - /// - /// See [InputDecoration.applyDefaults]. - final InputDecorationTheme inputDecorationTheme; + /// The brightness of the [primaryColor]. Used to determine the color of text and + /// icons placed on top of the primary color (e.g. toolbar text). + final Brightness primaryColorBrightness; - /// Configures the hit test size of certain Material widgets. - /// - /// Defaults to a [platform]-appropriate size: [MaterialTapTargetSize.padded] - /// on mobile platforms, [MaterialTapTargetSize.shrinkWrap] on desktop - /// platforms. - final MaterialTapTargetSize materialTapTargetSize; + /// A lighter version of the [primaryColor]. + final Color primaryColorLight; - /// Default [MaterialPageRoute] transitions per [TargetPlatform]. - /// - /// [MaterialPageRoute.buildTransitions] delegates to a [platform] specific - /// [PageTransitionsBuilder]. If a matching builder is not found, a builder - /// whose platform is null is used. - final PageTransitionsTheme pageTransitionsTheme; + /// A darker version of the [primaryColor]. + final Color primaryColorDark; - /// The platform the material widgets should adapt to target. + /// The default color of [MaterialType.canvas] [Material]. + final Color canvasColor; + + /// The color that the [Material] widget uses to draw elevation shadows. /// - /// Defaults to the current platform, as exposed by [defaultTargetPlatform]. - /// This should be used in order to style UI elements according to platform - /// conventions. - /// - /// Widgets from the material library should use this getter (via [Theme.of]) - /// to determine the current platform for the purpose of emulating the - /// platform behavior (e.g. scrolling or haptic effects). Widgets and render - /// objects at lower layers that try to emulate the underlying platform - /// platform can depend on [defaultTargetPlatform] directly, or may require - /// that the target platform be provided as an argument. The - /// [dart:io.Platform] object should only be used directly when it's critical - /// to actually know the current platform, without any overrides possible (for - /// example, when a system API is about to be called). - /// - /// In a test environment, the platform returned is [TargetPlatform.android] - /// regardless of the host platform. (Android was chosen because the tests - /// were originally written assuming Android-like behavior, and we added - /// platform adaptations for other platforms later). Tests can check behavior - /// for other platforms by setting the [platform] of the [Theme] explicitly to - /// another [TargetPlatform] value, or by setting - /// [debugDefaultTargetPlatformOverride]. - /// - /// Determines the defaults for [typography] and [materialTapTargetSize]. - final TargetPlatform platform; - - /// A theme for customizing the colors, thickness, and shape of [Scrollbar]s. - final ScrollbarThemeData scrollbarTheme; - - /// Defines the appearance of ink splashes produces by [InkWell] - /// and [InkResponse]. - /// - /// See also: - /// - /// * [InkSplash.splashFactory], which defines the default splash. - /// * [InkRipple.splashFactory], which defines a splash that spreads out - /// more aggressively than the default. - final InteractiveInkFeatureFactory splashFactory; - - /// The density value for specifying the compactness of various UI components. - /// - /// {@template flutter.material.themedata.visualDensity} - /// Density, in the context of a UI, is the vertical and horizontal - /// "compactness" of the elements in the UI. It is unitless, since it means - /// different things to different UI elements. For buttons, it affects the - /// spacing around the centered label of the button. For lists, it affects the - /// distance between baselines of entries in the list. - /// - /// Typically, density values are integral, but any value in range may be - /// used. The range includes values from [VisualDensity.minimumDensity] (which - /// is -4), to [VisualDensity.maximumDensity] (which is 4), inclusive, where - /// negative values indicate a denser, more compact, UI, and positive values - /// indicate a less dense, more expanded, UI. If a component doesn't support - /// the value given, it will clamp to the nearest supported value. - /// - /// The default for visual densities is zero for both vertical and horizontal - /// densities, which corresponds to the default visual density of components - /// in the Material Design specification. - /// - /// As a rule of thumb, a change of 1 or -1 in density corresponds to 4 - /// logical pixels. However, this is not a strict relationship since - /// components interpret the density values appropriately for their needs. - /// - /// A larger value translates to a spacing increase (less dense), and a - /// smaller value translates to a spacing decrease (more dense). - /// {@endtemplate} - final VisualDensity visualDensity; - - /// A temporary flag used to opt-in to new Material 3 features. - /// - /// If true, then components that have been migrated to Material 3 will - /// start using new colors, typography and other features of Material 3. - /// If false, they will use the Material 2 look and feel. - /// - /// During the migration to Material 3, turning this on may yield - /// inconsistent look and feel in your app. Some components will be migrated - /// before others and typography changes will be coming in stages. - /// - /// [useMaterial3] defaults to false. After all the migrated components - /// have landed on stable, we will change this to be true by default. After - /// that change has landed on stable, we will deprecate this flag and remove - /// all uses of it. Everything will use the Material 3 look and feel at - /// that point. - /// - /// Components that have been migrated to Material 3 are: - /// - /// * [FloatingActionButton] - /// - /// See also: - /// - /// * [Material Design 3](https://m3.material.io/). - final bool useMaterial3; - - // COLOR - - /// A set of twelve colors that can be used to configure the - /// color properties of most components. - /// - /// This property was added much later than the theme's set of highly - /// specific colors, like [cardColor], [buttonColor], [canvasColor] etc. - /// New components can be defined exclusively in terms of [colorScheme]. - /// Existing components will gradually migrate to it, to the extent - /// that is possible without significant backwards compatibility breaks. - final ColorScheme colorScheme; - - /// The background color for major parts of the app (toolbars, tab bars, etc) - /// - /// The theme's [colorScheme] property contains [ColorScheme.primary], as - /// well as a color that contrasts well with the primary color called - /// [ColorScheme.onPrimary]. It might be simpler to just configure an app's - /// visuals in terms of the theme's [colorScheme]. - final Color primaryColor; - - /// A lighter version of the [primaryColor]. - final Color primaryColorLight; - - /// A darker version of the [primaryColor]. - final Color primaryColorDark; - - /// The focus color used indicate that a component has the input focus. - final Color focusColor; - - /// The hover color used to indicate when a pointer is hovering over a - /// component. - final Color hoverColor; - - /// The color that the [Material] widget uses to draw elevation shadows. - /// - /// Defaults to fully opaque black. + /// Defaults to fully opaque black. /// /// Shadows can be difficult to see in a dark theme, so the elevation of a /// surface should be rendered with an "overlay" in addition to the shadow. @@ -1197,8 +954,40 @@ class ThemeData with Diagnosticable { /// overlay on or off for dark themes. final Color shadowColor; - /// The default color of [MaterialType.canvas] [Material]. - final Color canvasColor; + /// Obsolete property that was originally used as the foreground + /// color for widgets (knobs, text, overscroll edge effect, etc). + /// + /// The material library no longer uses this property. In most cases + /// the theme's [colorScheme] [ColorScheme.secondary] property is now + /// used instead. + /// + /// Apps should migrate uses of this property to the theme's [colorScheme] + /// [ColorScheme.secondary] color. In cases where a color is needed that + /// that contrasts well with the secondary color [ColorScheme.onSecondary] + /// can be used. + @Deprecated( + 'Use colorScheme.secondary instead. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + final Color accentColor; + + /// Obsolete property that was originally used to determine the color + /// of text and icons placed on top of the accent color (e.g. the + /// icons on a floating action button). + /// + /// The material library no longer uses this property. The + /// [floatingActionButtonTheme] can be used to configure + /// the appearance of [FloatingActionButton]s. The brightness + /// of any color can be found with [ThemeData.estimateBrightnessForColor]. + @Deprecated( + 'No longer used by the framework, please remove any reference to it. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + final Brightness accentColorBrightness; /// The default color of the [Material] that underlies the [Scaffold]. The /// background color for a typical material app or a page within the app. @@ -1219,15 +1008,29 @@ class ThemeData with Diagnosticable { /// [Divider.createBorderSide]. final Color dividerColor; + /// The focus color used indicate that a component has the input focus. + final Color focusColor; + + /// The hover color used to indicate when a pointer is hovering over a + /// component. + final Color hoverColor; + /// The highlight color used during ink splash animations or to /// indicate an item in a menu is selected. final Color highlightColor; - /// The color of ink splashes. + /// The color of ink splashes. See [InkWell]. + final Color splashColor; + + /// Defines the appearance of ink splashes produces by [InkWell] + /// and [InkResponse]. /// /// See also: - /// * [splashFactory], which defines the appearance of the splash. - final Color splashColor; + /// + /// * [InkSplash.splashFactory], which defines the default splash. + /// * [InkRipple.splashFactory], which defines a splash that spreads out + /// more aggressively than the default. + final InteractiveInkFeatureFactory splashFactory; /// The color used to highlight selected rows. final Color selectedRowColor; @@ -1241,12 +1044,47 @@ class ThemeData with Diagnosticable { /// checked or unchecked). final Color disabledColor; + /// Defines the default configuration of button widgets, like [RaisedButton] + /// and [FlatButton]. + final ButtonThemeData buttonTheme; + + /// Defines the default configuration of [ToggleButtons] widgets. + final ToggleButtonsThemeData toggleButtonsTheme; + + /// The default fill color of the [Material] used in [RaisedButton]s. + @Deprecated( + 'No longer used by the framework, please remove any reference to it. ' + 'This feature was deprecated after v2.3.0-0.2.pre.', + ) + final Color buttonColor; + /// The color of the header of a [PaginatedDataTable] when there are selected rows. // According to the spec for data tables: // https://material.io/archive/guidelines/components/data-tables.html#data-tables-tables-within-cards // ...this should be the "50-value of secondary app color". final Color secondaryHeaderColor; + /// The color of text selections in text fields, such as [TextField]. + @Deprecated( + 'Use TextSelectionThemeData.selectionColor instead. ' + 'This feature was deprecated after v1.26.0-18.0.pre.', + ) + final Color textSelectionColor; + + /// The color of cursors in Material-style text fields, such as [TextField]. + @Deprecated( + 'Use TextSelectionThemeData.cursorColor instead. ' + 'This feature was deprecated after v1.26.0-18.0.pre.', + ) + final Color cursorColor; + + /// The color of the handles used to adjust what part of the text is currently selected. + @Deprecated( + 'Use TextSelectionThemeData.selectionHandleColor instead. ' + 'This feature was deprecated after v1.26.0-18.0.pre.', + ) + final Color textSelectionHandleColor; + /// A color that contrasts with the [primaryColor], e.g. used as the /// remaining part of a progress bar. final Color backgroundColor; @@ -1268,89 +1106,181 @@ class ThemeData with Diagnosticable { /// [Switch], [Radio], and [Checkbox]. final Color toggleableActiveColor; - // TYPOGRAPHY & ICONOGRAPHY - - /// The color and geometry [TextTheme] values used to configure [textTheme]. - /// - /// Defaults to a [platform]-appropriate typography. - final Typography typography; - /// Text with a color that contrasts with the card and canvas colors. final TextTheme textTheme; /// A text theme that contrasts with the primary color. final TextTheme primaryTextTheme; + /// Obsolete property that was originally used when a [TextTheme] + /// that contrasted well with the [accentColor] was needed. + /// + /// The material library no longer uses this property and most uses + /// of [accentColor] have been replaced with + /// the theme's [colorScheme] [ColorScheme.secondary]. + /// You can configure the color of a [textTheme] [TextStyle] so that it + /// contrasts well with the [ColorScheme.secondary] like this: + /// + /// ```dart + /// final ThemeData theme = Theme.of(context); + /// theme.textTheme.headline1.copyWith( + /// color: theme.colorScheme.onSecondary, + /// ) + /// ``` + @Deprecated( + 'No longer used by the framework, please remove any reference to it. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + final TextTheme accentTextTheme; + + /// The default [InputDecoration] values for [InputDecorator], [TextField], + /// and [TextFormField] are based on this theme. + /// + /// See [InputDecoration.applyDefaults]. + final InputDecorationTheme inputDecorationTheme; + /// An icon theme that contrasts with the card and canvas colors. final IconThemeData iconTheme; /// An icon theme that contrasts with the primary color. final IconThemeData primaryIconTheme; - // COMPONENT THEMES + /// Obsolete property that was originally used when an [IconTheme] + /// that contrasted well with the [accentColor] was needed. + /// + /// The material library no longer uses this property and most uses + /// of [accentColor] have been replaced with + /// the theme's [colorScheme] [ColorScheme.secondary]. + @Deprecated( + 'No longer used by the framework, please remove any reference to it. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + final IconThemeData accentIconTheme; - /// A theme for customizing the color, elevation, brightness, iconTheme and - /// textTheme of [AppBar]s. - final AppBarTheme appBarTheme; + /// The colors and shapes used to render [Slider]. + /// + /// This is the value returned from [SliderTheme.of]. + final SliderThemeData sliderTheme; - /// A theme for customizing the color and text style of a [MaterialBanner]. - final MaterialBannerThemeData bannerTheme; + /// A theme for customizing the size, shape, and color of the tab bar indicator. + final TabBarTheme tabBarTheme; - /// A theme for customizing the shape, elevation, and color of a [BottomAppBar]. - final BottomAppBarTheme bottomAppBarTheme; - - /// A theme for customizing the appearance and layout of [BottomNavigationBar] - /// widgets. - final BottomNavigationBarThemeData bottomNavigationBarTheme; - - /// A theme for customizing the color, elevation, and shape of a bottom sheet. - final BottomSheetThemeData bottomSheetTheme; - - /// A theme for customizing the appearance and layout of [ButtonBar] widgets. - final ButtonBarThemeData buttonBarTheme; - - /// Defines the default configuration of button widgets, like [RaisedButton] - /// and [FlatButton]. - final ButtonThemeData buttonTheme; + /// A theme for customizing the visual properties of [Tooltip]s. + /// + /// This is the value returned from [TooltipTheme.of]. + final TooltipThemeData tooltipTheme; /// The colors and styles used to render [Card]. /// /// This is the value returned from [CardTheme.of]. final CardTheme cardTheme; - /// A theme for customizing the appearance and layout of [Checkbox] widgets. - final CheckboxThemeData checkboxTheme; - /// The colors and styles used to render [Chip]s. /// /// This is the value returned from [ChipTheme.of]. final ChipThemeData chipTheme; - /// A theme for customizing the appearance and layout of [DataTable] - /// widgets. - final DataTableThemeData dataTableTheme; + /// The platform the material widgets should adapt to target. + /// + /// Defaults to the current platform, as exposed by [defaultTargetPlatform]. + /// This should be used in order to style UI elements according to platform + /// conventions. + /// + /// Widgets from the material library should use this getter (via [Theme.of]) + /// to determine the current platform for the purpose of emulating the + /// platform behavior (e.g. scrolling or haptic effects). Widgets and render + /// objects at lower layers that try to emulate the underlying platform + /// platform can depend on [defaultTargetPlatform] directly, or may require + /// that the target platform be provided as an argument. The + /// [dart:io.Platform] object should only be used directly when it's critical + /// to actually know the current platform, without any overrides possible (for + /// example, when a system API is about to be called). + /// + /// In a test environment, the platform returned is [TargetPlatform.android] + /// regardless of the host platform. (Android was chosen because the tests + /// were originally written assuming Android-like behavior, and we added + /// platform adaptations for other platforms later). Tests can check behavior + /// for other platforms by setting the [platform] of the [Theme] explicitly to + /// another [TargetPlatform] value, or by setting + /// [debugDefaultTargetPlatformOverride]. + final TargetPlatform platform; - /// A theme for customizing the shape of a dialog. - final DialogTheme dialogTheme; + /// Configures the hit test size of certain Material widgets. + final MaterialTapTargetSize materialTapTargetSize; - /// A theme for customizing the color, thickness, and indents of [Divider]s, - /// [VerticalDivider]s, etc. - final DividerThemeData dividerTheme; + /// Apply a semi-transparent overlay color on Material surfaces to indicate + /// elevation for dark themes. + /// + /// Material drop shadows can be difficult to see in a dark theme, so the + /// elevation of a surface should be portrayed with an "overlay" in addition + /// to the shadow. As the elevation of the component increases, the + /// overlay increases in opacity. [applyElevationOverlayColor] turns the + /// application of this overlay on or off for dark themes. + /// + /// If true and [brightness] is [Brightness.dark], a + /// semi-transparent version of [ColorScheme.onSurface] will be + /// applied on top of [Material] widgets that have a [ColorScheme.surface] + /// color. The level of transparency is based on [Material.elevation] as + /// per the Material Dark theme specification. + /// + /// If false the surface color will be used unmodified. + /// + /// Defaults to false in order to maintain backwards compatibility with + /// apps that were built before the Material Dark theme specification + /// was published. New apps should set this to true for any themes + /// where [brightness] is [Brightness.dark]. + /// + /// See also: + /// + /// * [Material.elevation], which effects the level of transparency of the + /// overlay color. + /// * [ElevationOverlay.applyOverlay], which is used by [Material] to apply + /// the overlay color to its surface color. + /// * , which specifies how + /// the overlay should be applied. + final bool applyElevationOverlayColor; - /// A theme for customizing the appearance and layout of [Drawer] widgets. - final DrawerThemeData drawerTheme; + /// Default [MaterialPageRoute] transitions per [TargetPlatform]. + /// + /// [MaterialPageRoute.buildTransitions] delegates to a [platform] specific + /// [PageTransitionsBuilder]. If a matching builder is not found, a builder + /// whose platform is null is used. + final PageTransitionsTheme pageTransitionsTheme; - /// A theme for customizing the appearance and internal layout of - /// [ElevatedButton]s. - final ElevatedButtonThemeData elevatedButtonTheme; + /// A theme for customizing the color, elevation, brightness, iconTheme and + /// textTheme of [AppBar]s. + final AppBarTheme appBarTheme; + + /// A theme for customizing the colors, thickness, and shape of [Scrollbar]s. + final ScrollbarThemeData scrollbarTheme; + + /// A theme for customizing the shape, elevation, and color of a [BottomAppBar]. + final BottomAppBarTheme bottomAppBarTheme; + + /// A set of thirteen colors that can be used to configure the + /// color properties of most components. + /// + /// This property was added much later than the theme's set of highly + /// specific colors, like [cardColor], [buttonColor], [canvasColor] etc. + /// New components can be defined exclusively in terms of [colorScheme]. + /// Existing components will gradually migrate to it, to the extent + /// that is possible without significant backwards compatibility breaks. + final ColorScheme colorScheme; + + /// A theme for customizing colors, shape, elevation, and behavior of a [SnackBar]. + final SnackBarThemeData snackBarTheme; + + /// A theme for customizing the shape of a dialog. + final DialogTheme dialogTheme; /// A theme for customizing the shape, elevation, and color of a /// [FloatingActionButton]. final FloatingActionButtonThemeData floatingActionButtonTheme; - /// A theme for customizing the appearance of [ListTile] widgets. - final ListTileThemeData listTileTheme; - /// A theme for customizing the background color, text style, and icon themes /// of a [NavigationBar]. final NavigationBarThemeData navigationBarTheme; @@ -1359,163 +1289,81 @@ class ThemeData with Diagnosticable { /// icon themes of a [NavigationRail]. final NavigationRailThemeData navigationRailTheme; - /// A theme for customizing the appearance and internal layout of - /// [OutlinedButton]s. - final OutlinedButtonThemeData outlinedButtonTheme; + /// The color and geometry [TextTheme] values used to configure [textTheme]. + final Typography typography; + + /// Components of the [CupertinoThemeData] to override from the Material + /// [ThemeData] adaptation. + /// + /// By default, [cupertinoOverrideTheme] is null and Cupertino widgets + /// descendant to the Material [Theme] will adhere to a [CupertinoTheme] + /// derived from the Material [ThemeData]. e.g. [ThemeData]'s [ColorScheme] + /// will also inform the [CupertinoThemeData]'s `primaryColor` etc. + /// + /// This cascading effect for individual attributes of the [CupertinoThemeData] + /// can be overridden using attributes of this [cupertinoOverrideTheme]. + final NoDefaultCupertinoThemeData? cupertinoOverrideTheme; + + /// A theme for customizing the color, elevation, and shape of a bottom sheet. + final BottomSheetThemeData bottomSheetTheme; /// A theme for customizing the color, shape, elevation, and text style of /// popup menus. final PopupMenuThemeData popupMenuTheme; - /// A theme for customizing the appearance and layout of [ProgressIndicator] widgets. - final ProgressIndicatorThemeData progressIndicatorTheme; - - /// A theme for customizing the appearance and layout of [Radio] widgets. - final RadioThemeData radioTheme; + /// A theme for customizing the color and text style of a [MaterialBanner]. + final MaterialBannerThemeData bannerTheme; - /// The colors and shapes used to render [Slider]. - /// - /// This is the value returned from [SliderTheme.of]. - final SliderThemeData sliderTheme; + /// A theme for customizing the color, thickness, and indents of [Divider]s, + /// [VerticalDivider]s, etc. + final DividerThemeData dividerTheme; - /// A theme for customizing colors, shape, elevation, and behavior of a [SnackBar]. - final SnackBarThemeData snackBarTheme; + /// A theme for customizing the appearance and layout of [ButtonBar] widgets. + final ButtonBarThemeData buttonBarTheme; - /// A theme for customizing the appearance and layout of [Switch] widgets. - final SwitchThemeData switchTheme; + /// A theme for customizing the appearance and layout of [BottomNavigationBar] + /// widgets. + final BottomNavigationBarThemeData bottomNavigationBarTheme; - /// A theme for customizing the size, shape, and color of the tab bar indicator. - final TabBarTheme tabBarTheme; + /// A theme for customizing the appearance and layout of time picker widgets. + final TimePickerThemeData timePickerTheme; /// A theme for customizing the appearance and internal layout of /// [TextButton]s. final TextButtonThemeData textButtonTheme; - /// A theme for customizing the appearance and layout of [TextField] widgets. - final TextSelectionThemeData textSelectionTheme; - - /// A theme for customizing the appearance and layout of time picker widgets. - final TimePickerThemeData timePickerTheme; - - /// Defines the default configuration of [ToggleButtons] widgets. - final ToggleButtonsThemeData toggleButtonsTheme; - - /// A theme for customizing the visual properties of [Tooltip]s. - /// - /// This is the value returned from [TooltipTheme.of]. - final TooltipThemeData tooltipTheme; - - // DEPRECATED (newest deprecations at the bottom) + /// A theme for customizing the appearance and internal layout of + /// [ElevatedButton]s. + final ElevatedButtonThemeData elevatedButtonTheme; - /// A temporary flag that was used to opt-in to the new [TextSelectionTheme] - /// during the migration to this new theme. That migration is now complete - /// and this flag is not longer used by the framework. Please remove any - /// reference to this property, as it will be removed in future releases. - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v1.23.0-4.0.pre.', - ) - final bool useTextSelectionTheme; + /// A theme for customizing the appearance and internal layout of + /// [OutlinedButton]s. + final OutlinedButtonThemeData outlinedButtonTheme; - /// The color of text selections in text fields, such as [TextField]. - @Deprecated( - 'Use TextSelectionThemeData.selectionColor instead. ' - 'This feature was deprecated after v1.26.0-18.0.pre.', - ) - final Color textSelectionColor; + /// A theme for customizing the appearance and layout of [TextField] widgets. + final TextSelectionThemeData textSelectionTheme; - /// The color of cursors in Material-style text fields, such as [TextField]. - @Deprecated( - 'Use TextSelectionThemeData.cursorColor instead. ' - 'This feature was deprecated after v1.26.0-18.0.pre.', - ) - final Color cursorColor; + /// A theme for customizing the appearance and layout of [DataTable] + /// widgets. + final DataTableThemeData dataTableTheme; - /// The color of the handles used to adjust what part of the text is currently selected. - @Deprecated( - 'Use TextSelectionThemeData.selectionHandleColor instead. ' - 'This feature was deprecated after v1.26.0-18.0.pre.', - ) - final Color textSelectionHandleColor; + /// A theme for customizing the appearance and layout of [Checkbox] widgets. + final CheckboxThemeData checkboxTheme; - /// Obsolete property that was originally used as the foreground - /// color for widgets (knobs, text, overscroll edge effect, etc). - /// - /// The material library no longer uses this property. In most cases - /// the theme's [colorScheme] [ColorScheme.secondary] property is now - /// used instead. - /// - /// Apps should migrate uses of this property to the theme's [colorScheme] - /// [ColorScheme.secondary] color. In cases where a color is needed that - /// that contrasts well with the secondary color [ColorScheme.onSecondary] - /// can be used. - @Deprecated( - 'Use colorScheme.secondary instead. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - final Color accentColor; + /// A theme for customizing the appearance and layout of [Radio] widgets. + final RadioThemeData radioTheme; - /// Obsolete property that was originally used to determine the color - /// of text and icons placed on top of the accent color (e.g. the - /// icons on a floating action button). - /// - /// The material library no longer uses this property. The - /// [floatingActionButtonTheme] can be used to configure - /// the appearance of [FloatingActionButton]s. The brightness - /// of any color can be found with [ThemeData.estimateBrightnessForColor]. - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - final Brightness accentColorBrightness; + /// A theme for customizing the appearance and layout of [Switch] widgets. + final SwitchThemeData switchTheme; - /// Obsolete property that was originally used when a [TextTheme] - /// that contrasted well with the [accentColor] was needed. - /// - /// The material library no longer uses this property and most uses - /// of [accentColor] have been replaced with - /// the theme's [colorScheme] [ColorScheme.secondary]. - /// You can configure the color of a [textTheme] [TextStyle] so that it - /// contrasts well with the [ColorScheme.secondary] like this: - /// - /// ```dart - /// final ThemeData theme = Theme.of(context); - /// theme.textTheme.headline1.copyWith( - /// color: theme.colorScheme.onSecondary, - /// ) - /// ``` - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - final TextTheme accentTextTheme; + /// A theme for customizing the appearance and layout of [ProgressIndicator] widgets. + final ProgressIndicatorThemeData progressIndicatorTheme; - /// Obsolete property that was originally used when an [IconTheme] - /// that contrasted well with the [accentColor] was needed. - /// - /// The material library no longer uses this property and most uses - /// of [accentColor] have been replaced with - /// the theme's [colorScheme] [ColorScheme.secondary]. - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - final IconThemeData accentIconTheme; + /// A theme for customizing the appearance and layout of [Drawer] widgets. + final DrawerThemeData drawerTheme; - /// The default fill color of the [Material] used in [RaisedButton]s. - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v2.3.0-0.2.pre.', - ) - final Color buttonColor; + /// A theme for customizing the appearance of [ListTile] widgets. + final ListTileThemeData listTileTheme; /// An obsolete flag to allow apps to opt-out of a /// [small fix](https://github.com/flutter/flutter/issues/54028) for the Y @@ -1531,111 +1379,76 @@ class ThemeData with Diagnosticable { ) final bool fixTextFieldOutlineLabel; - /// Obsolete property that was originally used to determine the color - /// of text and icons placed on top of the primary color (e.g. toolbar text). - /// - /// The material library no longer uses this property. The [appBarTheme] can - /// be used to configure the appearance of [AppBar]s. The appearance of - /// Keyboards for [TextField]s now uses the overall theme's - /// [ThemeData.brightness] and can also be customized with - /// [TextField.keyboardAppearance]. The brightness of any color can be found - /// with [ThemeData.estimateBrightnessForColor]. + /// A temporary flag that was used to opt-in to the new [TextSelectionTheme] + /// during the migration to this new theme. That migration is now complete + /// and this flag is not longer used by the framework. Please remove any + /// reference to this property, as it will be removed in future releases. @Deprecated( 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v2.6.0-11.0.pre.', + 'This feature was deprecated after v1.23.0-4.0.pre.', ) - final Brightness primaryColorBrightness; + final bool useTextSelectionTheme; - /// Creates a copy of this theme but with the given fields replaced with the new values. + /// Specifies which overscroll indicator to use on [TargetPlatform.android]. /// - /// The [brightness] value is applied to the [colorScheme]. - ThemeData copyWith({ - // GENERAL CONFIGURATION - AndroidOverscrollIndicator? androidOverscrollIndicator, - bool? applyElevationOverlayColor, - NoDefaultCupertinoThemeData? cupertinoOverrideTheme, - InputDecorationTheme? inputDecorationTheme, - MaterialTapTargetSize? materialTapTargetSize, - PageTransitionsTheme? pageTransitionsTheme, - TargetPlatform? platform, - ScrollbarThemeData? scrollbarTheme, - InteractiveInkFeatureFactory? splashFactory, - VisualDensity? visualDensity, - bool? useMaterial3, - // COLOR - // [colorScheme] is the preferred way to configure colors. The other color - // properties will gradually be phased out, see - // https://github.com/flutter/flutter/issues/91772. - ColorScheme? colorScheme, + /// When null, the default value of + /// [MaterialScrollBehavior.androidOverscrollIndicator] is + /// [AndroidOverscrollIndicator.glow]. + /// + /// See also: + /// + /// * [StretchingOverscrollIndicator], a material design edge effect + /// that transforms the contents of a scrollable when overscrolled. + /// * [GlowingOverscrollIndicator], an edge effect that paints a glow + /// over the contents of a scrollable when overscrolled. + final AndroidOverscrollIndicator? androidOverscrollIndicator; + + /// Creates a copy of this theme but with the given fields replaced with the new values. + /// + /// The [brightness] value is applied to the [colorScheme]. + ThemeData copyWith({ Brightness? brightness, + VisualDensity? visualDensity, Color? primaryColor, + Brightness? primaryColorBrightness, Color? primaryColorLight, Color? primaryColorDark, - Color? focusColor, - Color? hoverColor, - Color? shadowColor, + @Deprecated( + 'No longer used by the framework, please remove any reference to it. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + Color? accentColor, + @Deprecated( + 'No longer used by the framework, please remove any reference to it. ' + 'For more information, consult the migration guide at ' + 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' + 'This feature was deprecated after v2.3.0-0.1.pre.', + ) + Brightness? accentColorBrightness, Color? canvasColor, + Color? shadowColor, Color? scaffoldBackgroundColor, Color? bottomAppBarColor, Color? cardColor, Color? dividerColor, + Color? focusColor, + Color? hoverColor, Color? highlightColor, Color? splashColor, + InteractiveInkFeatureFactory? splashFactory, Color? selectedRowColor, Color? unselectedWidgetColor, Color? disabledColor, - Color? secondaryHeaderColor, - Color? backgroundColor, - Color? dialogBackgroundColor, - Color? indicatorColor, - Color? hintColor, - Color? errorColor, - Color? toggleableActiveColor, - // TYPOGRAPHY & ICONOGRAPHY - Typography? typography, - TextTheme? textTheme, - TextTheme? primaryTextTheme, - IconThemeData? iconTheme, - IconThemeData? primaryIconTheme, - // COMPONENT THEMES - AppBarTheme? appBarTheme, - MaterialBannerThemeData? bannerTheme, - BottomAppBarTheme? bottomAppBarTheme, - BottomNavigationBarThemeData? bottomNavigationBarTheme, - BottomSheetThemeData? bottomSheetTheme, - ButtonBarThemeData? buttonBarTheme, ButtonThemeData? buttonTheme, - CardTheme? cardTheme, - CheckboxThemeData? checkboxTheme, - ChipThemeData? chipTheme, - DataTableThemeData? dataTableTheme, - DialogTheme? dialogTheme, - DividerThemeData? dividerTheme, - DrawerThemeData? drawerTheme, - ElevatedButtonThemeData? elevatedButtonTheme, - FloatingActionButtonThemeData? floatingActionButtonTheme, - ListTileThemeData? listTileTheme, - NavigationBarThemeData? navigationBarTheme, - NavigationRailThemeData? navigationRailTheme, - OutlinedButtonThemeData? outlinedButtonTheme, - PopupMenuThemeData? popupMenuTheme, - ProgressIndicatorThemeData? progressIndicatorTheme, - RadioThemeData? radioTheme, - SliderThemeData? sliderTheme, - SnackBarThemeData? snackBarTheme, - SwitchThemeData? switchTheme, - TabBarTheme? tabBarTheme, - TextButtonThemeData? textButtonTheme, - TextSelectionThemeData? textSelectionTheme, - TimePickerThemeData? timePickerTheme, ToggleButtonsThemeData? toggleButtonsTheme, - TooltipThemeData? tooltipTheme, - // DEPRECATED (newest deprecations at the bottom) @Deprecated( 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v1.23.0-4.0.pre.', + 'This feature was deprecated after v2.3.0-0.2.pre.', ) - bool? useTextSelectionTheme, + Color? buttonColor, + Color? secondaryHeaderColor, @Deprecated( 'Use TextSelectionThemeData.selectionColor instead. ' 'This feature was deprecated after v1.26.0-18.0.pre.', @@ -1651,20 +1464,14 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v1.26.0-18.0.pre.', ) Color? textSelectionHandleColor, - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - Color? accentColor, - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'For more information, consult the migration guide at ' - 'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. ' - 'This feature was deprecated after v2.3.0-0.1.pre.', - ) - Brightness? accentColorBrightness, + Color? backgroundColor, + Color? dialogBackgroundColor, + Color? indicatorColor, + Color? hintColor, + Color? errorColor, + Color? toggleableActiveColor, + TextTheme? textTheme, + TextTheme? primaryTextTheme, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' 'For more information, consult the migration guide at ' @@ -1672,6 +1479,9 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v2.3.0-0.1.pre.', ) TextTheme? accentTextTheme, + InputDecorationTheme? inputDecorationTheme, + IconThemeData? iconTheme, + IconThemeData? primaryIconTheme, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' 'For more information, consult the migration guide at ' @@ -1679,11 +1489,44 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v2.3.0-0.1.pre.', ) IconThemeData? accentIconTheme, - @Deprecated( - 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v2.3.0-0.2.pre.', - ) - Color? buttonColor, + SliderThemeData? sliderTheme, + TabBarTheme? tabBarTheme, + TooltipThemeData? tooltipTheme, + CardTheme? cardTheme, + ChipThemeData? chipTheme, + TargetPlatform? platform, + MaterialTapTargetSize? materialTapTargetSize, + bool? applyElevationOverlayColor, + PageTransitionsTheme? pageTransitionsTheme, + AppBarTheme? appBarTheme, + ScrollbarThemeData? scrollbarTheme, + BottomAppBarTheme? bottomAppBarTheme, + ColorScheme? colorScheme, + DialogTheme? dialogTheme, + FloatingActionButtonThemeData? floatingActionButtonTheme, + NavigationBarThemeData? navigationBarTheme, + NavigationRailThemeData? navigationRailTheme, + Typography? typography, + NoDefaultCupertinoThemeData? cupertinoOverrideTheme, + SnackBarThemeData? snackBarTheme, + BottomSheetThemeData? bottomSheetTheme, + PopupMenuThemeData? popupMenuTheme, + MaterialBannerThemeData? bannerTheme, + DividerThemeData? dividerTheme, + ButtonBarThemeData? buttonBarTheme, + BottomNavigationBarThemeData? bottomNavigationBarTheme, + TimePickerThemeData? timePickerTheme, + TextButtonThemeData? textButtonTheme, + ElevatedButtonThemeData? elevatedButtonTheme, + OutlinedButtonThemeData? outlinedButtonTheme, + TextSelectionThemeData? textSelectionTheme, + DataTableThemeData? dataTableTheme, + CheckboxThemeData? checkboxTheme, + RadioThemeData? radioTheme, + SwitchThemeData? switchTheme, + ProgressIndicatorThemeData? progressIndicatorTheme, + DrawerThemeData? drawerTheme, + ListTileThemeData? listTileTheme, @Deprecated( 'This "fix" is now enabled by default. ' 'This feature was deprecated after v2.5.0-1.0.pre.', @@ -1691,100 +1534,95 @@ class ThemeData with Diagnosticable { bool? fixTextFieldOutlineLabel, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' - 'This feature was deprecated after v2.6.0-11.0.pre.', + 'This feature was deprecated after v1.23.0-4.0.pre.', ) - Brightness? primaryColorBrightness, + bool? useTextSelectionTheme, + AndroidOverscrollIndicator? androidOverscrollIndicator, }) { cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault(); return ThemeData.raw( - // GENERAL CONFIGURATION - androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator, - applyElevationOverlayColor: applyElevationOverlayColor ?? this.applyElevationOverlayColor, - cupertinoOverrideTheme: cupertinoOverrideTheme ?? this.cupertinoOverrideTheme, - inputDecorationTheme: inputDecorationTheme ?? this.inputDecorationTheme, - materialTapTargetSize: materialTapTargetSize ?? this.materialTapTargetSize, - pageTransitionsTheme: pageTransitionsTheme ?? this.pageTransitionsTheme, - platform: platform ?? this.platform, - scrollbarTheme: scrollbarTheme ?? this.scrollbarTheme, - splashFactory: splashFactory ?? this.splashFactory, visualDensity: visualDensity ?? this.visualDensity, - useMaterial3: useMaterial3 ?? this.useMaterial3, - // COLOR - colorScheme: (colorScheme ?? this.colorScheme).copyWith(brightness: brightness), primaryColor: primaryColor ?? this.primaryColor, + primaryColorBrightness: primaryColorBrightness ?? this.primaryColorBrightness, primaryColorLight: primaryColorLight ?? this.primaryColorLight, primaryColorDark: primaryColorDark ?? this.primaryColorDark, - focusColor: focusColor ?? this.focusColor, - hoverColor: hoverColor ?? this.hoverColor, - shadowColor: shadowColor ?? this.shadowColor, + accentColor: accentColor ?? this.accentColor, + accentColorBrightness: accentColorBrightness ?? this.accentColorBrightness, canvasColor: canvasColor ?? this.canvasColor, + shadowColor: shadowColor ?? this.shadowColor, scaffoldBackgroundColor: scaffoldBackgroundColor ?? this.scaffoldBackgroundColor, bottomAppBarColor: bottomAppBarColor ?? this.bottomAppBarColor, cardColor: cardColor ?? this.cardColor, dividerColor: dividerColor ?? this.dividerColor, + focusColor: focusColor ?? this.focusColor, + hoverColor: hoverColor ?? this.hoverColor, highlightColor: highlightColor ?? this.highlightColor, splashColor: splashColor ?? this.splashColor, + splashFactory: splashFactory ?? this.splashFactory, selectedRowColor: selectedRowColor ?? this.selectedRowColor, unselectedWidgetColor: unselectedWidgetColor ?? this.unselectedWidgetColor, disabledColor: disabledColor ?? this.disabledColor, + buttonColor: buttonColor ?? this.buttonColor, + buttonTheme: buttonTheme ?? this.buttonTheme, + toggleButtonsTheme: toggleButtonsTheme ?? this.toggleButtonsTheme, secondaryHeaderColor: secondaryHeaderColor ?? this.secondaryHeaderColor, + textSelectionColor: textSelectionColor ?? this.textSelectionColor, + cursorColor: cursorColor ?? this.cursorColor, + textSelectionHandleColor: textSelectionHandleColor ?? this.textSelectionHandleColor, backgroundColor: backgroundColor ?? this.backgroundColor, dialogBackgroundColor: dialogBackgroundColor ?? this.dialogBackgroundColor, indicatorColor: indicatorColor ?? this.indicatorColor, hintColor: hintColor ?? this.hintColor, errorColor: errorColor ?? this.errorColor, toggleableActiveColor: toggleableActiveColor ?? this.toggleableActiveColor, - // TYPOGRAPHY & ICONOGRAPHY - typography: typography ?? this.typography, textTheme: textTheme ?? this.textTheme, primaryTextTheme: primaryTextTheme ?? this.primaryTextTheme, + accentTextTheme: accentTextTheme ?? this.accentTextTheme, + inputDecorationTheme: inputDecorationTheme ?? this.inputDecorationTheme, iconTheme: iconTheme ?? this.iconTheme, primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, - // COMPONENT THEMES - appBarTheme: appBarTheme ?? this.appBarTheme, - bannerTheme: bannerTheme ?? this.bannerTheme, - bottomAppBarTheme: bottomAppBarTheme ?? this.bottomAppBarTheme, - bottomNavigationBarTheme: bottomNavigationBarTheme ?? this.bottomNavigationBarTheme, - bottomSheetTheme: bottomSheetTheme ?? this.bottomSheetTheme, - buttonBarTheme: buttonBarTheme ?? this.buttonBarTheme, - buttonTheme: buttonTheme ?? this.buttonTheme, + accentIconTheme: accentIconTheme ?? this.accentIconTheme, + sliderTheme: sliderTheme ?? this.sliderTheme, + tabBarTheme: tabBarTheme ?? this.tabBarTheme, + tooltipTheme: tooltipTheme ?? this.tooltipTheme, cardTheme: cardTheme ?? this.cardTheme, - checkboxTheme: checkboxTheme ?? this.checkboxTheme, chipTheme: chipTheme ?? this.chipTheme, - dataTableTheme: dataTableTheme ?? this.dataTableTheme, + platform: platform ?? this.platform, + materialTapTargetSize: materialTapTargetSize ?? this.materialTapTargetSize, + applyElevationOverlayColor: applyElevationOverlayColor ?? this.applyElevationOverlayColor, + pageTransitionsTheme: pageTransitionsTheme ?? this.pageTransitionsTheme, + appBarTheme: appBarTheme ?? this.appBarTheme, + scrollbarTheme: scrollbarTheme ?? this.scrollbarTheme, + bottomAppBarTheme: bottomAppBarTheme ?? this.bottomAppBarTheme, + colorScheme: (colorScheme ?? this.colorScheme).copyWith(brightness: brightness), dialogTheme: dialogTheme ?? this.dialogTheme, - dividerTheme: dividerTheme ?? this.dividerTheme, - drawerTheme: drawerTheme ?? this.drawerTheme, - elevatedButtonTheme: elevatedButtonTheme ?? this.elevatedButtonTheme, floatingActionButtonTheme: floatingActionButtonTheme ?? this.floatingActionButtonTheme, - listTileTheme: listTileTheme ?? this.listTileTheme, navigationBarTheme: navigationBarTheme ?? this.navigationBarTheme, navigationRailTheme: navigationRailTheme ?? this.navigationRailTheme, - outlinedButtonTheme: outlinedButtonTheme ?? this.outlinedButtonTheme, - popupMenuTheme: popupMenuTheme ?? this.popupMenuTheme, - progressIndicatorTheme: progressIndicatorTheme ?? this.progressIndicatorTheme, - radioTheme: radioTheme ?? this.radioTheme, - sliderTheme: sliderTheme ?? this.sliderTheme, + typography: typography ?? this.typography, + cupertinoOverrideTheme: cupertinoOverrideTheme ?? this.cupertinoOverrideTheme, snackBarTheme: snackBarTheme ?? this.snackBarTheme, - switchTheme: switchTheme ?? this.switchTheme, - tabBarTheme: tabBarTheme ?? this.tabBarTheme, + bottomSheetTheme: bottomSheetTheme ?? this.bottomSheetTheme, + popupMenuTheme: popupMenuTheme ?? this.popupMenuTheme, + bannerTheme: bannerTheme ?? this.bannerTheme, + dividerTheme: dividerTheme ?? this.dividerTheme, + buttonBarTheme: buttonBarTheme ?? this.buttonBarTheme, + bottomNavigationBarTheme: bottomNavigationBarTheme ?? this.bottomNavigationBarTheme, + timePickerTheme: timePickerTheme ?? this.timePickerTheme, textButtonTheme: textButtonTheme ?? this.textButtonTheme, + elevatedButtonTheme: elevatedButtonTheme ?? this.elevatedButtonTheme, + outlinedButtonTheme: outlinedButtonTheme ?? this.outlinedButtonTheme, textSelectionTheme: textSelectionTheme ?? this.textSelectionTheme, - timePickerTheme: timePickerTheme ?? this.timePickerTheme, - toggleButtonsTheme: toggleButtonsTheme ?? this.toggleButtonsTheme, - tooltipTheme: tooltipTheme ?? this.tooltipTheme, - // DEPRECATED (newest deprecations at the bottom) - useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme, - textSelectionColor: textSelectionColor ?? this.textSelectionColor, - cursorColor: cursorColor ?? this.cursorColor, - textSelectionHandleColor: textSelectionHandleColor ?? this.textSelectionHandleColor, - accentColor: accentColor ?? this.accentColor, - accentColorBrightness: accentColorBrightness ?? this.accentColorBrightness, - accentTextTheme: accentTextTheme ?? this.accentTextTheme, - accentIconTheme: accentIconTheme ?? this.accentIconTheme, - buttonColor: buttonColor ?? this.buttonColor, + dataTableTheme: dataTableTheme ?? this.dataTableTheme, + checkboxTheme: checkboxTheme ?? this.checkboxTheme, + radioTheme: radioTheme ?? this.radioTheme, + switchTheme: switchTheme ?? this.switchTheme, + progressIndicatorTheme: progressIndicatorTheme ?? this.progressIndicatorTheme, + drawerTheme: drawerTheme ?? this.drawerTheme, + listTileTheme: listTileTheme ?? this.listTileTheme, fixTextFieldOutlineLabel: fixTextFieldOutlineLabel ?? this.fixTextFieldOutlineLabel, - primaryColorBrightness: primaryColorBrightness ?? this.primaryColorBrightness, + useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme, + androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator, ); } @@ -1866,94 +1704,88 @@ class ThemeData with Diagnosticable { // hashValues() and in the raw constructor and in the order of fields in // the class and in the lerp() method. return ThemeData.raw( - // GENERAL CONFIGURATION - androidOverscrollIndicator:t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator, - applyElevationOverlayColor:t < 0.5 ? a.applyElevationOverlayColor : b.applyElevationOverlayColor, - cupertinoOverrideTheme:t < 0.5 ? a.cupertinoOverrideTheme : b.cupertinoOverrideTheme, - inputDecorationTheme:t < 0.5 ? a.inputDecorationTheme : b.inputDecorationTheme, - materialTapTargetSize:t < 0.5 ? a.materialTapTargetSize : b.materialTapTargetSize, - pageTransitionsTheme:t < 0.5 ? a.pageTransitionsTheme : b.pageTransitionsTheme, - platform: t < 0.5 ? a.platform : b.platform, - scrollbarTheme: ScrollbarThemeData.lerp(a.scrollbarTheme, b.scrollbarTheme, t), - splashFactory: t < 0.5 ? a.splashFactory : b.splashFactory, visualDensity: VisualDensity.lerp(a.visualDensity, b.visualDensity, t), - useMaterial3: t < 0.5 ? a.useMaterial3 : b.useMaterial3, - // COLOR - colorScheme: ColorScheme.lerp(a.colorScheme, b.colorScheme, t), primaryColor: Color.lerp(a.primaryColor, b.primaryColor, t)!, + primaryColorBrightness: t < 0.5 ? a.primaryColorBrightness : b.primaryColorBrightness, primaryColorLight: Color.lerp(a.primaryColorLight, b.primaryColorLight, t)!, primaryColorDark: Color.lerp(a.primaryColorDark, b.primaryColorDark, t)!, - focusColor: Color.lerp(a.focusColor, b.focusColor, t)!, - hoverColor: Color.lerp(a.hoverColor, b.hoverColor, t)!, - shadowColor: Color.lerp(a.shadowColor, b.shadowColor, t)!, canvasColor: Color.lerp(a.canvasColor, b.canvasColor, t)!, + shadowColor: Color.lerp(a.shadowColor, b.shadowColor, t)!, + accentColor: Color.lerp(a.accentColor, b.accentColor, t)!, + accentColorBrightness: t < 0.5 ? a.accentColorBrightness : b.accentColorBrightness, scaffoldBackgroundColor: Color.lerp(a.scaffoldBackgroundColor, b.scaffoldBackgroundColor, t)!, bottomAppBarColor: Color.lerp(a.bottomAppBarColor, b.bottomAppBarColor, t)!, cardColor: Color.lerp(a.cardColor, b.cardColor, t)!, dividerColor: Color.lerp(a.dividerColor, b.dividerColor, t)!, + focusColor: Color.lerp(a.focusColor, b.focusColor, t)!, + hoverColor: Color.lerp(a.hoverColor, b.hoverColor, t)!, highlightColor: Color.lerp(a.highlightColor, b.highlightColor, t)!, splashColor: Color.lerp(a.splashColor, b.splashColor, t)!, + splashFactory: t < 0.5 ? a.splashFactory : b.splashFactory, selectedRowColor: Color.lerp(a.selectedRowColor, b.selectedRowColor, t)!, unselectedWidgetColor: Color.lerp(a.unselectedWidgetColor, b.unselectedWidgetColor, t)!, disabledColor: Color.lerp(a.disabledColor, b.disabledColor, t)!, + buttonTheme: t < 0.5 ? a.buttonTheme : b.buttonTheme, + buttonColor: Color.lerp(a.buttonColor, b.buttonColor, t)!, + toggleButtonsTheme: ToggleButtonsThemeData.lerp(a.toggleButtonsTheme, b.toggleButtonsTheme, t)!, secondaryHeaderColor: Color.lerp(a.secondaryHeaderColor, b.secondaryHeaderColor, t)!, + textSelectionColor: Color.lerp(a.textSelectionColor, b.textSelectionColor, t)!, + cursorColor: Color.lerp(a.cursorColor, b.cursorColor, t)!, + textSelectionHandleColor: Color.lerp(a.textSelectionHandleColor, b.textSelectionHandleColor, t)!, backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t)!, dialogBackgroundColor: Color.lerp(a.dialogBackgroundColor, b.dialogBackgroundColor, t)!, indicatorColor: Color.lerp(a.indicatorColor, b.indicatorColor, t)!, hintColor: Color.lerp(a.hintColor, b.hintColor, t)!, errorColor: Color.lerp(a.errorColor, b.errorColor, t)!, toggleableActiveColor: Color.lerp(a.toggleableActiveColor, b.toggleableActiveColor, t)!, - // TYPOGRAPHY & ICONOGRAPHY - typography: Typography.lerp(a.typography, b.typography, t), textTheme: TextTheme.lerp(a.textTheme, b.textTheme, t), primaryTextTheme: TextTheme.lerp(a.primaryTextTheme, b.primaryTextTheme, t), + accentTextTheme: TextTheme.lerp(a.accentTextTheme, b.accentTextTheme, t), + inputDecorationTheme: t < 0.5 ? a.inputDecorationTheme : b.inputDecorationTheme, iconTheme: IconThemeData.lerp(a.iconTheme, b.iconTheme, t), primaryIconTheme: IconThemeData.lerp(a.primaryIconTheme, b.primaryIconTheme, t), - // COMPONENT THEMES - appBarTheme: AppBarTheme.lerp(a.appBarTheme, b.appBarTheme, t), - bannerTheme: MaterialBannerThemeData.lerp(a.bannerTheme, b.bannerTheme, t), - bottomAppBarTheme: BottomAppBarTheme.lerp(a.bottomAppBarTheme, b.bottomAppBarTheme, t), - bottomNavigationBarTheme: BottomNavigationBarThemeData.lerp(a.bottomNavigationBarTheme, b.bottomNavigationBarTheme, t), - bottomSheetTheme: BottomSheetThemeData.lerp(a.bottomSheetTheme, b.bottomSheetTheme, t)!, - buttonBarTheme: ButtonBarThemeData.lerp(a.buttonBarTheme, b.buttonBarTheme, t)!, - buttonTheme: t < 0.5 ? a.buttonTheme : b.buttonTheme, + accentIconTheme: IconThemeData.lerp(a.accentIconTheme, b.accentIconTheme, t), + sliderTheme: SliderThemeData.lerp(a.sliderTheme, b.sliderTheme, t), + tabBarTheme: TabBarTheme.lerp(a.tabBarTheme, b.tabBarTheme, t), + tooltipTheme: TooltipThemeData.lerp(a.tooltipTheme, b.tooltipTheme, t)!, cardTheme: CardTheme.lerp(a.cardTheme, b.cardTheme, t), - checkboxTheme: CheckboxThemeData.lerp(a.checkboxTheme, b.checkboxTheme, t), chipTheme: ChipThemeData.lerp(a.chipTheme, b.chipTheme, t)!, - dataTableTheme: DataTableThemeData.lerp(a.dataTableTheme, b.dataTableTheme, t), + platform: t < 0.5 ? a.platform : b.platform, + materialTapTargetSize: t < 0.5 ? a.materialTapTargetSize : b.materialTapTargetSize, + applyElevationOverlayColor: t < 0.5 ? a.applyElevationOverlayColor : b.applyElevationOverlayColor, + pageTransitionsTheme: t < 0.5 ? a.pageTransitionsTheme : b.pageTransitionsTheme, + appBarTheme: AppBarTheme.lerp(a.appBarTheme, b.appBarTheme, t), + scrollbarTheme: ScrollbarThemeData.lerp(a.scrollbarTheme, b.scrollbarTheme, t), + bottomAppBarTheme: BottomAppBarTheme.lerp(a.bottomAppBarTheme, b.bottomAppBarTheme, t), + colorScheme: ColorScheme.lerp(a.colorScheme, b.colorScheme, t), dialogTheme: DialogTheme.lerp(a.dialogTheme, b.dialogTheme, t), - dividerTheme: DividerThemeData.lerp(a.dividerTheme, b.dividerTheme, t), - drawerTheme: DrawerThemeData.lerp(a.drawerTheme, b.drawerTheme, t)!, - elevatedButtonTheme: ElevatedButtonThemeData.lerp(a.elevatedButtonTheme, b.elevatedButtonTheme, t)!, floatingActionButtonTheme: FloatingActionButtonThemeData.lerp(a.floatingActionButtonTheme, b.floatingActionButtonTheme, t)!, - listTileTheme: ListTileThemeData.lerp(a.listTileTheme, b.listTileTheme, t)!, navigationBarTheme: NavigationBarThemeData.lerp(a.navigationBarTheme, b.navigationBarTheme, t)!, navigationRailTheme: NavigationRailThemeData.lerp(a.navigationRailTheme, b.navigationRailTheme, t)!, - outlinedButtonTheme: OutlinedButtonThemeData.lerp(a.outlinedButtonTheme, b.outlinedButtonTheme, t)!, - popupMenuTheme: PopupMenuThemeData.lerp(a.popupMenuTheme, b.popupMenuTheme, t)!, - progressIndicatorTheme: ProgressIndicatorThemeData.lerp(a.progressIndicatorTheme, b.progressIndicatorTheme, t)!, - radioTheme: RadioThemeData.lerp(a.radioTheme, b.radioTheme, t), - sliderTheme: SliderThemeData.lerp(a.sliderTheme, b.sliderTheme, t), + typography: Typography.lerp(a.typography, b.typography, t), + cupertinoOverrideTheme: t < 0.5 ? a.cupertinoOverrideTheme : b.cupertinoOverrideTheme, snackBarTheme: SnackBarThemeData.lerp(a.snackBarTheme, b.snackBarTheme, t), - switchTheme: SwitchThemeData.lerp(a.switchTheme, b.switchTheme, t), - tabBarTheme: TabBarTheme.lerp(a.tabBarTheme, b.tabBarTheme, t), + bottomSheetTheme: BottomSheetThemeData.lerp(a.bottomSheetTheme, b.bottomSheetTheme, t)!, + popupMenuTheme: PopupMenuThemeData.lerp(a.popupMenuTheme, b.popupMenuTheme, t)!, + bannerTheme: MaterialBannerThemeData.lerp(a.bannerTheme, b.bannerTheme, t), + dividerTheme: DividerThemeData.lerp(a.dividerTheme, b.dividerTheme, t), + buttonBarTheme: ButtonBarThemeData.lerp(a.buttonBarTheme, b.buttonBarTheme, t)!, + bottomNavigationBarTheme: BottomNavigationBarThemeData.lerp(a.bottomNavigationBarTheme, b.bottomNavigationBarTheme, t), + timePickerTheme: TimePickerThemeData.lerp(a.timePickerTheme, b.timePickerTheme, t), textButtonTheme: TextButtonThemeData.lerp(a.textButtonTheme, b.textButtonTheme, t)!, + elevatedButtonTheme: ElevatedButtonThemeData.lerp(a.elevatedButtonTheme, b.elevatedButtonTheme, t)!, + outlinedButtonTheme: OutlinedButtonThemeData.lerp(a.outlinedButtonTheme, b.outlinedButtonTheme, t)!, textSelectionTheme: TextSelectionThemeData.lerp(a.textSelectionTheme, b.textSelectionTheme, t)!, - timePickerTheme: TimePickerThemeData.lerp(a.timePickerTheme, b.timePickerTheme, t), - toggleButtonsTheme: ToggleButtonsThemeData.lerp(a.toggleButtonsTheme, b.toggleButtonsTheme, t)!, - tooltipTheme: TooltipThemeData.lerp(a.tooltipTheme, b.tooltipTheme, t)!, - // DEPRECATED (newest deprecations at the bottom) - useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme, - textSelectionColor: Color.lerp(a.textSelectionColor, b.textSelectionColor, t)!, - cursorColor: Color.lerp(a.cursorColor, b.cursorColor, t)!, - textSelectionHandleColor: Color.lerp(a.textSelectionHandleColor, b.textSelectionHandleColor, t)!, - accentColor: Color.lerp(a.accentColor, b.accentColor, t)!, - accentColorBrightness: t < 0.5 ? a.accentColorBrightness : b.accentColorBrightness, - accentTextTheme: TextTheme.lerp(a.accentTextTheme, b.accentTextTheme, t), - accentIconTheme: IconThemeData.lerp(a.accentIconTheme, b.accentIconTheme, t), - buttonColor: Color.lerp(a.buttonColor, b.buttonColor, t)!, + dataTableTheme: DataTableThemeData.lerp(a.dataTableTheme, b.dataTableTheme, t), + checkboxTheme: CheckboxThemeData.lerp(a.checkboxTheme, b.checkboxTheme, t), + radioTheme: RadioThemeData.lerp(a.radioTheme, b.radioTheme, t), + switchTheme: SwitchThemeData.lerp(a.switchTheme, b.switchTheme, t), + progressIndicatorTheme: ProgressIndicatorThemeData.lerp(a.progressIndicatorTheme, b.progressIndicatorTheme, t)!, + drawerTheme: DrawerThemeData.lerp(a.drawerTheme, b.drawerTheme, t)!, + listTileTheme: ListTileThemeData.lerp(a.listTileTheme, b.listTileTheme, t)!, fixTextFieldOutlineLabel: t < 0.5 ? a.fixTextFieldOutlineLabel : b.fixTextFieldOutlineLabel, - primaryColorBrightness: t < 0.5 ? a.primaryColorBrightness : b.primaryColorBrightness, + useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme, + androidOverscrollIndicator: t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator, ); } @@ -1964,95 +1796,89 @@ class ThemeData with Diagnosticable { // Warning: make sure these properties are in the exact same order as in // hashValues() and in the raw constructor and in the order of fields in // the class and in the lerp() method. - return other is ThemeData && - // GENERAL CONFIGURATION - other.androidOverscrollIndicator == androidOverscrollIndicator && - other.applyElevationOverlayColor == applyElevationOverlayColor && - other.cupertinoOverrideTheme == cupertinoOverrideTheme && - other.inputDecorationTheme == inputDecorationTheme && - other.materialTapTargetSize == materialTapTargetSize && - other.pageTransitionsTheme == pageTransitionsTheme && - other.platform == platform && - other.scrollbarTheme == scrollbarTheme && - other.splashFactory == splashFactory && - other.visualDensity == visualDensity && - other.useMaterial3 == useMaterial3 && - // COLOR - other.colorScheme == colorScheme && - other.primaryColor == primaryColor && - other.primaryColorLight == primaryColorLight && - other.primaryColorDark == primaryColorDark && - other.focusColor == focusColor && - other.hoverColor == hoverColor && - other.shadowColor == shadowColor && - other.canvasColor == canvasColor && - other.scaffoldBackgroundColor == scaffoldBackgroundColor && - other.bottomAppBarColor == bottomAppBarColor && - other.cardColor == cardColor && - other.dividerColor == dividerColor && - other.highlightColor == highlightColor && - other.splashColor == splashColor && - other.selectedRowColor == selectedRowColor && - other.unselectedWidgetColor == unselectedWidgetColor && - other.disabledColor == disabledColor && - other.secondaryHeaderColor == secondaryHeaderColor && - other.backgroundColor == backgroundColor && - other.dialogBackgroundColor == dialogBackgroundColor && - other.indicatorColor == indicatorColor && - other.hintColor == hintColor && - other.errorColor == errorColor && - other.toggleableActiveColor == toggleableActiveColor && - // TYPOGRAPHY & ICONOGRAPHY - other.typography == typography && - other.textTheme == textTheme && - other.primaryTextTheme == primaryTextTheme && - other.iconTheme == iconTheme && - other.primaryIconTheme == primaryIconTheme && - // COMPONENT THEMES - other.appBarTheme == appBarTheme && - other.bannerTheme == bannerTheme && - other.bottomAppBarTheme == bottomAppBarTheme && - other.bottomNavigationBarTheme == bottomNavigationBarTheme && - other.bottomSheetTheme == bottomSheetTheme && - other.buttonBarTheme == buttonBarTheme && - other.buttonTheme == buttonTheme && - other.cardTheme == cardTheme && - other.checkboxTheme == checkboxTheme && - other.chipTheme == chipTheme && - other.dataTableTheme == dataTableTheme && - other.dialogTheme == dialogTheme && - other.dividerTheme == dividerTheme && - other.drawerTheme == drawerTheme && - other.elevatedButtonTheme == elevatedButtonTheme && - other.floatingActionButtonTheme == floatingActionButtonTheme && - other.listTileTheme == listTileTheme && - other.navigationBarTheme == navigationBarTheme && - other.navigationRailTheme == navigationRailTheme && - other.outlinedButtonTheme == outlinedButtonTheme && - other.popupMenuTheme == popupMenuTheme && - other.progressIndicatorTheme == progressIndicatorTheme && - other.radioTheme == radioTheme && - other.sliderTheme == sliderTheme && - other.snackBarTheme == snackBarTheme && - other.switchTheme == switchTheme && - other.tabBarTheme == tabBarTheme && - other.textButtonTheme == textButtonTheme && - other.textSelectionTheme == textSelectionTheme && - other.timePickerTheme == timePickerTheme && - other.toggleButtonsTheme == toggleButtonsTheme && - other.tooltipTheme == tooltipTheme && - // DEPRECATED (newest deprecations at the bottom) - other.useTextSelectionTheme == useTextSelectionTheme && - other.textSelectionColor == textSelectionColor && - other.cursorColor == cursorColor && - other.textSelectionHandleColor == textSelectionHandleColor && - other.accentColor == accentColor && - other.accentColorBrightness == accentColorBrightness && - other.accentTextTheme == accentTextTheme && - other.accentIconTheme == accentIconTheme && - other.buttonColor == buttonColor && - other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel && - other.primaryColorBrightness == primaryColorBrightness; + return other is ThemeData + && other.visualDensity == visualDensity + && other.primaryColor == primaryColor + && other.primaryColorBrightness == primaryColorBrightness + && other.primaryColorLight == primaryColorLight + && other.primaryColorDark == primaryColorDark + && other.canvasColor == canvasColor + && other.shadowColor == shadowColor + && other.accentColor == accentColor + && other.accentColorBrightness == accentColorBrightness + && other.scaffoldBackgroundColor == scaffoldBackgroundColor + && other.bottomAppBarColor == bottomAppBarColor + && other.cardColor == cardColor + && other.dividerColor == dividerColor + && other.focusColor == focusColor + && other.hoverColor == hoverColor + && other.highlightColor == highlightColor + && other.splashColor == splashColor + && other.splashFactory == splashFactory + && other.selectedRowColor == selectedRowColor + && other.unselectedWidgetColor == unselectedWidgetColor + && other.disabledColor == disabledColor + && other.buttonTheme == buttonTheme + && other.buttonColor == buttonColor + && other.toggleButtonsTheme == toggleButtonsTheme + && other.secondaryHeaderColor == secondaryHeaderColor + && other.textSelectionColor == textSelectionColor + && other.cursorColor == cursorColor + && other.textSelectionHandleColor == textSelectionHandleColor + && other.backgroundColor == backgroundColor + && other.dialogBackgroundColor == dialogBackgroundColor + && other.indicatorColor == indicatorColor + && other.hintColor == hintColor + && other.errorColor == errorColor + && other.toggleableActiveColor == toggleableActiveColor + && other.textTheme == textTheme + && other.primaryTextTheme == primaryTextTheme + && other.accentTextTheme == accentTextTheme + && other.inputDecorationTheme == inputDecorationTheme + && other.iconTheme == iconTheme + && other.primaryIconTheme == primaryIconTheme + && other.accentIconTheme == accentIconTheme + && other.sliderTheme == sliderTheme + && other.tabBarTheme == tabBarTheme + && other.tooltipTheme == tooltipTheme + && other.cardTheme == cardTheme + && other.chipTheme == chipTheme + && other.platform == platform + && other.materialTapTargetSize == materialTapTargetSize + && other.applyElevationOverlayColor == applyElevationOverlayColor + && other.pageTransitionsTheme == pageTransitionsTheme + && other.appBarTheme == appBarTheme + && other.scrollbarTheme == scrollbarTheme + && other.bottomAppBarTheme == bottomAppBarTheme + && other.colorScheme == colorScheme + && other.dialogTheme == dialogTheme + && other.floatingActionButtonTheme == floatingActionButtonTheme + && other.navigationBarTheme == navigationBarTheme + && other.navigationRailTheme == navigationRailTheme + && other.typography == typography + && other.cupertinoOverrideTheme == cupertinoOverrideTheme + && other.snackBarTheme == snackBarTheme + && other.bottomSheetTheme == bottomSheetTheme + && other.popupMenuTheme == popupMenuTheme + && other.bannerTheme == bannerTheme + && other.dividerTheme == dividerTheme + && other.buttonBarTheme == buttonBarTheme + && other.bottomNavigationBarTheme == bottomNavigationBarTheme + && other.timePickerTheme == timePickerTheme + && other.textButtonTheme == textButtonTheme + && other.elevatedButtonTheme == elevatedButtonTheme + && other.outlinedButtonTheme == outlinedButtonTheme + && other.textSelectionTheme == textSelectionTheme + && other.dataTableTheme == dataTableTheme + && other.checkboxTheme == checkboxTheme + && other.radioTheme == radioTheme + && other.switchTheme == switchTheme + && other.progressIndicatorTheme == progressIndicatorTheme + && other.drawerTheme == drawerTheme + && other.listTileTheme == listTileTheme + && other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel + && other.useTextSelectionTheme == useTextSelectionTheme + && other.androidOverscrollIndicator == androidOverscrollIndicator; } @override @@ -2061,94 +1887,88 @@ class ThemeData with Diagnosticable { // are in the exact same order as in operator == and in the raw constructor // and in the order of fields in the class and in the lerp() method. final List values = [ - // GENERAL CONFIGURATION - androidOverscrollIndicator, - applyElevationOverlayColor, - cupertinoOverrideTheme, - inputDecorationTheme, - materialTapTargetSize, - pageTransitionsTheme, - platform, - scrollbarTheme, - splashFactory, visualDensity, - useMaterial3, - // COLOR - colorScheme, primaryColor, + primaryColorBrightness, primaryColorLight, primaryColorDark, - focusColor, - hoverColor, - shadowColor, canvasColor, + shadowColor, + accentColor, + accentColorBrightness, scaffoldBackgroundColor, bottomAppBarColor, cardColor, dividerColor, + focusColor, + hoverColor, highlightColor, splashColor, + splashFactory, selectedRowColor, unselectedWidgetColor, disabledColor, + buttonTheme, + buttonColor, + toggleButtonsTheme, secondaryHeaderColor, + textSelectionColor, + cursorColor, + textSelectionHandleColor, backgroundColor, dialogBackgroundColor, indicatorColor, hintColor, errorColor, toggleableActiveColor, - // TYPOGRAPHY & ICONOGRAPHY - typography, textTheme, primaryTextTheme, + accentTextTheme, + inputDecorationTheme, iconTheme, primaryIconTheme, - // COMPONENT THEMES - appBarTheme, - bannerTheme, - bottomAppBarTheme, - bottomNavigationBarTheme, - bottomSheetTheme, - buttonBarTheme, - buttonTheme, + accentIconTheme, + sliderTheme, + tabBarTheme, + tooltipTheme, cardTheme, - checkboxTheme, chipTheme, - dataTableTheme, + platform, + materialTapTargetSize, + applyElevationOverlayColor, + pageTransitionsTheme, + appBarTheme, + scrollbarTheme, + bottomAppBarTheme, + colorScheme, dialogTheme, - dividerTheme, - drawerTheme, - elevatedButtonTheme, floatingActionButtonTheme, - listTileTheme, navigationBarTheme, navigationRailTheme, - outlinedButtonTheme, - popupMenuTheme, - progressIndicatorTheme, - radioTheme, - sliderTheme, + typography, + cupertinoOverrideTheme, snackBarTheme, - switchTheme, - tabBarTheme, + bottomSheetTheme, + popupMenuTheme, + bannerTheme, + dividerTheme, + buttonBarTheme, + bottomNavigationBarTheme, + timePickerTheme, textButtonTheme, + elevatedButtonTheme, + outlinedButtonTheme, textSelectionTheme, - timePickerTheme, - toggleButtonsTheme, - tooltipTheme, - // DEPRECATED (newest deprecations at the bottom) - useTextSelectionTheme, - textSelectionColor, - cursorColor, - textSelectionHandleColor, - accentColor, - accentColorBrightness, - accentTextTheme, - accentIconTheme, - buttonColor, + dataTableTheme, + checkboxTheme, + radioTheme, + switchTheme, + progressIndicatorTheme, + drawerTheme, + listTileTheme, fixTextFieldOutlineLabel, - primaryColorBrightness, + useTextSelectionTheme, + androidOverscrollIndicator, ]; return hashList(values); } @@ -2157,94 +1977,88 @@ class ThemeData with Diagnosticable { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); final ThemeData defaultData = ThemeData.fallback(); - // GENERAL CONFIGURATION - properties.add(EnumProperty('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('applyElevationOverlayColor', applyElevationOverlayColor, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('cupertinoOverrideTheme', cupertinoOverrideTheme, defaultValue: defaultData.cupertinoOverrideTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('inputDecorationTheme', inputDecorationTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('materialTapTargetSize', materialTapTargetSize, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('pageTransitionsTheme', pageTransitionsTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('visualDensity', visualDensity, level: DiagnosticLevel.debug)); properties.add(EnumProperty('platform', platform, defaultValue: defaultTargetPlatform, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('scrollbarTheme', scrollbarTheme, defaultValue: defaultData.scrollbarTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('splashFactory', splashFactory, defaultValue: defaultData.splashFactory, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('visualDensity', visualDensity, defaultValue: defaultData.visualDensity, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('useMaterial3', useMaterial3, defaultValue: defaultData.useMaterial3, level: DiagnosticLevel.debug)); - // COLORS - properties.add(DiagnosticsProperty('colorScheme', colorScheme, defaultValue: defaultData.colorScheme, level: DiagnosticLevel.debug)); properties.add(ColorProperty('primaryColor', primaryColor, defaultValue: defaultData.primaryColor, level: DiagnosticLevel.debug)); + properties.add(EnumProperty('primaryColorBrightness', primaryColorBrightness, defaultValue: defaultData.primaryColorBrightness, level: DiagnosticLevel.debug)); properties.add(ColorProperty('primaryColorLight', primaryColorLight, defaultValue: defaultData.primaryColorLight, level: DiagnosticLevel.debug)); properties.add(ColorProperty('primaryColorDark', primaryColorDark, defaultValue: defaultData.primaryColorDark, level: DiagnosticLevel.debug)); - properties.add(ColorProperty('focusColor', focusColor, defaultValue: defaultData.focusColor, level: DiagnosticLevel.debug)); - properties.add(ColorProperty('hoverColor', hoverColor, defaultValue: defaultData.hoverColor, level: DiagnosticLevel.debug)); - properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: defaultData.shadowColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('accentColor', accentColor, defaultValue: defaultData.accentColor, level: DiagnosticLevel.debug)); + properties.add(EnumProperty('accentColorBrightness', accentColorBrightness, defaultValue: defaultData.accentColorBrightness, level: DiagnosticLevel.debug)); properties.add(ColorProperty('canvasColor', canvasColor, defaultValue: defaultData.canvasColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: defaultData.shadowColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('scaffoldBackgroundColor', scaffoldBackgroundColor, defaultValue: defaultData.scaffoldBackgroundColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('bottomAppBarColor', bottomAppBarColor, defaultValue: defaultData.bottomAppBarColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('cardColor', cardColor, defaultValue: defaultData.cardColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('dividerColor', dividerColor, defaultValue: defaultData.dividerColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('focusColor', focusColor, defaultValue: defaultData.focusColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('hoverColor', hoverColor, defaultValue: defaultData.hoverColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('highlightColor', highlightColor, defaultValue: defaultData.highlightColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('splashColor', splashColor, defaultValue: defaultData.splashColor, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('splashFactory', splashFactory, defaultValue: defaultData.splashFactory, level: DiagnosticLevel.debug)); properties.add(ColorProperty('selectedRowColor', selectedRowColor, defaultValue: defaultData.selectedRowColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('unselectedWidgetColor', unselectedWidgetColor, defaultValue: defaultData.unselectedWidgetColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('disabledColor', disabledColor, defaultValue: defaultData.disabledColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('buttonColor', buttonColor, defaultValue: defaultData.buttonColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('secondaryHeaderColor', secondaryHeaderColor, defaultValue: defaultData.secondaryHeaderColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('textSelectionColor', textSelectionColor, defaultValue: defaultData.textSelectionColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('cursorColor', cursorColor, defaultValue: defaultData.cursorColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('textSelectionHandleColor', textSelectionHandleColor, defaultValue: defaultData.textSelectionHandleColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: defaultData.backgroundColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('dialogBackgroundColor', dialogBackgroundColor, defaultValue: defaultData.dialogBackgroundColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('indicatorColor', indicatorColor, defaultValue: defaultData.indicatorColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('hintColor', hintColor, defaultValue: defaultData.hintColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('errorColor', errorColor, defaultValue: defaultData.errorColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('toggleableActiveColor', toggleableActiveColor, defaultValue: defaultData.toggleableActiveColor, level: DiagnosticLevel.debug)); - // TYPOGRAPHY & ICONOGRAPHY - properties.add(DiagnosticsProperty('typography', typography, defaultValue: defaultData.typography, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('buttonTheme', buttonTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('toggleButtonsTheme', toggleButtonsTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('textTheme', textTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('primaryTextTheme', primaryTextTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('accentTextTheme', accentTextTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('inputDecorationTheme', inputDecorationTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('iconTheme', iconTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('primaryIconTheme', primaryIconTheme, level: DiagnosticLevel.debug)); - // COMPONENT THEMES - properties.add(DiagnosticsProperty('appBarTheme', appBarTheme, defaultValue: defaultData.appBarTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('bannerTheme', bannerTheme, defaultValue: defaultData.bannerTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('bottomAppBarTheme', bottomAppBarTheme, defaultValue: defaultData.bottomAppBarTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('bottomNavigationBarTheme', bottomNavigationBarTheme, defaultValue: defaultData.bottomNavigationBarTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('bottomSheetTheme', bottomSheetTheme, defaultValue: defaultData.bottomSheetTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('buttonBarTheme', buttonBarTheme, defaultValue: defaultData.buttonBarTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('buttonTheme', buttonTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('accentIconTheme', accentIconTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('sliderTheme', sliderTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('tabBarTheme', tabBarTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('tooltipTheme', tooltipTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('cardTheme', cardTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('checkboxTheme', checkboxTheme, defaultValue: defaultData.checkboxTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('chipTheme', chipTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('dataTableTheme', dataTableTheme, defaultValue: defaultData.dataTableTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('materialTapTargetSize', materialTapTargetSize, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('applyElevationOverlayColor', applyElevationOverlayColor, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('pageTransitionsTheme', pageTransitionsTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('appBarTheme', appBarTheme, defaultValue: defaultData.appBarTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('scrollbarTheme', scrollbarTheme, defaultValue: defaultData.scrollbarTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('bottomAppBarTheme', bottomAppBarTheme, defaultValue: defaultData.bottomAppBarTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('colorScheme', colorScheme, defaultValue: defaultData.colorScheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('dialogTheme', dialogTheme, defaultValue: defaultData.dialogTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('dividerTheme', dividerTheme, defaultValue: defaultData.dividerTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('drawerTheme', drawerTheme, defaultValue: defaultData.drawerTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('elevatedButtonTheme', elevatedButtonTheme, defaultValue: defaultData.elevatedButtonTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('floatingActionButtonTheme', floatingActionButtonTheme, defaultValue: defaultData.floatingActionButtonTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('listTileTheme', listTileTheme, defaultValue: defaultData.listTileTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('navigationBarTheme', navigationBarTheme, defaultValue: defaultData.navigationBarTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('navigationRailTheme', navigationRailTheme, defaultValue: defaultData.navigationRailTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('outlinedButtonTheme', outlinedButtonTheme, defaultValue: defaultData.outlinedButtonTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('typography', typography, defaultValue: defaultData.typography, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('cupertinoOverrideTheme', cupertinoOverrideTheme, defaultValue: defaultData.cupertinoOverrideTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('snackBarTheme', snackBarTheme, defaultValue: defaultData.snackBarTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('bottomSheetTheme', bottomSheetTheme, defaultValue: defaultData.bottomSheetTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('popupMenuTheme', popupMenuTheme, defaultValue: defaultData.popupMenuTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('progressIndicatorTheme', progressIndicatorTheme, defaultValue: defaultData.progressIndicatorTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('bannerTheme', bannerTheme, defaultValue: defaultData.bannerTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('dividerTheme', dividerTheme, defaultValue: defaultData.dividerTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('buttonBarTheme', buttonBarTheme, defaultValue: defaultData.buttonBarTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('timePickerTheme', timePickerTheme, defaultValue: defaultData.timePickerTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('textSelectionTheme', textSelectionTheme, defaultValue: defaultData.textSelectionTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('bottomNavigationBarTheme', bottomNavigationBarTheme, defaultValue: defaultData.bottomNavigationBarTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('textButtonTheme', textButtonTheme, defaultValue: defaultData.textButtonTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('elevatedButtonTheme', elevatedButtonTheme, defaultValue: defaultData.elevatedButtonTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('outlinedButtonTheme', outlinedButtonTheme, defaultValue: defaultData.outlinedButtonTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('dataTableTheme', dataTableTheme, defaultValue: defaultData.dataTableTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('checkboxTheme', checkboxTheme, defaultValue: defaultData.checkboxTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('radioTheme', radioTheme, defaultValue: defaultData.radioTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('sliderTheme', sliderTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('snackBarTheme', snackBarTheme, defaultValue: defaultData.snackBarTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('switchTheme', switchTheme, defaultValue: defaultData.switchTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('tabBarTheme', tabBarTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('textButtonTheme', textButtonTheme, defaultValue: defaultData.textButtonTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('textSelectionTheme', textSelectionTheme, defaultValue: defaultData.textSelectionTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('timePickerTheme', timePickerTheme, defaultValue: defaultData.timePickerTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('toggleButtonsTheme', toggleButtonsTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('tooltipTheme', tooltipTheme, level: DiagnosticLevel.debug)); - // DEPRECATED (newest deprecations at the bottom) - properties.add(DiagnosticsProperty('useTextSelectionTheme', useTextSelectionTheme, level: DiagnosticLevel.debug)); - properties.add(ColorProperty('textSelectionColor', textSelectionColor, defaultValue: defaultData.textSelectionColor, level: DiagnosticLevel.debug)); - properties.add(ColorProperty('cursorColor', cursorColor, defaultValue: defaultData.cursorColor, level: DiagnosticLevel.debug)); - properties.add(ColorProperty('textSelectionHandleColor', textSelectionHandleColor, defaultValue: defaultData.textSelectionHandleColor, level: DiagnosticLevel.debug)); - properties.add(ColorProperty('accentColor', accentColor, defaultValue: defaultData.accentColor, level: DiagnosticLevel.debug)); - properties.add(EnumProperty('accentColorBrightness', accentColorBrightness, defaultValue: defaultData.accentColorBrightness, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('accentTextTheme', accentTextTheme, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('accentIconTheme', accentIconTheme, level: DiagnosticLevel.debug)); - properties.add(ColorProperty('buttonColor', buttonColor, defaultValue: defaultData.buttonColor, level: DiagnosticLevel.debug)); - properties.add(DiagnosticsProperty('fixTextFieldOutlineLabel', fixTextFieldOutlineLabel, level: DiagnosticLevel.debug)); - properties.add(EnumProperty('primaryColorBrightness', primaryColorBrightness, defaultValue: defaultData.primaryColorBrightness, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('progressIndicatorTheme', progressIndicatorTheme, defaultValue: defaultData.progressIndicatorTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('drawerTheme', drawerTheme, defaultValue: defaultData.drawerTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('listTileTheme', listTileTheme, defaultValue: defaultData.listTileTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('fixTextFieldOutlineLabel', fixTextFieldOutlineLabel, defaultValue: true, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('useTextSelectionTheme', useTextSelectionTheme, defaultValue: true, level: DiagnosticLevel.debug)); + properties.add(EnumProperty('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug)); } } @@ -2472,7 +2286,6 @@ class VisualDensity with Diagnosticable { }) : assert(horizontal != null), assert(vertical != null), assert(vertical <= maximumDensity), - assert(vertical <= maximumDensity), assert(vertical >= minimumDensity), assert(horizontal <= maximumDensity), assert(horizontal >= minimumDensity); diff --git a/packages/flutter/lib/src/material/toggle_buttons.dart b/packages/flutter/lib/src/material/toggle_buttons.dart index f4c23dcf6323c..9234050434ec8 100644 --- a/packages/flutter/lib/src/material/toggle_buttons.dart +++ b/packages/flutter/lib/src/material/toggle_buttons.dart @@ -172,7 +172,6 @@ class ToggleButtons extends StatelessWidget { required this.isSelected, this.onPressed, this.mouseCursor, - this.tapTargetSize, this.textStyle, this.constraints, this.color, @@ -232,15 +231,6 @@ class ToggleButtons extends StatelessWidget { /// {@macro flutter.material.RawMaterialButton.mouseCursor} final MouseCursor? mouseCursor; - /// Configures the minimum size of the area within which the buttons may - /// be pressed. - /// - /// If the [tapTargetSize] is larger than [constraints], the buttons will - /// include a transparent margin that responds to taps. - /// - /// Defaults to [ThemeData.materialTapTargetSize]. - final MaterialTapTargetSize? tapTargetSize; - /// The [TextStyle] to apply to any text in these toggle buttons. /// /// [TextStyle.color] will be ignored and substituted by [color], @@ -696,7 +686,7 @@ class ToggleButtons extends StatelessWidget { ); }); - final Widget result = direction == Axis.horizontal + return direction == Axis.horizontal ? IntrinsicHeight( child: Row( mainAxisSize: MainAxisSize.min, @@ -712,18 +702,6 @@ class ToggleButtons extends StatelessWidget { children: buttons, ), ); - - final MaterialTapTargetSize resolvedTapTargetSize = tapTargetSize ?? theme.materialTapTargetSize; - switch (resolvedTapTargetSize) { - case MaterialTapTargetSize.padded: - return _InputPadding( - minSize: const Size(kMinInteractiveDimension, kMinInteractiveDimension), - direction: direction, - child: result, - ); - case MaterialTapTargetSize.shrinkWrap: - return result; - } } @override @@ -1572,141 +1550,3 @@ class _SelectToggleButtonRenderObject extends RenderShiftedBox { } } } - -/// A widget to pad the area around a [ToggleButtons]'s children. -/// -/// This widget is based on a similar one used in [ButtonStyleButton] but it -/// only redirects taps along one axis to ensure the correct button is tapped -/// within the [ToggleButtons]. -/// -/// This ensures that a widget takes up at least as much space as the minSize -/// parameter to ensure adequate tap target size, while keeping the widget -/// visually smaller to the user. -class _InputPadding extends SingleChildRenderObjectWidget { - const _InputPadding({ - Key? key, - Widget? child, - required this.minSize, - required this.direction, - }) : super(key: key, child: child); - - final Size minSize; - final Axis direction; - - @override - RenderObject createRenderObject(BuildContext context) { - return _RenderInputPadding(minSize, direction); - } - - @override - void updateRenderObject(BuildContext context, covariant _RenderInputPadding renderObject) { - renderObject.minSize = minSize; - renderObject.direction = direction; - } -} - -class _RenderInputPadding extends RenderShiftedBox { - _RenderInputPadding(this._minSize, this._direction, [RenderBox? child]) : super(child); - - Size get minSize => _minSize; - Size _minSize; - set minSize(Size value) { - if (_minSize == value) - return; - _minSize = value; - markNeedsLayout(); - } - - Axis get direction => _direction; - Axis _direction; - set direction(Axis value) { - if (_direction == value) - return; - _direction = value; - markNeedsLayout(); - } - - @override - double computeMinIntrinsicWidth(double height) { - if (child != null) - return math.max(child!.getMinIntrinsicWidth(height), minSize.width); - return 0.0; - } - - @override - double computeMinIntrinsicHeight(double width) { - if (child != null) - return math.max(child!.getMinIntrinsicHeight(width), minSize.height); - return 0.0; - } - - @override - double computeMaxIntrinsicWidth(double height) { - if (child != null) - return math.max(child!.getMaxIntrinsicWidth(height), minSize.width); - return 0.0; - } - - @override - double computeMaxIntrinsicHeight(double width) { - if (child != null) - return math.max(child!.getMaxIntrinsicHeight(width), minSize.height); - return 0.0; - } - - Size _computeSize({required BoxConstraints constraints, required ChildLayouter layoutChild}) { - if (child != null) { - final Size childSize = layoutChild(child!, constraints); - final double height = math.max(childSize.width, minSize.width); - final double width = math.max(childSize.height, minSize.height); - return constraints.constrain(Size(height, width)); - } - return Size.zero; - } - - @override - Size computeDryLayout(BoxConstraints constraints) { - return _computeSize( - constraints: constraints, - layoutChild: ChildLayoutHelper.dryLayoutChild, - ); - } - - @override - void performLayout() { - size = _computeSize( - constraints: constraints, - layoutChild: ChildLayoutHelper.layoutChild, - ); - if (child != null) { - final BoxParentData childParentData = child!.parentData! as BoxParentData; - childParentData.offset = Alignment.center.alongOffset(size - child!.size as Offset); - } - } - - @override - bool hitTest(BoxHitTestResult result, { required Offset position }) { - // The super.hitTest() method also checks hitTestChildren(). We don't - // want that in this case because we've padded around the children per - // tapTargetSize. - if (!size.contains(position)) { - return false; - } - - // Only adjust one axis to ensure the correct button is tapped. - Offset center; - if (direction == Axis.horizontal) { - center = Offset(position.dx, child!.size.height / 2); - } else { - center = Offset(child!.size.width / 2, position.dy); - } - return result.addWithRawTransform( - transform: MatrixUtils.forceToPoint(center), - position: center, - hitTest: (BoxHitTestResult result, Offset position) { - assert(position == center); - return child!.hitTest(result, position: center); - }, - ); - } -} diff --git a/packages/flutter/lib/src/material/toggleable.dart b/packages/flutter/lib/src/material/toggleable.dart index 284321fad0618..6b5c7b3445627 100644 --- a/packages/flutter/lib/src/material/toggleable.dart +++ b/packages/flutter/lib/src/material/toggleable.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; @@ -590,7 +589,4 @@ abstract class ToggleablePainter extends ChangeNotifier implements CustomPainter @override bool shouldRebuildSemantics(covariant CustomPainter oldDelegate) => false; - - @override - String toString() => describeIdentity(this); } diff --git a/packages/flutter/lib/src/material/typography.dart b/packages/flutter/lib/src/material/typography.dart index 35cc0dc259bf6..cf44598e709b7 100644 --- a/packages/flutter/lib/src/material/typography.dart +++ b/packages/flutter/lib/src/material/typography.dart @@ -332,84 +332,76 @@ class Typography with Diagnosticable { /// /// This [TextTheme] provides color but not geometry (font size, weight, etc). static const TextTheme blackMountainView = TextTheme( - displayLarge : TextStyle(debugLabel: 'blackMountainView displayLarge', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'blackMountainView displayMedium', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'blackMountainView displaySmall', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'blackMountainView headlineLarge', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'blackMountainView headlineMedium', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'blackMountainView headlineSmall', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'blackMountainView titleLarge', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'blackMountainView titleMedium', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'blackMountainView titleSmall', fontFamily: 'Roboto', color: Colors.black, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'blackMountainView bodyLarge', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'blackMountainView bodyMedium', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'blackMountainView bodySmall', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'blackMountainView labelLarge', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'blackMountainView labelMedium', fontFamily: 'Roboto', color: Colors.black, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'blackMountainView labelSmall', fontFamily: 'Roboto', color: Colors.black, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'blackMountainView headline1', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'blackMountainView headline2', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'blackMountainView headline3', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'blackMountainView headline4', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'blackMountainView headline5', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'blackMountainView headline6', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'blackMountainView bodyText1', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'blackMountainView bodyText2', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'blackMountainView subtitle1', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'blackMountainView subtitle2', fontFamily: 'Roboto', color: Colors.black, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'blackMountainView caption', fontFamily: 'Roboto', color: Colors.black54, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'blackMountainView button', fontFamily: 'Roboto', color: Colors.black87, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'blackMountainView overline', fontFamily: 'Roboto', color: Colors.black, decoration: TextDecoration.none), ); /// A material design text theme with light glyphs based on Roboto. /// /// This [TextTheme] provides color but not geometry (font size, weight, etc). static const TextTheme whiteMountainView = TextTheme( - displayLarge : TextStyle(debugLabel: 'whiteMountainView displayLarge', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'whiteMountainView displayMedium', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'whiteMountainView displaySmall', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'whiteMountainView headlineLarge', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'whiteMountainView headlineMedium', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'whiteMountainView headlineSmall', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'whiteMountainView titleLarge', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'whiteMountainView titleMedium', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'whiteMountainView titleSmall', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'whiteMountainView bodyLarge', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'whiteMountainView bodyMedium', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'whiteMountainView bodySmall', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'whiteMountainView labelLarge', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'whiteMountainView labelMedium', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'whiteMountainView labelSmall', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'whiteMountainView headline1', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'whiteMountainView headline2', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'whiteMountainView headline3', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'whiteMountainView headline4', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'whiteMountainView headline5', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'whiteMountainView headline6', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'whiteMountainView bodyText1', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'whiteMountainView bodyText2', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'whiteMountainView subtitle1', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'whiteMountainView subtitle2', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'whiteMountainView caption', fontFamily: 'Roboto', color: Colors.white70, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'whiteMountainView button', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'whiteMountainView overline', fontFamily: 'Roboto', color: Colors.white, decoration: TextDecoration.none), ); /// A material design text theme with dark glyphs based on Segoe UI. /// /// This [TextTheme] provides color but not geometry (font size, weight, etc). static const TextTheme blackRedmond = TextTheme( - displayLarge : TextStyle(debugLabel: 'blackRedmond displayLarge', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'blackRedmond displayMedium', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'blackRedmond displaySmall', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'blackRedmond headlineLarge', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'blackRedmond headlineMedium', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'blackRedmond headlineSmall', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'blackRedmond titleLarge', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'blackRedmond titleMedium', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'blackRedmond titleSmall', fontFamily: 'Segoe UI', color: Colors.black, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'blackRedmond bodyLarge', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'blackRedmond bodyMedium', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'blackRedmond bodySmall', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'blackRedmond labelLarge', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'blackRedmond labelMedium', fontFamily: 'Segoe UI', color: Colors.black, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'blackRedmond labelSmall', fontFamily: 'Segoe UI', color: Colors.black, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'blackRedmond headline1', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'blackRedmond headline2', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'blackRedmond headline3', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'blackRedmond headline4', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'blackRedmond headline5', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'blackRedmond headline6', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'blackRedmond bodyText1', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'blackRedmond bodyText2', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'blackRedmond subtitle1', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'blackRedmond subtitle2', fontFamily: 'Segoe UI', color: Colors.black, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'blackRedmond caption', fontFamily: 'Segoe UI', color: Colors.black54, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'blackRedmond button', fontFamily: 'Segoe UI', color: Colors.black87, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'blackRedmond overline', fontFamily: 'Segoe UI', color: Colors.black, decoration: TextDecoration.none), ); /// A material design text theme with light glyphs based on Segoe UI. /// /// This [TextTheme] provides color but not geometry (font size, weight, etc). static const TextTheme whiteRedmond = TextTheme( - displayLarge : TextStyle(debugLabel: 'whiteRedmond displayLarge', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'whiteRedmond displayMedium', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'whiteRedmond displaySmall', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'whiteRedmond headlineLarge', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'whiteRedmond headlineMedium', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'whiteRedmond headlineSmall', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'whiteRedmond titleLarge', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'whiteRedmond titleMedium', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'whiteRedmond titleSmall', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'whiteRedmond bodyLarge', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'whiteRedmond bodyMedium', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'whiteRedmond bodySmall', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'whiteRedmond labelLarge', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'whiteRedmond labelMedium', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'whiteRedmond labelSmall', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'whiteRedmond headline1', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'whiteRedmond headline2', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'whiteRedmond headline3', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'whiteRedmond headline4', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'whiteRedmond headline5', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'whiteRedmond headline6', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'whiteRedmond bodyText1', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'whiteRedmond bodyText2', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'whiteRedmond subtitle1', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'whiteRedmond subtitle2', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'whiteRedmond caption', fontFamily: 'Segoe UI', color: Colors.white70, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'whiteRedmond button', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'whiteRedmond overline', fontFamily: 'Segoe UI', color: Colors.white, decoration: TextDecoration.none), ); static const List _helsinkiFontFallbacks = ['Ubuntu', 'Cantarell', 'DejaVu Sans', 'Liberation Sans', 'Arial']; @@ -419,42 +411,38 @@ class Typography with Diagnosticable { /// /// This [TextTheme] provides color but not geometry (font size, weight, etc). static const TextTheme blackHelsinki = TextTheme( - displayLarge : TextStyle(debugLabel: 'blackHelsinki displayLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'blackHelsinki displayMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'blackHelsinki displaySmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'blackHelsinki headlineLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'blackHelsinki headlineMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'blackHelsinki headlineSmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'blackHelsinki titleLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'blackHelsinki titleMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'blackHelsinki titleSmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'blackHelsinki bodyLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'blackHelsinki bodyMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'blackHelsinki bodySmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'blackHelsinki labelLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'blackHelsinki labelMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'blackHelsinki labelSmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'blackHelsinki headline1', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'blackHelsinki headline2', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'blackHelsinki headline3', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'blackHelsinki headline4', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'blackHelsinki headline5', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'blackHelsinki headline6', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'blackHelsinki bodyText1', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'blackHelsinki bodyText2', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'blackHelsinki subtitle1', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'blackHelsinki subtitle2', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'blackHelsinki caption', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black54, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'blackHelsinki button', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black87, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'blackHelsinki overline', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.black, decoration: TextDecoration.none), ); /// A material design text theme with light glyphs based on Roboto, with fallbacks of DejaVu Sans, Liberation Sans and Arial. /// /// This [TextTheme] provides color but not geometry (font size, weight, etc). static const TextTheme whiteHelsinki = TextTheme( - displayLarge : TextStyle(debugLabel: 'whiteHelsinki displayLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'whiteHelsinki displayMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'whiteHelsinki displaySmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'whiteHelsinki headlineLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'whiteHelsinki headlineMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'whiteHelsinki headlineSmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'whiteHelsinki titleLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'whiteHelsinki titleMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'whiteHelsinki titleSmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'whiteHelsinki bodyLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'whiteHelsinki bodyMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'whiteHelsinki bodySmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'whiteHelsinki labelLarge', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'whiteHelsinki labelMedium', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'whiteHelsinki labelSmall', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'whiteHelsinki headline1', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'whiteHelsinki headline2', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'whiteHelsinki headline3', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'whiteHelsinki headline4', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'whiteHelsinki headline5', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'whiteHelsinki headline6', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'whiteHelsinki bodyText1', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'whiteHelsinki bodyText2', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'whiteHelsinki subtitle1', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'whiteHelsinki subtitle2', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'whiteHelsinki caption', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white70, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'whiteHelsinki button', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'whiteHelsinki overline', fontFamily: 'Roboto', fontFamilyFallback: _helsinkiFontFallbacks, color: Colors.white, decoration: TextDecoration.none), ); /// A material design text theme with dark glyphs based on San Francisco. @@ -463,21 +451,19 @@ class Typography with Diagnosticable { /// /// This theme uses the iOS version of the font names. static const TextTheme blackCupertino = TextTheme( - displayLarge : TextStyle(debugLabel: 'blackCupertino displayLarge', fontFamily: '.SF UI Display', color: Colors.black54, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'blackCupertino displayMedium', fontFamily: '.SF UI Display', color: Colors.black54, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'blackCupertino displaySmall', fontFamily: '.SF UI Display', color: Colors.black54, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'blackCupertino headlineLarge', fontFamily: '.SF UI Display', color: Colors.black54, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'blackCupertino headlineMedium', fontFamily: '.SF UI Display', color: Colors.black54, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'blackCupertino headlineSmall', fontFamily: '.SF UI Display', color: Colors.black87, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'blackCupertino titleLarge', fontFamily: '.SF UI Display', color: Colors.black87, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'blackCupertino titleMedium', fontFamily: '.SF UI Text', color: Colors.black87, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'blackCupertino titleSmall', fontFamily: '.SF UI Text', color: Colors.black, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'blackCupertino bodyLarge', fontFamily: '.SF UI Text', color: Colors.black87, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'blackCupertino bodyMedium', fontFamily: '.SF UI Text', color: Colors.black87, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'blackCupertino bodySmall', fontFamily: '.SF UI Text', color: Colors.black54, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'blackCupertino labelLarge', fontFamily: '.SF UI Text', color: Colors.black87, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'blackCupertino labelMedium', fontFamily: '.SF UI Text', color: Colors.black, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'blackCupertino labelSmall', fontFamily: '.SF UI Text', color: Colors.black, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'blackCupertino headline1', fontFamily: '.SF UI Display', color: Colors.black54, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'blackCupertino headline2', fontFamily: '.SF UI Display', color: Colors.black54, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'blackCupertino headline3', fontFamily: '.SF UI Display', color: Colors.black54, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'blackCupertino headline4', fontFamily: '.SF UI Display', color: Colors.black54, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'blackCupertino headline5', fontFamily: '.SF UI Display', color: Colors.black87, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'blackCupertino headline6', fontFamily: '.SF UI Display', color: Colors.black87, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'blackCupertino bodyText1', fontFamily: '.SF UI Text', color: Colors.black87, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'blackCupertino bodyText2', fontFamily: '.SF UI Text', color: Colors.black87, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'blackCupertino subtitle1', fontFamily: '.SF UI Text', color: Colors.black87, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'blackCupertino subtitle2', fontFamily: '.SF UI Text', color: Colors.black, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'blackCupertino caption', fontFamily: '.SF UI Text', color: Colors.black54, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'blackCupertino button', fontFamily: '.SF UI Text', color: Colors.black87, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'blackCupertino overline', fontFamily: '.SF UI Text', color: Colors.black, decoration: TextDecoration.none), ); /// A material design text theme with light glyphs based on San Francisco. @@ -486,21 +472,19 @@ class Typography with Diagnosticable { /// /// This theme uses the iOS version of the font names. static const TextTheme whiteCupertino = TextTheme( - displayLarge : TextStyle(debugLabel: 'whiteCupertino displayLarge', fontFamily: '.SF UI Display', color: Colors.white70, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'whiteCupertino displayMedium', fontFamily: '.SF UI Display', color: Colors.white70, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'whiteCupertino displaySmall', fontFamily: '.SF UI Display', color: Colors.white70, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'whiteCupertino headlineLarge', fontFamily: '.SF UI Display', color: Colors.white70, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'whiteCupertino headlineMedium', fontFamily: '.SF UI Display', color: Colors.white70, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'whiteCupertino headlineSmall', fontFamily: '.SF UI Display', color: Colors.white, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'whiteCupertino titleLarge', fontFamily: '.SF UI Display', color: Colors.white, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'whiteCupertino titleMedium', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'whiteCupertino titleSmall', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'whiteCupertino bodyLarge', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'whiteCupertino bodyMedium', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'whiteCupertino bodySmall', fontFamily: '.SF UI Text', color: Colors.white70, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'whiteCupertino labelLarge', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'whiteCupertino labelMedium', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'whiteCupertino labelSmall', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'whiteCupertino headline1', fontFamily: '.SF UI Display', color: Colors.white70, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'whiteCupertino headline2', fontFamily: '.SF UI Display', color: Colors.white70, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'whiteCupertino headline3', fontFamily: '.SF UI Display', color: Colors.white70, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'whiteCupertino headline4', fontFamily: '.SF UI Display', color: Colors.white70, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'whiteCupertino headline5', fontFamily: '.SF UI Display', color: Colors.white, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'whiteCupertino headline6', fontFamily: '.SF UI Display', color: Colors.white, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'whiteCupertino subtitle1', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'whiteCupertino bodyText1', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'whiteCupertino bodyText2', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'whiteCupertino caption', fontFamily: '.SF UI Text', color: Colors.white70, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'whiteCupertino button', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'whiteCupertino subtitle2', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'whiteCupertino overline', fontFamily: '.SF UI Text', color: Colors.white, decoration: TextDecoration.none), ); /// A material design text theme with dark glyphs based on San Francisco. @@ -509,21 +493,19 @@ class Typography with Diagnosticable { /// /// This theme uses the macOS version of the font names. static const TextTheme blackRedwoodCity = TextTheme( - displayLarge : TextStyle(debugLabel: 'blackRedwoodCity displayLarge', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'blackRedwoodCity displayMedium', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'blackRedwoodCity displaySmall', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'blackRedwoodCity headlineLarge', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'blackRedwoodCity headlineMedium', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'blackRedwoodCity headlineSmall', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'blackRedwoodCity titleLarge', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'blackRedwoodCity titleMedium', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'blackRedwoodCity titleSmall', fontFamily: '.AppleSystemUIFont', color: Colors.black, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'blackRedwoodCity bodyLarge', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'blackRedwoodCity bodyMedium', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'blackRedwoodCity bodySmall', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'blackRedwoodCity labelLarge', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'blackRedwoodCity labelMedium', fontFamily: '.AppleSystemUIFont', color: Colors.black, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'blackRedwoodCity labelSmall', fontFamily: '.AppleSystemUIFont', color: Colors.black, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'blackRedwoodCity headline1', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'blackRedwoodCity headline2', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'blackRedwoodCity headline3', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'blackRedwoodCity headline4', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'blackRedwoodCity headline5', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'blackRedwoodCity headline6', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'blackRedwoodCity bodyText1', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'blackRedwoodCity bodyText2', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'blackRedwoodCity subtitle1', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'blackRedwoodCity subtitle2', fontFamily: '.AppleSystemUIFont', color: Colors.black, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'blackRedwoodCity caption', fontFamily: '.AppleSystemUIFont', color: Colors.black54, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'blackRedwoodCity button', fontFamily: '.AppleSystemUIFont', color: Colors.black87, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'blackRedwoodCity overline', fontFamily: '.AppleSystemUIFont', color: Colors.black, decoration: TextDecoration.none), ); /// A material design text theme with light glyphs based on San Francisco. @@ -532,147 +514,133 @@ class Typography with Diagnosticable { /// /// This theme uses the macOS version of the font names. static const TextTheme whiteRedwoodCity = TextTheme( - displayLarge : TextStyle(debugLabel: 'whiteRedwoodCity displayLarge', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), - displayMedium : TextStyle(debugLabel: 'whiteRedwoodCity displayMedium', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), - displaySmall : TextStyle(debugLabel: 'whiteRedwoodCity displaySmall', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), - headlineLarge : TextStyle(debugLabel: 'whiteRedwoodCity headlineLarge', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), - headlineMedium : TextStyle(debugLabel: 'whiteRedwoodCity headlineMedium', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), - headlineSmall : TextStyle(debugLabel: 'whiteRedwoodCity headlineSmall', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), - titleLarge : TextStyle(debugLabel: 'whiteRedwoodCity titleLarge', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), - titleMedium : TextStyle(debugLabel: 'whiteRedwoodCity titleMedium', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), - titleSmall : TextStyle(debugLabel: 'whiteRedwoodCity titleSmall', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), - bodyLarge : TextStyle(debugLabel: 'whiteRedwoodCity bodyLarge', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), - bodyMedium : TextStyle(debugLabel: 'whiteRedwoodCity bodyMedium', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), - bodySmall : TextStyle(debugLabel: 'whiteRedwoodCity bodySmall', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), - labelLarge : TextStyle(debugLabel: 'whiteRedwoodCity labelLarge', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), - labelMedium : TextStyle(debugLabel: 'whiteRedwoodCity labelMedium', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), - labelSmall : TextStyle(debugLabel: 'whiteRedwoodCity labelSmall', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), + headline1 : TextStyle(debugLabel: 'whiteRedwoodCity headline1', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), + headline2 : TextStyle(debugLabel: 'whiteRedwoodCity headline2', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), + headline3 : TextStyle(debugLabel: 'whiteRedwoodCity headline3', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), + headline4 : TextStyle(debugLabel: 'whiteRedwoodCity headline4', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), + headline5 : TextStyle(debugLabel: 'whiteRedwoodCity headline5', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), + headline6 : TextStyle(debugLabel: 'whiteRedwoodCity headline6', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), + subtitle1 : TextStyle(debugLabel: 'whiteRedwoodCity subtitle1', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), + bodyText1 : TextStyle(debugLabel: 'whiteRedwoodCity bodyText1', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), + bodyText2 : TextStyle(debugLabel: 'whiteRedwoodCity bodyText2', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), + caption : TextStyle(debugLabel: 'whiteRedwoodCity caption', fontFamily: '.AppleSystemUIFont', color: Colors.white70, decoration: TextDecoration.none), + button : TextStyle(debugLabel: 'whiteRedwoodCity button', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), + subtitle2 : TextStyle(debugLabel: 'whiteRedwoodCity subtitle2', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), + overline : TextStyle(debugLabel: 'whiteRedwoodCity overline', fontFamily: '.AppleSystemUIFont', color: Colors.white, decoration: TextDecoration.none), ); /// Defines text geometry for [ScriptCategory.englishLike] scripts, such as /// English, French, Russian, etc. static const TextTheme englishLike2014 = TextTheme( - displayLarge : TextStyle(debugLabel: 'englishLike displayLarge 2014', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.alphabetic), - displayMedium : TextStyle(debugLabel: 'englishLike displayMedium 2014', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - displaySmall : TextStyle(debugLabel: 'englishLike displaySmall 2014', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineLarge : TextStyle(debugLabel: 'englishLike headlineLarge 2014', inherit: false, fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineMedium : TextStyle(debugLabel: 'englishLike headlineMedium 2014', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineSmall : TextStyle(debugLabel: 'englishLike headlineSmall 2014', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - titleLarge : TextStyle(debugLabel: 'englishLike titleLarge 2014', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), - titleMedium : TextStyle(debugLabel: 'englishLike titleMedium 2014', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - titleSmall : TextStyle(debugLabel: 'englishLike titleSmall 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.1), - bodyLarge : TextStyle(debugLabel: 'englishLike bodyLarge 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), - bodyMedium : TextStyle(debugLabel: 'englishLike bodyMedium 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - bodySmall : TextStyle(debugLabel: 'englishLike bodySmall 2014', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - labelLarge : TextStyle(debugLabel: 'englishLike labelLarge 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), - labelMedium : TextStyle(debugLabel: 'englishLike labelMedium 2014', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - labelSmall : TextStyle(debugLabel: 'englishLike labelSmall 2014', inherit: false, fontSize: 10.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5), + headline1 : TextStyle(debugLabel: 'englishLike display4 2014', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.alphabetic), + headline2 : TextStyle(debugLabel: 'englishLike display3 2014', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline3 : TextStyle(debugLabel: 'englishLike display2 2014', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline4 : TextStyle(debugLabel: 'englishLike display1 2014', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline5 : TextStyle(debugLabel: 'englishLike headline 2014', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline6 : TextStyle(debugLabel: 'englishLike title 2014', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), + bodyText1 : TextStyle(debugLabel: 'englishLike body2 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), + bodyText2 : TextStyle(debugLabel: 'englishLike body1 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + subtitle1 : TextStyle(debugLabel: 'englishLike subhead 2014', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + subtitle2 : TextStyle(debugLabel: 'englishLike subtitle 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.1), + caption : TextStyle(debugLabel: 'englishLike caption 2014', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + button : TextStyle(debugLabel: 'englishLike button 2014', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), + overline : TextStyle(debugLabel: 'englishLike overline 2014', inherit: false, fontSize: 10.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5), ); /// Defines text geometry for [ScriptCategory.englishLike] scripts, such as /// English, French, Russian, etc. /// /// The font sizes, weights, and letter spacings in this version match the - /// [2018 Material Design specification](https://material.io/go/design-typography#typography-styles). + /// [latest Material Design specification](https://material.io/go/design-typography#typography-styles). static const TextTheme englishLike2018 = TextTheme( - displayLarge : TextStyle(debugLabel: 'englishLike displayLarge 2018', fontSize: 96.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -1.5), - displayMedium : TextStyle(debugLabel: 'englishLike displayMedium 2018', fontSize: 60.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -0.5), - displaySmall : TextStyle(debugLabel: 'englishLike displaySmall 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0), - headlineLarge : TextStyle(debugLabel: 'englishLike headlineLarge 2018', fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), - headlineMedium : TextStyle(debugLabel: 'englishLike headlineMedium 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), - headlineSmall : TextStyle(debugLabel: 'englishLike headlineSmall 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0), - titleLarge : TextStyle(debugLabel: 'englishLike titleLarge 2018', fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15), - titleMedium : TextStyle(debugLabel: 'englishLike titleMedium 2018', fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15), - titleSmall : TextStyle(debugLabel: 'englishLike titleSmall 2018', fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.1), - bodyLarge : TextStyle(debugLabel: 'englishLike bodyLarge 2018', fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.5), - bodyMedium : TextStyle(debugLabel: 'englishLike bodyMedium 2018', fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), - bodySmall : TextStyle(debugLabel: 'englishLike bodySmall 2018', fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.4), - labelLarge : TextStyle(debugLabel: 'englishLike labelLarge 2018', fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.25), - labelMedium : TextStyle(debugLabel: 'englishLike labelMedium 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5), - labelSmall : TextStyle(debugLabel: 'englishLike labelSmall 2018', fontSize: 10.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5), + headline1 : TextStyle(debugLabel: 'englishLike headline1 2018', fontSize: 96.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -1.5), + headline2 : TextStyle(debugLabel: 'englishLike headline2 2018', fontSize: 60.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -0.5), + headline3 : TextStyle(debugLabel: 'englishLike headline3 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0), + headline4 : TextStyle(debugLabel: 'englishLike headline4 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), + headline5 : TextStyle(debugLabel: 'englishLike headline5 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0), + headline6 : TextStyle(debugLabel: 'englishLike headline6 2018', fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15), + bodyText1 : TextStyle(debugLabel: 'englishLike bodyText1 2018', fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.5), + bodyText2 : TextStyle(debugLabel: 'englishLike bodyText2 2018', fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), + subtitle1 : TextStyle(debugLabel: 'englishLike subtitle1 2018', fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15), + subtitle2 : TextStyle(debugLabel: 'englishLike subtitle2 2018', fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.1), + button : TextStyle(debugLabel: 'englishLike button 2018', fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.25), + caption : TextStyle(debugLabel: 'englishLike caption 2018', fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.4), + overline : TextStyle(debugLabel: 'englishLike overline 2018', fontSize: 10.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5), ); /// Defines text geometry for dense scripts, such as Chinese, Japanese /// and Korean. static const TextTheme dense2014 = TextTheme( - displayLarge : TextStyle(debugLabel: 'dense displayLarge 2014', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), - displayMedium : TextStyle(debugLabel: 'dense displayMedium 2014', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - displaySmall : TextStyle(debugLabel: 'dense displaySmall 2014', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - headlineLarge : TextStyle(debugLabel: 'dense headlineLarge 2014', inherit: false, fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - headlineMedium : TextStyle(debugLabel: 'dense headlineMedium 2014', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - headlineSmall : TextStyle(debugLabel: 'dense headlineSmall 2014', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - titleLarge : TextStyle(debugLabel: 'dense titleLarge 2014', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - titleMedium : TextStyle(debugLabel: 'dense titleMedium 2014', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - titleSmall : TextStyle(debugLabel: 'dense titleSmall 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - bodyLarge : TextStyle(debugLabel: 'dense bodyLarge 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - bodyMedium : TextStyle(debugLabel: 'dense bodyMedium 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - bodySmall : TextStyle(debugLabel: 'dense bodySmall 2014', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - labelLarge : TextStyle(debugLabel: 'dense labelLarge 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - labelMedium : TextStyle(debugLabel: 'dense labelMedium 2014', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - labelSmall : TextStyle(debugLabel: 'dense labelSmall 2014', inherit: false, fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headline1 : TextStyle(debugLabel: 'dense display4 2014', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), + headline2 : TextStyle(debugLabel: 'dense display3 2014', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headline3 : TextStyle(debugLabel: 'dense display2 2014', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headline4 : TextStyle(debugLabel: 'dense display1 2014', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headline5 : TextStyle(debugLabel: 'dense headline 2014', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headline6 : TextStyle(debugLabel: 'dense title 2014', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + bodyText1 : TextStyle(debugLabel: 'dense body2 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + bodyText2 : TextStyle(debugLabel: 'dense body1 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + subtitle1 : TextStyle(debugLabel: 'dense subhead 2014', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + subtitle2 : TextStyle(debugLabel: 'dense subtitle 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + caption : TextStyle(debugLabel: 'dense caption 2014', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + button : TextStyle(debugLabel: 'dense button 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + overline : TextStyle(debugLabel: 'dense overline 2014', inherit: false, fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), ); /// Defines text geometry for dense scripts, such as Chinese, Japanese /// and Korean. /// /// The font sizes, weights, and letter spacings in this version match the - /// 2018 [Material Design specification](https://material.io/go/design-typography#typography-styles). + /// latest [Material Design specification](https://material.io/go/design-typography#typography-styles). static const TextTheme dense2018 = TextTheme( - displayLarge : TextStyle(debugLabel: 'dense displayLarge 2018', fontSize: 96.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), - displayMedium : TextStyle(debugLabel: 'dense displayMedium 2018', fontSize: 60.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), - displaySmall : TextStyle(debugLabel: 'dense displaySmall 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - headlineLarge : TextStyle(debugLabel: 'dense headlineLarge 2018', fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - headlineMedium : TextStyle(debugLabel: 'dense headlineMedium 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - headlineSmall : TextStyle(debugLabel: 'dense headlineSmall 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - titleLarge : TextStyle(debugLabel: 'dense titleLarge 2018', fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - titleMedium : TextStyle(debugLabel: 'dense titleMedium 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - titleSmall : TextStyle(debugLabel: 'dense titleSmall 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - bodyLarge : TextStyle(debugLabel: 'dense bodyLarge 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - bodyMedium : TextStyle(debugLabel: 'dense bodyMedium 2018', fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - bodySmall : TextStyle(debugLabel: 'dense bodySmall 2018', fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - labelLarge : TextStyle(debugLabel: 'dense labelLarge 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - labelMedium : TextStyle(debugLabel: 'dense labelMedium 2018', fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - labelSmall : TextStyle(debugLabel: 'dense labelSmall 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headline1 : TextStyle(debugLabel: 'dense headline1 2018', fontSize: 96.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), + headline2 : TextStyle(debugLabel: 'dense headline2 2018', fontSize: 60.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), + headline3 : TextStyle(debugLabel: 'dense headline3 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headline4 : TextStyle(debugLabel: 'dense headline4 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headline5 : TextStyle(debugLabel: 'dense headline5 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headline6 : TextStyle(debugLabel: 'dense headline6 2018', fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + bodyText1 : TextStyle(debugLabel: 'dense bodyText1 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + bodyText2 : TextStyle(debugLabel: 'dense bodyText2 2018', fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + subtitle1 : TextStyle(debugLabel: 'dense subtitle1 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + subtitle2 : TextStyle(debugLabel: 'dense subtitle2 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + button : TextStyle(debugLabel: 'dense button 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + caption : TextStyle(debugLabel: 'dense caption 2018', fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + overline : TextStyle(debugLabel: 'dense overline 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), ); /// Defines text geometry for tall scripts, such as Farsi, Hindi, and Thai. static const TextTheme tall2014 = TextTheme( - displayLarge : TextStyle(debugLabel: 'tall displayLarge 2014', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - displayMedium : TextStyle(debugLabel: 'tall displayMedium 2014', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - displaySmall : TextStyle(debugLabel: 'tall displaySmall 2014', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineLarge : TextStyle(debugLabel: 'tall headlineLarge 2014', inherit: false, fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineMedium : TextStyle(debugLabel: 'tall headlineMedium 2014', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineSmall : TextStyle(debugLabel: 'tall headlineSmall 2014', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - titleLarge : TextStyle(debugLabel: 'tall titleLarge 2014', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), - titleMedium : TextStyle(debugLabel: 'tall titleMedium 2014', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - titleSmall : TextStyle(debugLabel: 'tall titleSmall 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), - bodyLarge : TextStyle(debugLabel: 'tall bodyLarge 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), - bodyMedium : TextStyle(debugLabel: 'tall bodyMedium 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - bodySmall : TextStyle(debugLabel: 'tall bodySmall 2014', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - labelLarge : TextStyle(debugLabel: 'tall labelLarge 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), - labelMedium : TextStyle(debugLabel: 'tall labelMedium 2014', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - labelSmall : TextStyle(debugLabel: 'tall labelSmall 2014', inherit: false, fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline1 : TextStyle(debugLabel: 'tall display4 2014', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline2 : TextStyle(debugLabel: 'tall display3 2014', inherit: false, fontSize: 56.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline3 : TextStyle(debugLabel: 'tall display2 2014', inherit: false, fontSize: 45.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline4 : TextStyle(debugLabel: 'tall display1 2014', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline5 : TextStyle(debugLabel: 'tall headline 2014', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline6 : TextStyle(debugLabel: 'tall title 2014', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), + bodyText1 : TextStyle(debugLabel: 'tall body2 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), + bodyText2 : TextStyle(debugLabel: 'tall body1 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + subtitle1 : TextStyle(debugLabel: 'tall subhead 2014', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + subtitle2 : TextStyle(debugLabel: 'tall subtitle 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), + caption : TextStyle(debugLabel: 'tall caption 2014', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + button : TextStyle(debugLabel: 'tall button 2014', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), + overline : TextStyle(debugLabel: 'tall overline 2014', inherit: false, fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), ); /// Defines text geometry for tall scripts, such as Farsi, Hindi, and Thai. /// /// The font sizes, weights, and letter spacings in this version match the - /// 2018 [Material Design specification](https://material.io/go/design-typography#typography-styles). + /// latest [Material Design specification](https://material.io/go/design-typography#typography-styles). static const TextTheme tall2018 = TextTheme( - displayLarge : TextStyle(debugLabel: 'tall displayLarge 2018', fontSize: 96.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - displayMedium : TextStyle(debugLabel: 'tall displayMedium 2018', fontSize: 60.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - displaySmall : TextStyle(debugLabel: 'tall displaySmall 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineLarge : TextStyle(debugLabel: 'tall headlineLarge 2018', fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineMedium : TextStyle(debugLabel: 'tall headlineMedium 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineSmall : TextStyle(debugLabel: 'tall headlineSmall 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - titleLarge : TextStyle(debugLabel: 'tall titleLarge 2018', fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), - titleMedium : TextStyle(debugLabel: 'tall titleMedium 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - titleSmall : TextStyle(debugLabel: 'tall titleSmall 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), - bodyLarge : TextStyle(debugLabel: 'tall bodyLarge 2018', fontSize: 17.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), - bodyMedium : TextStyle(debugLabel: 'tall bodyMedium 2018', fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - bodySmall : TextStyle(debugLabel: 'tall bodySmall 2018', fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - labelLarge : TextStyle(debugLabel: 'tall labelLarge 2018', fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), - labelMedium : TextStyle(debugLabel: 'tall labelMedium 2018', fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - labelSmall : TextStyle(debugLabel: 'tall labelSmall 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline1 : TextStyle(debugLabel: 'tall headline1 2018', fontSize: 96.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline2 : TextStyle(debugLabel: 'tall headline2 2018', fontSize: 60.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline3 : TextStyle(debugLabel: 'tall headline3 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline4 : TextStyle(debugLabel: 'tall headline4 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline5 : TextStyle(debugLabel: 'tall headline5 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headline6 : TextStyle(debugLabel: 'tall headline6 2018', fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), + bodyText1 : TextStyle(debugLabel: 'tall bodyText1 2018', fontSize: 17.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), + bodyText2 : TextStyle(debugLabel: 'tall bodyText2 2018', fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + subtitle1 : TextStyle(debugLabel: 'tall subtitle1 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + subtitle2 : TextStyle(debugLabel: 'tall subtitle2 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), + button : TextStyle(debugLabel: 'tall button 2018', fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), + caption : TextStyle(debugLabel: 'tall caption 2018', fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + overline : TextStyle(debugLabel: 'tall overline 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), ); } diff --git a/packages/flutter/lib/src/painting/_network_image_io.dart b/packages/flutter/lib/src/painting/_network_image_io.dart index 9542c017b5677..21d0c95c9009c 100644 --- a/packages/flutter/lib/src/painting/_network_image_io.dart +++ b/packages/flutter/lib/src/painting/_network_image_io.dart @@ -51,10 +51,12 @@ class NetworkImage extends image_provider.ImageProvider [ - DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image key', key), - ], + informationCollector: () { + return [ + DiagnosticsProperty('Image provider', this), + DiagnosticsProperty('Image key', key), + ]; + }, ); } diff --git a/packages/flutter/lib/src/painting/_network_image_web.dart b/packages/flutter/lib/src/painting/_network_image_web.dart index a1133291e78ec..61543599cb303 100644 --- a/packages/flutter/lib/src/painting/_network_image_web.dart +++ b/packages/flutter/lib/src/painting/_network_image_web.dart @@ -59,10 +59,12 @@ class NetworkImage InformationCollector? _imageStreamInformationCollector(image_provider.NetworkImage key) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image key', key as NetworkImage), - ]; + collector = () { + return [ + DiagnosticsProperty('Image provider', this), + DiagnosticsProperty('Image key', key as NetworkImage), + ]; + }; return true; }()); return collector; diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart index 7e3cbdeeececf..95e2558038362 100644 --- a/packages/flutter/lib/src/painting/decoration_image.dart +++ b/packages/flutter/lib/src/painting/decoration_image.dart @@ -657,7 +657,7 @@ void paintImage({ } } -Iterable _generateImageTileRects(Rect outputRect, Rect fundamentalRect, ImageRepeat repeat) { +Iterable _generateImageTileRects(Rect outputRect, Rect fundamentalRect, ImageRepeat repeat) sync* { int startX = 0; int startY = 0; int stopX = 0; @@ -675,11 +675,10 @@ Iterable _generateImageTileRects(Rect outputRect, Rect fundamentalRect, Im stopY = ((outputRect.bottom - fundamentalRect.bottom) / strideY).ceil(); } - return [ - for (int i = startX; i <= stopX; ++i) - for (int j = startY; j <= stopY; ++j) - fundamentalRect.shift(Offset(i * strideX, j * strideY)), - ]; + for (int i = startX; i <= stopX; ++i) { + for (int j = startY; j <= stopY; ++j) + yield fundamentalRect.shift(Offset(i * strideX, j * strideY)); + } } Rect _scaleRect(Rect rect, double scale) => Rect.fromLTRB(rect.left * scale, rect.top * scale, rect.right * scale, rect.bottom * scale); diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index d5ca57e9f496d..852db6960b461 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -148,7 +148,7 @@ class ImageConfiguration { if (platform != null) { if (hasArguments) result.write(', '); - result.write('platform: ${platform!.name}'); + result.write('platform: ${describeEnum(platform!)}'); hasArguments = true; } result.write(')'); @@ -186,7 +186,7 @@ typedef DecoderCallback = Future Function(Uint8List bytes, {int? cache /// The type argument does not have to be specified when using the type as an /// argument (where any image provider is acceptable). /// -/// The following image formats are supported: {@macro dart.ui.imageFormats} +/// The following image formats are supported: {@macro flutter.dart:ui.imageFormats} /// /// ## Lifecycle of resolving an image /// @@ -336,11 +336,11 @@ abstract class ImageProvider { await null; // wait an event turn in case a listener has been added to the image stream. InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image configuration', configuration), - DiagnosticsProperty('Image key', key, defaultValue: null), - ]; + collector = () sync* { + yield DiagnosticsProperty('Image provider', this); + yield DiagnosticsProperty('Image configuration', configuration); + yield DiagnosticsProperty('Image key', key, defaultValue: null); + }; return true; }()); if (stream.completer == null) { @@ -395,11 +395,11 @@ abstract class ImageProvider { } else { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image configuration', configuration), - DiagnosticsProperty('Image key', key, defaultValue: null), - ]; + collector = () sync* { + yield DiagnosticsProperty('Image provider', this); + yield DiagnosticsProperty('Image configuration', configuration); + yield DiagnosticsProperty('Image key', key, defaultValue: null); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( @@ -648,10 +648,10 @@ abstract class AssetBundleImageProvider extends ImageProvider [ - DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image key', key), - ]; + collector = () sync* { + yield DiagnosticsProperty('Image provider', this); + yield DiagnosticsProperty('Image key', key); + }; return true; }()); return MultiFrameImageStreamCompleter( @@ -878,9 +878,9 @@ class FileImage extends ImageProvider { codec: _loadAsync(key, decode), scale: key.scale, debugLabel: key.file.path, - informationCollector: () => [ - ErrorDescription('Path: ${file.path}'), - ], + informationCollector: () sync* { + yield ErrorDescription('Path: ${file.path}'); + }, ); } @@ -938,7 +938,7 @@ class MemoryImage extends ImageProvider { /// The bytes to decode into an image. /// /// The bytes represent encoded image bytes and can be encoded in any of the - /// following supported image formats: {@macro dart.ui.imageFormats} + /// following supported image formats: {@macro flutter.dart:ui.imageFormats} /// /// See also: /// diff --git a/packages/flutter/lib/src/painting/image_stream.dart b/packages/flutter/lib/src/painting/image_stream.dart index 82322077b008a..06e0face2b91f 100644 --- a/packages/flutter/lib/src/painting/image_stream.dart +++ b/packages/flutter/lib/src/painting/image_stream.dart @@ -571,8 +571,6 @@ abstract class ImageStreamCompleter with Diagnosticable { } bool _disposed = false; - - @mustCallSuper void _maybeDispose() { if (!_hadAtLeastOneListener || _disposed || _listeners.isNotEmpty || _keepAliveHandles != 0) { return; @@ -629,7 +627,7 @@ abstract class ImageStreamCompleter with Diagnosticable { return; // Make a copy to allow for concurrent modification. final List localListeners = - List.of(_listeners); + List.from(_listeners); for (final ImageStreamListener listener in localListeners) { try { listener.onImage(image.clone(), false); @@ -853,7 +851,7 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter { ); }); if (chunkEvents != null) { - _chunkSubscription = chunkEvents.listen(reportImageChunkEvent, + chunkEvents.listen(reportImageChunkEvent, onError: (Object error, StackTrace stack) { reportError( context: ErrorDescription('loading an image'), @@ -867,7 +865,6 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter { } } - StreamSubscription? _chunkSubscription; ui.Codec? _codec; final double _scale; final InformationCollector? _informationCollector; @@ -993,14 +990,4 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter { _timer = null; } } - - @override - void _maybeDispose() { - super._maybeDispose(); - if (_disposed) { - _chunkSubscription?.onData(null); - _chunkSubscription?.cancel(); - _chunkSubscription = null; - } - } } diff --git a/packages/flutter/lib/src/painting/matrix_utils.dart b/packages/flutter/lib/src/painting/matrix_utils.dart index 6543fe3a2b0a7..f684b7246bd09 100644 --- a/packages/flutter/lib/src/painting/matrix_utils.dart +++ b/packages/flutter/lib/src/painting/matrix_utils.dart @@ -171,7 +171,7 @@ class MatrixUtils { return Rect.fromLTRB(_minMax[0], _minMax[1], _minMax[2], _minMax[3]); } - static final Float64List _minMax = Float64List(4); + static late final Float64List _minMax = Float64List(4); static void _accumulate(Float64List m, double x, double y, bool first, bool isAffine) { final double w = isAffine ? 1.0 : 1.0 / (m[3] * x + m[7] * y + m[15]); final double tx = (m[0] * x + m[4] * y + m[12]) * w; diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 478f5271872f3..5b465114969d2 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -206,7 +206,6 @@ class TextPainter { /// in framework will automatically invoke this method. void markNeedsLayout() { _paragraph = null; - _lineMetricsCache = null; _previousCaretPosition = null; _previousCaretPrototype = null; } @@ -391,7 +390,7 @@ class TextPainter { markNeedsLayout(); } - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} ui.TextHeightBehavior? get textHeightBehavior => _textHeightBehavior; ui.TextHeightBehavior? _textHeightBehavior; set textHeightBehavior(ui.TextHeightBehavior? value) { @@ -780,7 +779,7 @@ class TextPainter { final double caretEnd = box.end; final double dx = box.direction == TextDirection.rtl ? caretEnd - caretPrototype.width : caretEnd; - return Rect.fromLTRB(dx.clamp(0, _paragraph!.width), box.top, dx.clamp(0, _paragraph!.width), box.bottom); + return Rect.fromLTRB(min(dx, _paragraph!.width), box.top, min(dx, _paragraph!.width), box.bottom); } return null; } @@ -822,7 +821,7 @@ class TextPainter { final TextBox box = boxes.last; final double caretStart = box.start; final double dx = box.direction == TextDirection.rtl ? caretStart - caretPrototype.width : caretStart; - return Rect.fromLTRB(dx.clamp(0, _paragraph!.width), box.top, dx.clamp(0, _paragraph!.width), box.bottom); + return Rect.fromLTRB(min(dx, _paragraph!.width), box.top, min(dx, _paragraph!.width), box.bottom); } return null; } @@ -976,7 +975,6 @@ class TextPainter { return _paragraph!.getLineBoundary(position); } - List? _lineMetricsCache; /// Returns the full list of [LineMetrics] that describe in detail the various /// metrics of each laid out line. /// @@ -988,8 +986,12 @@ class TextPainter { /// widgets to a particular line. /// /// Valid only after [layout] has been called. + /// + /// This can potentially return a large amount of data, so it is not recommended + /// to repeatedly call this. Instead, cache the results. The cached results + /// should be invalidated upon the next successful [layout]. List computeLineMetrics() { assert(!_debugNeedsLayout); - return _lineMetricsCache ??= _paragraph!.computeLineMetrics(); + return _paragraph!.computeLineMetrics(); } } diff --git a/packages/flutter/lib/src/painting/text_style.dart b/packages/flutter/lib/src/painting/text_style.dart index 5faa8d2c7a1e7..3ad318e425529 100644 --- a/packages/flutter/lib/src/painting/text_style.dart +++ b/packages/flutter/lib/src/painting/text_style.dart @@ -1378,7 +1378,7 @@ class TextStyle with Diagnosticable { if (decoration != null || decorationColor != null || decorationStyle != null || decorationThickness != null) { final List decorationDescription = []; if (decorationStyle != null) - decorationDescription.add(decorationStyle!.name); + decorationDescription.add(describeEnum(decorationStyle!)); // Hide decorationColor from the default text view as it is shown in the // terse decoration summary as well. diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index a12cade253dc8..ff77ca58d37ff 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -508,15 +508,11 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture Future performReassemble() async { await super.performReassemble(); if (BindingBase.debugReassembleConfig?.widgetName == null) { - if (!kReleaseMode) { - Timeline.startSync('Preparing Hot Reload (layout)', arguments: timelineArgumentsIndicatingLandmarkEvent); - } + Timeline.startSync('Dirty Render Tree', arguments: timelineArgumentsIndicatingLandmarkEvent); try { renderView.reassemble(); } finally { - if (!kReleaseMode) { - Timeline.finishSync(); - } + Timeline.finishSync(); } } scheduleWarmUpFrame(); diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart index 1687ce15223c7..6b82436270b88 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:developer' show Timeline; import 'dart:math' as math; import 'dart:ui' as ui show lerpDouble; @@ -1359,7 +1358,6 @@ abstract class RenderBox extends RenderObject { } Map<_IntrinsicDimensionsCacheEntry, double>? _cachedIntrinsicDimensions; - static int _debugIntrinsicsDepth = 0; double _computeIntrinsicDimension(_IntrinsicDimension dimension, double argument, double Function(double argument) computer) { assert(RenderObject.debugCheckingIntrinsics || !debugDoingThisResize); // performResize should not depend on anything except the incoming constraints @@ -1372,38 +1370,11 @@ abstract class RenderBox extends RenderObject { return true; }()); if (shouldCache) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - if (debugProfileLayoutsEnabled) { - debugTimelineArguments = toDiagnosticsNode().toTimelineArguments(); - } else { - debugTimelineArguments = Map.of(debugTimelineArguments); - } - debugTimelineArguments['intrinsics dimension'] = describeEnum(dimension); - debugTimelineArguments['intrinsics argument'] = '$argument'; - return true; - }()); - if (!kReleaseMode) { - if (debugProfileLayoutsEnabled || _debugIntrinsicsDepth == 0) { - Timeline.startSync( - '$runtimeType intrinsics', - arguments: debugTimelineArguments, - ); - } - _debugIntrinsicsDepth += 1; - } _cachedIntrinsicDimensions ??= <_IntrinsicDimensionsCacheEntry, double>{}; - final double result = _cachedIntrinsicDimensions!.putIfAbsent( + return _cachedIntrinsicDimensions!.putIfAbsent( _IntrinsicDimensionsCacheEntry(dimension, argument), () => computer(argument), ); - if (!kReleaseMode) { - _debugIntrinsicsDepth -= 1; - if (debugProfileLayoutsEnabled || _debugIntrinsicsDepth == 0) { - Timeline.finishSync(); - } - } - return result; } return computer(argument); } @@ -1836,34 +1807,8 @@ abstract class RenderBox extends RenderObject { return true; }()); if (shouldCache) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - if (debugProfileLayoutsEnabled) { - debugTimelineArguments = toDiagnosticsNode().toTimelineArguments(); - } else { - debugTimelineArguments = Map.of(debugTimelineArguments); - } - debugTimelineArguments['getDryLayout constraints'] = '$constraints'; - return true; - }()); - if (!kReleaseMode) { - if (debugProfileLayoutsEnabled || _debugIntrinsicsDepth == 0) { - Timeline.startSync( - '$runtimeType.getDryLayout', - arguments: debugTimelineArguments, - ); - } - _debugIntrinsicsDepth += 1; - } _cachedDryLayoutSizes ??= {}; - final Size result = _cachedDryLayoutSizes!.putIfAbsent(constraints, () => _computeDryLayout(constraints)); - if (!kReleaseMode) { - _debugIntrinsicsDepth -= 1; - if (debugProfileLayoutsEnabled || _debugIntrinsicsDepth == 0) { - Timeline.finishSync(); - } - } - return result; + return _cachedDryLayoutSizes!.putIfAbsent(constraints, () => _computeDryLayout(constraints)); } return _computeDryLayout(constraints); } diff --git a/packages/flutter/lib/src/rendering/custom_paint.dart b/packages/flutter/lib/src/rendering/custom_paint.dart index 508e82a839540..0339fc2585988 100644 --- a/packages/flutter/lib/src/rendering/custom_paint.dart +++ b/packages/flutter/lib/src/rendering/custom_paint.dart @@ -1017,14 +1017,4 @@ class RenderCustomPaint extends RenderProxyBox { return newChild; } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(MessageProperty('painter', '$painter')); - properties.add(MessageProperty('foregroundPainter', '$foregroundPainter', level: foregroundPainter != null ? DiagnosticLevel.info : DiagnosticLevel.fine)); - properties.add(DiagnosticsProperty('preferredSize', preferredSize, defaultValue: Size.zero)); - properties.add(DiagnosticsProperty('isComplex', isComplex, defaultValue: false)); - properties.add(DiagnosticsProperty('willChange', willChange, defaultValue: false)); - } } diff --git a/packages/flutter/lib/src/rendering/debug.dart b/packages/flutter/lib/src/rendering/debug.dart index 0c0e84babcdc0..b709076400c49 100644 --- a/packages/flutter/lib/src/rendering/debug.dart +++ b/packages/flutter/lib/src/rendering/debug.dart @@ -96,18 +96,9 @@ bool debugCheckIntrinsicSizes = false; /// Adds [dart:developer.Timeline] events for every [RenderObject] layout. /// -/// The timing information this flag exposes is not representative of the actual -/// cost of layout, because the overhead of adding timeline events is -/// significant relative to the time each object takes to lay out. However, it -/// can expose unexpected layout behavior in the timeline. -/// -/// In debug builds, additional information is included in the trace (such as -/// the properties of render objects being laid out). Collecting this data is -/// expensive and further makes these traces non-representative of actual -/// performance. This data is omitted in profile builds. -/// -/// For more information about performance debugging in Flutter, see -/// . +/// For details on how to use [dart:developer.Timeline] events in the Dart +/// Observatory to optimize your app, see: +/// /// /// See also: /// @@ -121,17 +112,11 @@ bool debugProfileLayoutsEnabled = false; /// Adds [dart:developer.Timeline] events for every [RenderObject] painted. /// /// The timing information this flag exposes is not representative of actual -/// paints, because the overhead of adding timeline events is significant -/// relative to the time each object takes to paint. However, it can expose -/// unexpected painting in the timeline. -/// -/// In debug builds, additional information is included in the trace (such as -/// the properties of render objects being painted). Collecting this data is -/// expensive and further makes these traces non-representative of actual -/// performance. This data is omitted in profile builds. +/// paints. However, it can expose unexpected painting in the timeline. /// -/// For more information about performance debugging in Flutter, see -/// . +/// For details on how to use [dart:developer.Timeline] events in the Dart +/// Observatory to optimize your app, see: +/// /// /// See also: /// diff --git a/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart b/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart index 8f5a4edf50501..e6fbde201296a 100644 --- a/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart +++ b/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart @@ -241,18 +241,16 @@ mixin DebugOverflowIndicatorMixin on RenderObject { exception: FlutterError('A $runtimeType overflowed by $overflowText.'), library: 'rendering library', context: ErrorDescription('during layout'), - informationCollector: () => [ - // debugCreator should only be set in DebugMode, but we want the - // treeshaker to know that. - if (kDebugMode && debugCreator != null) - DiagnosticsDebugCreator(debugCreator!), - ...overflowHints!, - describeForError('The specific $runtimeType in question is'), + informationCollector: () sync* { + if (debugCreator != null) + yield DiagnosticsDebugCreator(debugCreator!); + yield* overflowHints!; + yield describeForError('The specific $runtimeType in question is'); // TODO(jacobr): this line is ascii art that it would be nice to // handle a little more generically in GUI debugging clients in the // future. - DiagnosticsNode.message('◢◤' * (FlutterError.wrapWidth ~/ 2), allowWrap: false), - ], + yield DiagnosticsNode.message('◢◤' * (FlutterError.wrapWidth ~/ 2), allowWrap: false); + }, ), ); } diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index f8113e3121b1d..dd19cf48be4e8 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -4,7 +4,7 @@ import 'dart:collection'; import 'dart:math' as math; -import 'dart:ui' as ui show TextBox, BoxHeightStyle, BoxWidthStyle, PlaceholderAlignment, LineMetrics; +import 'dart:ui' as ui show TextBox, BoxHeightStyle, BoxWidthStyle, PlaceholderAlignment; import 'package:characters/characters.dart'; import 'package:flutter/foundation.dart'; @@ -77,141 +77,6 @@ class TextSelectionPoint { } } -/// The consecutive sequence of [TextPosition]s that the caret should move to -/// when the user navigates the paragraph using the upward arrow key or the -/// downward arrow key. -/// -/// {@template flutter.rendering.RenderEditable.verticalArrowKeyMovement} -/// When the user presses the upward arrow key or the downward arrow key, on -/// many platforms (macOS for instance), the caret will move to the previous -/// line or the next line, while maintaining its original horizontal location. -/// When it encounters a shorter line, the caret moves to the closest horizontal -/// location within that line, and restores the original horizontal location -/// when a long enough line is encountered. -/// -/// Additionally, the caret will move to the beginning of the document if the -/// upward arrow key is pressed and the caret is already on the first line. If -/// the downward arrow key is pressed next, the caret will restore its original -/// horizontal location and move to the second line. Similarly the caret moves -/// to the end of the document if the downward arrow key is pressed when it's -/// already on the last line. -/// -/// Consider a left-aligned paragraph: -/// aa| -/// a -/// aaa -/// where the caret was initially placed at the end of the first line. Pressing -/// the downward arrow key once will move the caret to the end of the second -/// line, and twice the arrow key moves to the third line after the second "a" -/// on that line. Pressing the downward arrow key again, the caret will move to -/// the end of the third line (the end of the document). Pressing the upward -/// arrow key in this state will result in the caret moving to the end of the -/// second line. -/// -/// Vertical caret runs are typically interrupted when the layout of the text -/// changes (including when the text itself changes), or when the selection is -/// changed by other input events or programmatically (for example, when the -/// user pressed the left arrow key). -/// {@endtemplate} -/// -/// The [movePrevious] method moves the caret location (which is -/// [VerticalCaretMovementRun.current]) to the previous line, and in case -/// the caret is already on the first line, the method does nothing and returns -/// false. Similarly the [moveNext] method moves the caret to the next line, and -/// returns false if the caret is already on the last line. -/// -/// If the underlying paragraph's layout changes, [isValid] becomes false and -/// the [VerticalCaretMovementRun] must not be used. The [isValid] property must -/// be checked before calling [movePrevious] and [moveNext], or accessing -/// [current]. -class VerticalCaretMovementRun extends BidirectionalIterator { - VerticalCaretMovementRun._( - this._editable, - this._lineMetrics, - this._currentTextPosition, - this._currentLine, - this._currentOffset, - ); - - Offset _currentOffset; - int _currentLine; - TextPosition _currentTextPosition; - - final List _lineMetrics; - final RenderEditable _editable; - - bool _isValid = true; - /// Whether this [VerticalCaretMovementRun] can still continue. - /// - /// A [VerticalCaretMovementRun] run is valid if the underlying text layout - /// hasn't changed. - /// - /// The [current] value and the [movePrevious] and [moveNext] methods must not - /// be accessed when [isValid] is false. - bool get isValid { - if (!_isValid) { - return false; - } - final List newLineMetrics = _editable._textPainter.computeLineMetrics(); - // Use the implementation detail of the computeLineMetrics method to figure - // out if the current text layout has been invalidated. - if (!identical(newLineMetrics, _lineMetrics)) { - _isValid = false; - } - return _isValid; - } - - final Map> _positionCache = >{}; - - MapEntry _getTextPositionForLine(int lineNumber) { - assert(isValid); - assert(lineNumber >= 0); - final MapEntry? cachedPosition = _positionCache[lineNumber]; - if (cachedPosition != null) { - return cachedPosition; - } - assert(lineNumber != _currentLine); - - final Offset newOffset = Offset(_currentOffset.dx, _lineMetrics[lineNumber].baseline); - final TextPosition closestPosition = _editable._textPainter.getPositionForOffset(newOffset); - final MapEntry position = MapEntry(newOffset, closestPosition); - _positionCache[lineNumber] = position; - return position; - } - - @override - TextPosition get current { - assert(isValid); - return _currentTextPosition; - } - - @override - bool moveNext() { - assert(isValid); - if (_currentLine + 1 >= _lineMetrics.length) { - return false; - } - final MapEntry position = _getTextPositionForLine(_currentLine + 1); - _currentLine += 1; - _currentOffset = position.key; - _currentTextPosition = position.value; - return true; - } - - @override - bool movePrevious() { - assert(isValid); - if (_currentLine <= 0) { - return false; - } - final MapEntry position = _getTextPositionForLine(_currentLine - 1); - _currentLine -= 1; - _currentOffset = position.key; - _currentTextPosition = position.value; - return true; - } -} - /// Displays some text in a scrollable container with a potentially blinking /// cursor and with gesture recognizers. /// @@ -547,7 +412,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, /// The default value of this property is false. bool ignorePointer; - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} TextHeightBehavior? get textHeightBehavior => _textPainter.textHeightBehavior; set textHeightBehavior(TextHeightBehavior? value) { if (_textPainter.textHeightBehavior == value) @@ -1664,8 +1529,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, final Offset start = Offset(0.0, preferredLineHeight) + caretOffset + paintOffset; return [TextSelectionPoint(start, null)]; } else { - final Offset start = Offset(boxes.first.start.clamp(0, _textPainter.size.width), boxes.first.bottom) + paintOffset; - final Offset end = Offset(boxes.last.end.clamp(0, _textPainter.size.width), boxes.last.bottom) + paintOffset; + final Offset start = Offset(boxes.first.start, boxes.first.bottom) + paintOffset; + final Offset end = Offset(boxes.last.end, boxes.last.bottom) + paintOffset; return [ TextSelectionPoint(start, boxes.first.direction), TextSelectionPoint(end, boxes.last.direction), @@ -2401,48 +2266,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, _caretPainter.showRegularCaret = _resetFloatingCursorAnimationValue == null; } - MapEntry _lineNumberFor(TextPosition startPosition, List metrics) { - // TODO(LongCatIsLooong): include line boundaries information in - // ui.LineMetrics, then we can get rid of this. - final Offset offset = _textPainter.getOffsetForCaret(startPosition, Rect.zero); - for (final ui.LineMetrics lineMetrics in metrics) { - if (lineMetrics.baseline + lineMetrics.descent > offset.dy) { - return MapEntry(lineMetrics.lineNumber, Offset(offset.dx, lineMetrics.baseline)); - } - } - assert(startPosition.offset == 0, 'unable to find the line for $startPosition'); - return MapEntry( - math.max(0, metrics.length - 1), - Offset(offset.dx, metrics.isNotEmpty ? metrics.last.baseline + metrics.last.descent : 0.0), - ); - } - - /// Starts a [VerticalCaretMovementRun] at the given location in the text, for - /// handling consecutive vertical caret movements. - /// - /// This can be used to handle consecutive upward/downward arrow key movements - /// in an input field. - /// - /// {@macro flutter.rendering.RenderEditable.verticalArrowKeyMovement} - /// - /// The [VerticalCaretMovementRun.isValid] property indicates whether the text - /// layout has changed and the vertical caret run is invalidated. - /// - /// The caller should typically discard a [VerticalCaretMovementRun] when - /// its [VerticalCaretMovementRun.isValid] becomes false, or on other - /// occasions where the vertical caret run should be interrupted. - VerticalCaretMovementRun startVerticalCaretMovement(TextPosition startPosition) { - final List metrics = _textPainter.computeLineMetrics(); - final MapEntry currentLine = _lineNumberFor(startPosition, metrics); - return VerticalCaretMovementRun._( - this, - metrics, - startPosition, - currentLine.key, - currentLine.value, - ); - } - void _paintContents(PaintingContext context, Offset offset) { debugAssertLayoutUpToDate(); final Offset effectiveOffset = offset + _paintOffset; @@ -2741,19 +2564,14 @@ class _TextHighlightPainter extends RenderEditablePainter { } highlightPaint.color = color; - final TextPainter textPainter = renderEditable._textPainter; - final List boxes = textPainter.getBoxesForSelection( + final List boxes = renderEditable._textPainter.getBoxesForSelection( TextSelection(baseOffset: range.start, extentOffset: range.end), boxHeightStyle: selectionHeightStyle, boxWidthStyle: selectionWidthStyle, ); for (final TextBox box in boxes) - canvas.drawRect( - box.toRect().shift(renderEditable._paintOffset) - .intersect(Rect.fromLTWH(0, 0, textPainter.width, textPainter.height)), - highlightPaint, - ); + canvas.drawRect(box.toRect().shift(renderEditable._paintOffset), highlightPaint); } @override diff --git a/packages/flutter/lib/src/rendering/flex.dart b/packages/flutter/lib/src/rendering/flex.dart index 99107df196b26..730c835273b6f 100644 --- a/packages/flutter/lib/src/rendering/flex.dart +++ b/packages/flutter/lib/src/rendering/flex.dart @@ -1155,10 +1155,8 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin { /// tree. /// /// It is similar to [entries] but does not contain other information. - Iterable get annotations { - return _entries.map((AnnotationEntry entry) => entry.annotation); + Iterable get annotations sync* { + for (final AnnotationEntry entry in _entries) + yield entry.annotation; } } @@ -1764,16 +1764,11 @@ class OpacityLayer extends OffsetLayer { @override void addToScene(ui.SceneBuilder builder) { assert(alpha != null); - - // Don't add this layer if there's no child. - bool enabled = firstChild != null; + bool enabled = firstChild != null; // don't add this layer if there's no child if (!enabled) { - // Ensure the engineLayer is disposed. - engineLayer = null; // TODO(dnfield): Remove this if/when we can fix https://github.com/flutter/flutter/issues/90004 return; } - assert(() { enabled = enabled && !debugDisableOpacityLayers; return true; @@ -2109,57 +2104,35 @@ class PhysicalModelLayer extends ContainerLayer { /// * [RenderLeaderLayer] and [RenderFollowerLayer], the corresponding /// render objects. class LayerLink { - /// The [LeaderLayer] connected to this link. - LeaderLayer? get leader => _leader; LeaderLayer? _leader; - void _registerLeader(LeaderLayer leader) { - assert(_leader != leader); - assert((){ - if (_leader != null) { - _debugPreviousLeaders ??= {}; - _debugPreviousLeaders!.add(_leader!); - _debugScheduleLeadersCleanUpCheck(); - } - return true; - }()); - _leader = leader; - } + int _connectedFollowers = 0; - void _unregisterLeader(LeaderLayer leader) { - assert(_leader != null); - if (_leader == leader) { - _leader = null; - } else { - assert((){ - _debugPreviousLeaders!.remove(leader); - return true; - }()); - } - } + /// Whether a [LeaderLayer] is currently connected to this link. + bool get leaderConnected => _leader != null; - /// Stores the previous leaders that were replaced by the current [_leader] - /// in the current frame. + /// Called by the [FollowerLayer] to establish a link to a [LeaderLayer]. /// - /// These leaders need to give up their leaderships of this link by the end of - /// the current frame. - Set? _debugPreviousLeaders; - bool _debugLeaderCheckScheduled = false; + /// The returned [LayerLinkHandle] provides access to the leader via + /// [LayerLinkHandle.leader]. + /// + /// When the [FollowerLayer] no longer wants to follow the [LeaderLayer], + /// [LayerLinkHandle.dispose] must be called to disconnect the link. + _LayerLinkHandle _registerFollower() { + assert(_connectedFollowers >= 0); + _connectedFollowers++; + return _LayerLinkHandle(this); + } - /// Schedules the check as post frame callback to make sure the - /// [_debugPreviousLeaders] is empty. - void _debugScheduleLeadersCleanUpCheck() { - assert(_debugPreviousLeaders != null); - assert(() { - if (_debugLeaderCheckScheduled) - return true; - _debugLeaderCheckScheduled = true; - SchedulerBinding.instance!.addPostFrameCallback((Duration timeStamp) { - _debugLeaderCheckScheduled = false; - assert(_debugPreviousLeaders!.isEmpty); - }); - return true; - }()); + /// Returns the [LeaderLayer] currently connected to this link. + /// + /// Valid in debug mode only. Returns null in all other modes. + LeaderLayer? get debugLeader { + LeaderLayer? result; + if (kDebugMode) { + result = _leader; + } + return result; } /// The total size of the content of the connected [LeaderLayer]. @@ -2174,6 +2147,30 @@ class LayerLink { String toString() => '${describeIdentity(this)}(${ _leader != null ? "" : "" })'; } +/// A handle provided by [LayerLink.registerFollower] to a calling +/// [FollowerLayer] to establish a link between that [FollowerLayer] and a +/// [LeaderLayer]. +/// +/// If the link is no longer needed, [dispose] must be called to disconnect it. +class _LayerLinkHandle { + _LayerLinkHandle(this._link); + + LayerLink? _link; + + /// The currently-registered [LeaderLayer], if any. + LeaderLayer? get leader => _link!._leader; + + /// Disconnects the link between the [FollowerLayer] owning this handle and + /// the [leader]. + /// + /// The [LayerLinkHandle] becomes unusable after calling this method. + void dispose() { + assert(_link!._connectedFollowers > 0); + _link!._connectedFollowers--; + _link = null; + } +} + /// A composited layer that can be followed by a [FollowerLayer]. /// /// This layer collapses the accumulated offset into a transform and passes @@ -2201,10 +2198,7 @@ class LeaderLayer extends ContainerLayer { if (_link == value) { return; } - if (attached) { - _link._unregisterLeader(this); - value._registerLeader(this); - } + _link._leader = null; _link = value; } @@ -2228,18 +2222,33 @@ class LeaderLayer extends ContainerLayer { } } + /// {@macro flutter.rendering.FollowerLayer.alwaysNeedsAddToScene} + @override + bool get alwaysNeedsAddToScene => _link._connectedFollowers > 0; + @override void attach(Object owner) { super.attach(owner); - _link._registerLeader(this); + assert(link._leader == null); + _lastOffset = null; + link._leader = this; } @override void detach() { - _link._unregisterLeader(this); + assert(link._leader == this); + link._leader = null; + _lastOffset = null; super.detach(); } + /// The offset the last time this layer was composited. + /// + /// This is reset to null when the layer is attached or detached, to help + /// catch cases where the follower layer ends up before the leader layer, but + /// not every case can be detected. + Offset? _lastOffset; + @override bool findAnnotations(AnnotationResult result, Offset localPosition, { required bool onlyFirst }) { return super.findAnnotations(result, localPosition - offset, onlyFirst: onlyFirst); @@ -2248,13 +2257,14 @@ class LeaderLayer extends ContainerLayer { @override void addToScene(ui.SceneBuilder builder) { assert(offset != null); - if (offset != Offset.zero) + _lastOffset = offset; + if (_lastOffset != Offset.zero) engineLayer = builder.pushTransform( - Matrix4.translationValues(offset.dx, offset.dy, 0.0).storage, + Matrix4.translationValues(_lastOffset!.dx, _lastOffset!.dy, 0.0).storage, oldLayer: _engineLayer as ui.TransformEngineLayer?, ); addChildrenToScene(builder); - if (offset != Offset.zero) + if (_lastOffset != Offset.zero) builder.pop(); } @@ -2267,8 +2277,9 @@ class LeaderLayer extends ContainerLayer { /// children. @override void applyTransform(Layer? child, Matrix4 transform) { - if (offset != Offset.zero) - transform.translate(offset.dx, offset.dy); + assert(_lastOffset != null); + if (_lastOffset != Offset.zero) + transform.translate(_lastOffset!.dx, _lastOffset!.dy); } @override @@ -2311,6 +2322,10 @@ class FollowerLayer extends ContainerLayer { LayerLink get link => _link; set link(LayerLink value) { assert(value != null); + if (value != _link && _leaderHandle != null) { + _leaderHandle!.dispose(); + _leaderHandle = value._registerFollower(); + } _link = value; } LayerLink _link; @@ -2357,6 +2372,21 @@ class FollowerLayer extends ContainerLayer { /// * [unlinkedOffset], for when the layer is not linked. Offset? linkedOffset; + _LayerLinkHandle? _leaderHandle; + + @override + void attach(Object owner) { + super.attach(owner); + _leaderHandle = _link._registerFollower(); + } + + @override + void detach() { + super.detach(); + _leaderHandle?.dispose(); + _leaderHandle = null; + } + Offset? _lastOffset; Matrix4? _lastTransform; Matrix4? _invertedTransform; @@ -2376,7 +2406,7 @@ class FollowerLayer extends ContainerLayer { @override bool findAnnotations(AnnotationResult result, Offset localPosition, { required bool onlyFirst }) { - if (_link.leader == null) { + if (_leaderHandle!.leader == null) { if (showWhenUnlinked!) { return super.findAnnotations(result, localPosition - unlinkedOffset!, onlyFirst: onlyFirst); } @@ -2451,39 +2481,11 @@ class FollowerLayer extends ContainerLayer { return _pathsToCommonAncestor(a.parent, b.parent, ancestorsA, ancestorsB); } - bool _debugCheckLeaderBeforeFollower( - List leaderToCommonAncestor, - List followerToCommonAncestor, - ) { - if (followerToCommonAncestor.length <= 1) { - // Follower is the common ancestor, ergo the leader must come AFTER the follower. - return false; - } - if (leaderToCommonAncestor.length <= 1) { - // Leader is the common ancestor, ergo the leader must come BEFORE the follower. - return true; - } - - // Common ancestor is neither the leader nor the follower. - final ContainerLayer leaderSubtreeBelowAncestor = leaderToCommonAncestor[leaderToCommonAncestor.length - 2]; - final ContainerLayer followerSubtreeBelowAncestor = followerToCommonAncestor[followerToCommonAncestor.length - 2]; - - Layer? sibling = leaderSubtreeBelowAncestor; - while (sibling != null) { - if (sibling == followerSubtreeBelowAncestor) { - return true; - } - sibling = sibling.nextSibling; - } - // The follower subtree didn't come after the leader subtree. - return false; - } - /// Populate [_lastTransform] given the current state of the tree. void _establishTransform() { assert(link != null); _lastTransform = null; - final LeaderLayer? leader = _link.leader; + final LeaderLayer? leader = _leaderHandle!.leader; // Check to see if we are linked. if (leader == null) return; @@ -2492,25 +2494,22 @@ class FollowerLayer extends ContainerLayer { leader.owner == owner, 'Linked LeaderLayer anchor is not in the same layer tree as the FollowerLayer.', ); + assert( + leader._lastOffset != null, + 'LeaderLayer anchor must come before FollowerLayer in paint order, but the reverse was true.', + ); // Stores [leader, ..., commonAncestor] after calling _pathsToCommonAncestor. - final List forwardLayers = [leader]; + final List forwardLayers = [leader]; // Stores [this (follower), ..., commonAncestor] after calling // _pathsToCommonAncestor. - final List inverseLayers = [this]; + final List inverseLayers = [this]; final Layer? ancestor = _pathsToCommonAncestor( leader, this, forwardLayers, inverseLayers, ); - assert( - ancestor != null, - 'LeaderLayer and FollowerLayer do not have a common ancestor.', - ); - assert( - _debugCheckLeaderBeforeFollower(forwardLayers, inverseLayers), - 'LeaderLayer anchor must come before FollowerLayer in paint order, but the reverse was true.', - ); + assert(ancestor != null); final Matrix4 forwardTransform = _collectTransformForLayerChain(forwardLayers); // Further transforms the coordinate system to a hypothetical child (null) @@ -2548,7 +2547,7 @@ class FollowerLayer extends ContainerLayer { void addToScene(ui.SceneBuilder builder) { assert(link != null); assert(showWhenUnlinked != null); - if (_link.leader == null && !showWhenUnlinked!) { + if (_leaderHandle!.leader == null && !showWhenUnlinked!) { _lastTransform = null; _lastOffset = null; _inverseDirty = true; diff --git a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart index b9a81899a08ee..08f5240956307 100644 --- a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart +++ b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart @@ -663,10 +663,12 @@ class RenderListWheelViewport /// by [childManager]. @override void performLayout() { - // Apply the dimensions first in case it changes the scroll offset which - // determines what should be shown. - offset.applyViewportDimension(_viewportExtent); - offset.applyContentDimensions(_minEstimatedScrollExtent, _maxEstimatedScrollExtent); + final BoxConstraints childConstraints = + constraints.copyWith( + minHeight: _itemExtent, + maxHeight: _itemExtent, + minWidth: 0.0, + ); // The height, in pixel, that children will be visible and might be laid out // and painted. @@ -678,7 +680,7 @@ class RenderListWheelViewport visibleHeight *= 2; final double firstVisibleOffset = - offset.pixels + _itemExtent / 2 - visibleHeight / 2; + offset.pixels + _itemExtent / 2 - visibleHeight / 2; final double lastVisibleOffset = firstVisibleOffset + visibleHeight; // The index range that we want to spawn children. We find indexes that @@ -719,11 +721,6 @@ class RenderListWheelViewport _destroyChild(firstChild!); } - final BoxConstraints childConstraints = constraints.copyWith( - minHeight: _itemExtent, - maxHeight: _itemExtent, - minWidth: 0.0, - ); // If there is no child at this stage, we add the first one that is in // target range. if (childCount == 0) { @@ -762,6 +759,8 @@ class RenderListWheelViewport _layoutChild(lastChild!, childConstraints, ++currentLastIndex); } + offset.applyViewportDimension(_viewportExtent); + // Applying content dimensions bases on how the childManager builds widgets: // if it is available to provide a child just out of target range, then // we don't know whether there's a limit yet, and set the dimension to the @@ -771,16 +770,16 @@ class RenderListWheelViewport ? _minEstimatedScrollExtent : indexToScrollOffset(targetFirstIndex); final double maxScrollExtent = childManager.childExistsAt(targetLastIndex + 1) - ? _maxEstimatedScrollExtent - : indexToScrollOffset(targetLastIndex); + ? _maxEstimatedScrollExtent + : indexToScrollOffset(targetLastIndex); offset.applyContentDimensions(minScrollExtent, maxScrollExtent); } bool _shouldClipAtCurrentOffset() { final double highestUntransformedPaintY = - _getUntransformedPaintingCoordinateY(0.0); + _getUntransformedPaintingCoordinateY(0.0); return highestUntransformedPaintY < 0.0 - || size.height < highestUntransformedPaintY + _maxEstimatedScrollExtent + _itemExtent; + || size.height < highestUntransformedPaintY + _maxEstimatedScrollExtent + _itemExtent; } @override diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index b42ae2d983cd1..dd4248f1cfc22 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -175,6 +175,8 @@ class PaintingContext extends ClipContext { /// into the layer subtree associated with this painting context. Otherwise, /// the child will be painted into the current PictureLayer for this context. void paintChild(RenderObject child, Offset offset) { + if (!kReleaseMode && debugProfilePaintsEnabled) + Timeline.startSync('${child.runtimeType}', arguments: timelineArgumentsIndicatingLandmarkEvent); assert(() { debugOnProfilePaint?.call(child); return true; @@ -186,6 +188,9 @@ class PaintingContext extends ClipContext { } else { child._paintWithContext(this, offset); } + + if (!kReleaseMode && debugProfilePaintsEnabled) + Timeline.finishSync(); } void _compositeChild(RenderObject child, Offset offset) { @@ -858,27 +863,14 @@ class PipelineOwner { /// See [RendererBinding] for an example of how this function is used. void flushLayout() { if (!kReleaseMode) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - if (debugProfileLayoutsEnabled) { - debugTimelineArguments = { - ...debugTimelineArguments, - 'dirty count': '${_nodesNeedingLayout.length}', - 'dirty list': '$_nodesNeedingLayout', - }; - } - return true; - }()); - Timeline.startSync( - 'LAYOUT', - arguments: debugTimelineArguments, - ); + Timeline.startSync('Layout', arguments: timelineArgumentsIndicatingLandmarkEvent); } assert(() { _debugDoingLayout = true; return true; }()); try { + // TODO(ianh): assert that we're not allowing previously dirty nodes to redirty themselves while (_nodesNeedingLayout.isNotEmpty) { final List dirtyNodes = _nodesNeedingLayout; _nodesNeedingLayout = []; @@ -931,7 +923,7 @@ class PipelineOwner { /// [flushPaint]. void flushCompositingBits() { if (!kReleaseMode) { - Timeline.startSync('UPDATING COMPOSITING BITS', arguments: timelineArgumentsIndicatingLandmarkEvent); + Timeline.startSync('Compositing bits'); } _nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth); for (final RenderObject node in _nodesNeedingCompositingBitsUpdate) { @@ -964,21 +956,7 @@ class PipelineOwner { /// See [RendererBinding] for an example of how this function is used. void flushPaint() { if (!kReleaseMode) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - if (debugProfilePaintsEnabled) { - debugTimelineArguments = { - ...debugTimelineArguments, - 'dirty count': '${_nodesNeedingPaint.length}', - 'dirty list': '$_nodesNeedingPaint', - }; - } - return true; - }()); - Timeline.startSync( - 'PAINT', - arguments: debugTimelineArguments, - ); + Timeline.startSync('Paint', arguments: timelineArgumentsIndicatingLandmarkEvent); } assert(() { _debugDoingPaint = true; @@ -1080,7 +1058,7 @@ class PipelineOwner { if (_semanticsOwner == null) return; if (!kReleaseMode) { - Timeline.startSync('SEMANTICS', arguments: timelineArgumentsIndicatingLandmarkEvent); + Timeline.startSync('Semantics'); } assert(_semanticsOwner != null); assert(() { @@ -1114,8 +1092,6 @@ class PipelineOwner { /// The [RenderObject] class hierarchy is the core of the rendering /// library's reason for being. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=zmbmrw07qBc} -/// /// [RenderObject]s have a [parent], and have a slot called [parentData] in /// which the parent [RenderObject] can store child-specific data, for example, /// the child position. The [RenderObject] class also implements the basic @@ -1393,18 +1369,16 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im stack: stack, library: 'rendering library', context: ErrorDescription('during $method()'), - informationCollector: () => [ - // debugCreator should always be null outside of debugMode, but we want - // the tree shaker to notice this. - if (kDebugMode && debugCreator != null) - DiagnosticsDebugCreator(debugCreator!), - describeForError('The following RenderObject was being processed when the exception was fired'), + informationCollector: () sync* { + if (debugCreator != null) + yield DiagnosticsDebugCreator(debugCreator!); + yield describeForError('The following RenderObject was being processed when the exception was fired'); // TODO(jacobr): this error message has a code smell. Consider whether // displaying the truncated children is really useful for command line // users. Inspector users can see the full tree by clicking on the // render object so this may not be that useful. - describeForError('RenderObject', style: DiagnosticsTreeStyle.truncateChildren), - ], + yield describeForError('RenderObject', style: DiagnosticsTreeStyle.truncateChildren); + }, )); } @@ -1771,21 +1745,13 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im @pragma('vm:notify-debugger-on-exception') void layout(Constraints constraints, { bool parentUsesSize = false }) { assert(!_debugDisposed); - if (!kReleaseMode && debugProfileLayoutsEnabled) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - debugTimelineArguments = toDiagnosticsNode().toTimelineArguments(); - return true; - }()); - Timeline.startSync( - '$runtimeType', - arguments: debugTimelineArguments, - ); - } + if (!kReleaseMode && debugProfileLayoutsEnabled) + Timeline.startSync('$runtimeType', arguments: timelineArgumentsIndicatingLandmarkEvent); + assert(constraints != null); assert(constraints.debugAssertIsValid( isAppliedConstraint: true, - informationCollector: () { + informationCollector: () sync* { final List stack = StackTrace.current.toString().split('\n'); int? targetFrame; final Pattern layoutFramePattern = RegExp(r'^#[0-9]+ +RenderObject.layout \('); @@ -1800,16 +1766,13 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im final Match? targetFrameMatch = targetFramePattern.matchAsPrefix(stack[targetFrame]); final String? problemFunction = (targetFrameMatch != null && targetFrameMatch.groupCount > 0) ? targetFrameMatch.group(1) : stack[targetFrame].trim(); // TODO(jacobr): this case is similar to displaying a single stack frame. - return [ - ErrorDescription( - "These invalid constraints were provided to $runtimeType's layout() " - 'function by the following function, which probably computed the ' - 'invalid constraints in question:\n' - ' $problemFunction', - ), - ]; + yield ErrorDescription( + "These invalid constraints were provided to $runtimeType's layout() " + 'function by the following function, which probably computed the ' + 'invalid constraints in question:\n' + ' $problemFunction', + ); } - return []; }, )); assert(!_debugDoingThisResize); @@ -2373,17 +2336,6 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im // a different layer, because there's a repaint boundary between us. if (_needsLayout) return; - if (!kReleaseMode && debugProfilePaintsEnabled) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - debugTimelineArguments = toDiagnosticsNode().toTimelineArguments(); - return true; - }()); - Timeline.startSync( - '$runtimeType', - arguments: debugTimelineArguments, - ); - } assert(() { if (_needsCompositingBitsUpdate) { if (parent is RenderObject) { @@ -2460,8 +2412,6 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im _debugDoingThisPaint = false; return true; }()); - if (!kReleaseMode && debugProfilePaintsEnabled) - Timeline.finishSync(); } /// An estimate of the bounds within which this render object will paint. @@ -2935,29 +2885,27 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im @override String toStringShort() { String header = describeIdentity(this); - if (!kReleaseMode) { - if (_debugDisposed) { - header += ' DISPOSED'; - return header; - } - if (_relayoutBoundary != null && _relayoutBoundary != this) { - int count = 1; - RenderObject? target = parent as RenderObject?; - while (target != null && target != _relayoutBoundary) { - target = target.parent as RenderObject?; - count += 1; - } - header += ' relayoutBoundary=up$count'; + if (_debugDisposed) { + header += ' DISPOSED'; + return header; + } + if (_relayoutBoundary != null && _relayoutBoundary != this) { + int count = 1; + RenderObject? target = parent as RenderObject?; + while (target != null && target != _relayoutBoundary) { + target = target.parent as RenderObject?; + count += 1; } - if (_needsLayout) - header += ' NEEDS-LAYOUT'; - if (_needsPaint) - header += ' NEEDS-PAINT'; - if (_needsCompositingBitsUpdate) - header += ' NEEDS-COMPOSITING-BITS-UPDATE'; - if (!attached) - header += ' DETACHED'; + header += ' relayoutBoundary=up$count'; } + if (_needsLayout) + header += ' NEEDS-LAYOUT'; + if (_needsPaint) + header += ' NEEDS-PAINT'; + if (_needsCompositingBitsUpdate) + header += ' NEEDS-COMPOSITING-BITS-UPDATE'; + if (!attached) + header += ' DETACHED'; return header; } @@ -3219,11 +3167,6 @@ mixin ContainerParentDataMixin on ParentData { /// parent data. /// /// Moreover, this is a required mixin for render objects returned to [MultiChildRenderObjectWidget]. -/// -/// See also: -/// -/// * [SlottedContainerRenderObjectMixin], which organizes its children -/// in different named slots. mixin ContainerRenderObjectMixin> on RenderObject { bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType? equals }) { ParentDataType childParentData = child.parentData! as ParentDataType; diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 52afda8d4878e..01e8ec02ceafe 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -288,7 +288,7 @@ class RenderParagraph extends RenderBox markNeedsLayout(); } - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} ui.TextHeightBehavior? get textHeightBehavior => _textPainter.textHeightBehavior; set textHeightBehavior(ui.TextHeightBehavior? value) { if (_textPainter.textHeightBehavior == value) diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 9e1caa3df88ac..39680da94a572 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -2398,10 +2398,8 @@ class RenderTransform extends RenderProxyBox { layer = null; } } else { - final Matrix4 effectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0.0) - ..multiply(transform)..translate(-offset.dx, -offset.dy); final ui.ImageFilter filter = ui.ImageFilter.matrix( - effectiveTransform.storage, + transform.storage, filterQuality: filterQuality!, ); if (layer is ImageFilterLayer) { @@ -5289,7 +5287,7 @@ class RenderFollowerLayer extends RenderProxyBox { @override bool hitTest(BoxHitTestResult result, { required Offset position }) { // Disables the hit testing if this render object is hidden. - if (link.leader == null && !showWhenUnlinked) + if (!link.leaderConnected && !showWhenUnlinked) return false; // RenderFollowerLayer objects don't check if they are // themselves hit, because it's confusing to think about @@ -5313,8 +5311,8 @@ class RenderFollowerLayer extends RenderProxyBox { void paint(PaintingContext context, Offset offset) { final Size? leaderSize = link.leaderSize; assert( - link.leaderSize != null || (link.leader == null || leaderAnchor == Alignment.topLeft), - '$link: layer is linked to ${link.leader} but a valid leaderSize is not set. ' + link.leaderSize != null || (!link.leaderConnected || leaderAnchor == Alignment.topLeft), + '$link: layer is linked to ${link.debugLeader} but a valid leaderSize is not set. ' 'leaderSize is required when leaderAnchor is not Alignment.topLeft ' '(current value is $leaderAnchor).', ); diff --git a/packages/flutter/lib/src/rendering/shifted_box.dart b/packages/flutter/lib/src/rendering/shifted_box.dart index 3be9cad449d42..1d8b39b6c9cc3 100644 --- a/packages/flutter/lib/src/rendering/shifted_box.dart +++ b/packages/flutter/lib/src/rendering/shifted_box.dart @@ -838,10 +838,8 @@ class RenderConstraintsTransformBox extends RenderAligningShiftedBox with DebugO @override String toStringShort() { String header = super.toStringShort(); - if (!kReleaseMode) { - if (_isOverflowing) - header += ' OVERFLOWING'; - } + if (_isOverflowing) + header += ' OVERFLOWING'; return header; } } diff --git a/packages/flutter/lib/src/rendering/sliver.dart b/packages/flutter/lib/src/rendering/sliver.dart index 1fa9de85bf1dd..32b72607f56c8 100644 --- a/packages/flutter/lib/src/rendering/sliver.dart +++ b/packages/flutter/lib/src/rendering/sliver.dart @@ -1203,9 +1203,9 @@ abstract class RenderSliver extends RenderObject { @override void debugAssertDoesMeetConstraints() { assert(geometry!.debugAssertIsValid( - informationCollector: () => [ - describeForError('The RenderSliver that returned the offending geometry was'), - ], + informationCollector: () sync* { + yield describeForError('The RenderSliver that returned the offending geometry was'); + }, )); assert(() { if (geometry!.paintOrigin + geometry!.paintExtent > constraints.remainingPaintExtent) { diff --git a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart index 9aa6a07deaf9a..c4c23de5bf3fb 100644 --- a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart +++ b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart @@ -68,7 +68,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda if (itemExtent > 0.0) { final double actual = scrollOffset / itemExtent; final int round = actual.round(); - if ((actual * itemExtent - round * itemExtent).abs() < precisionErrorTolerance) { + if ((actual - round).abs() < precisionErrorTolerance) { return round; } return actual.floor(); @@ -88,7 +88,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda if (itemExtent > 0.0) { final double actual = scrollOffset / itemExtent - 1; final int round = actual.round(); - if ((actual * itemExtent - round * itemExtent).abs() < precisionErrorTolerance) { + if (_isWithinPrecisionErrorTolerance(actual, round)) { return math.max(0, round); } return math.max(0, actual.ceil()); @@ -358,3 +358,7 @@ class RenderSliverFixedExtentList extends RenderSliverFixedExtentBoxAdaptor { markNeedsLayout(); } } + +bool _isWithinPrecisionErrorTolerance(double actual, int round) { + return (actual - round).abs() < precisionErrorTolerance; +} diff --git a/packages/flutter/lib/src/rendering/table.dart b/packages/flutter/lib/src/rendering/table.dart index c0fdc35fcabdc..7104a82602a07 100644 --- a/packages/flutter/lib/src/rendering/table.dart +++ b/packages/flutter/lib/src/rendering/table.dart @@ -647,7 +647,7 @@ class RenderTable extends RenderBox { // update our internal values _columns = columns; _rows = cells.length ~/ columns; - _children = List.of(cells); + _children = List.from(cells); assert(_children.length == rows * columns); markNeedsLayout(); } @@ -795,8 +795,6 @@ class RenderTable extends RenderBox { /// column, in row order, starting from the first row. /// /// This is a lazily-evaluated iterable. - // The following uses sync* because it is public API documented to return a - // lazy iterable. Iterable column(int x) sync* { for (int y = 0; y < rows; y += 1) { final int xy = x + y * columns; @@ -810,8 +808,6 @@ class RenderTable extends RenderBox { /// row, in column order, starting with the first column. /// /// This is a lazily-evaluated iterable. - // The following uses sync* because it is public API documented to return a - // lazy iterable. Iterable row(int y) sync* { final int start = y * columns; final int end = (y + 1) * columns; diff --git a/packages/flutter/lib/src/rendering/view.dart b/packages/flutter/lib/src/rendering/view.dart index a4ab69cf0599e..3e4b1a2b5ff25 100644 --- a/packages/flutter/lib/src/rendering/view.dart +++ b/packages/flutter/lib/src/rendering/view.dart @@ -220,9 +220,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin /// /// Actually causes the output of the rendering pipeline to appear on screen. void compositeFrame() { - if (!kReleaseMode) { - Timeline.startSync('COMPOSITING', arguments: timelineArgumentsIndicatingLandmarkEvent); - } + Timeline.startSync('Compositing', arguments: timelineArgumentsIndicatingLandmarkEvent); try { final ui.SceneBuilder builder = ui.SceneBuilder(); final ui.Scene scene = layer!.buildScene(builder); @@ -236,9 +234,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin return true; }()); } finally { - if (!kReleaseMode) { - Timeline.finishSync(); - } + Timeline.finishSync(); } } diff --git a/packages/flutter/lib/src/rendering/viewport.dart b/packages/flutter/lib/src/rendering/viewport.dart index 0eb540249534c..e4f0dffd4f04c 100644 --- a/packages/flutter/lib/src/rendering/viewport.dart +++ b/packages/flutter/lib/src/rendering/viewport.dart @@ -1718,40 +1718,37 @@ class RenderViewport extends RenderViewportBase get childrenInPaintOrder { - final List children = []; + Iterable get childrenInPaintOrder sync* { if (firstChild == null) - return children; + return; RenderSliver? child = firstChild; while (child != center) { - children.add(child!); + yield child!; child = childAfter(child); } child = lastChild; while (true) { - children.add(child!); + yield child!; if (child == center) - return children; + return; child = childBefore(child); } } @override - Iterable get childrenInHitTestOrder { - final List children = []; + Iterable get childrenInHitTestOrder sync* { if (firstChild == null) - return children; + return; RenderSliver? child = center; while (child != null) { - children.add(child); + yield child; child = childAfter(child); } child = childBefore(center!); while (child != null) { - children.add(child); + yield child; child = childBefore(child); } - return children; } @override @@ -2033,24 +2030,20 @@ class RenderShrinkWrappingViewport extends RenderViewportBase 'child $index'; @override - Iterable get childrenInPaintOrder { - final List children = []; + Iterable get childrenInPaintOrder sync* { RenderSliver? child = lastChild; while (child != null) { - children.add(child); + yield child; child = childBefore(child); } - return children; } @override - Iterable get childrenInHitTestOrder { - final List children = []; + Iterable get childrenInHitTestOrder sync* { RenderSliver? child = firstChild; while (child != null) { - children.add(child); + yield child; child = childAfter(child); } - return children; } } diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart index 3f9ad49f94ad9..23cd44e9bae7d 100644 --- a/packages/flutter/lib/src/scheduler/binding.dart +++ b/packages/flutter/lib/src/scheduler/binding.dart @@ -279,7 +279,7 @@ mixin SchedulerBinding on BindingBase { @pragma('vm:notify-debugger-on-exception') void _executeTimingsCallbacks(List timings) { final List clonedCallbacks = - List.of(_timingsCallbacks); + List.from(_timingsCallbacks); for (final TimingsCallback callback in clonedCallbacks) { try { if (_timingsCallbacks.contains(callback)) { @@ -288,13 +288,13 @@ mixin SchedulerBinding on BindingBase { } catch (exception, stack) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty( + collector = () sync* { + yield DiagnosticsProperty( 'The TimingsCallback that gets executed was', callback, style: DiagnosticsTreeStyle.errorProperty, - ), - ]; + ); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( @@ -467,15 +467,13 @@ mixin SchedulerBinding on BindingBase { stack: exceptionStack, library: 'scheduler library', context: ErrorDescription('during a task callback'), - informationCollector: (callbackStack == null) ? null : () { - return [ - DiagnosticsStackTrace( - '\nThis exception was thrown in the context of a scheduler callback. ' - 'When the scheduler callback was _registered_ (as opposed to when the ' - 'exception was thrown), this was the stack', - callbackStack, - ), - ]; + informationCollector: (callbackStack == null) ? null : () sync* { + yield DiagnosticsStackTrace( + '\nThis exception was thrown in the context of a scheduler callback. ' + 'When the scheduler callback was _registered_ (as opposed to when the ' + 'exception was thrown), this was the stack', + callbackStack, + ); }, )); } @@ -564,25 +562,28 @@ mixin SchedulerBinding on BindingBase { // even if the information collector is called after // the problem has been resolved. final int count = transientCallbackCount; - final Map callbacks = Map.of(_transientCallbacks); + final Map callbacks = Map.from(_transientCallbacks); FlutterError.reportError(FlutterErrorDetails( exception: reason, library: 'scheduler library', - informationCollector: () => [ - if (count == 1) + informationCollector: () sync* { + if (count == 1) { // TODO(jacobr): I have added an extra line break in this case. - ErrorDescription( + yield ErrorDescription( 'There was one transient callback left. ' 'The stack trace for when it was registered is as follows:', - ) - else - ErrorDescription( + ); + } else { + yield ErrorDescription( 'There were $count transient callbacks left. ' 'The stack traces for when they were registered are as follows:', - ), - for (final int id in callbacks.keys) - DiagnosticsStackTrace('── callback $id ──', callbacks[id]!.debugStack, showSeparator: false), - ], + ); + } + for (final int id in callbacks.keys) { + final _FrameCallbackEntry entry = callbacks[id]!; + yield DiagnosticsStackTrace('── callback $id ──', entry.debugStack, showSeparator: false); + } + }, )); } return true; @@ -1083,7 +1084,7 @@ mixin SchedulerBinding on BindingBase { // POST-FRAME CALLBACKS _schedulerPhase = SchedulerPhase.postFrameCallbacks; final List localPostFrameCallbacks = - List.of(_postFrameCallbacks); + List.from(_postFrameCallbacks); _postFrameCallbacks.clear(); for (final FrameCallback callback in localPostFrameCallbacks) _invokeFrameCallback(callback, _currentFrameTimeStamp!); @@ -1148,15 +1149,13 @@ mixin SchedulerBinding on BindingBase { stack: exceptionStack, library: 'scheduler library', context: ErrorDescription('during a scheduler callback'), - informationCollector: (callbackStack == null) ? null : () { - return [ - DiagnosticsStackTrace( - '\nThis exception was thrown in the context of a scheduler callback. ' - 'When the scheduler callback was _registered_ (as opposed to when the ' - 'exception was thrown), this was the stack', - callbackStack, - ), - ]; + informationCollector: (callbackStack == null) ? null : () sync* { + yield DiagnosticsStackTrace( + '\nThis exception was thrown in the context of a scheduler callback. ' + 'When the scheduler callback was _registered_ (as opposed to when the ' + 'exception was thrown), this was the stack', + callbackStack, + ); }, )); } diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index afb168db8666e..9e273218b71d1 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -217,7 +217,7 @@ class AttributedString { // None of the strings is empty. final String newString = string + other.string; - final List newAttributes = List.of(attributes); + final List newAttributes = List.from(attributes); if (other.attributes.isNotEmpty) { final int offset = string.length; for (final StringAttribute attribute in other.attributes) { @@ -1739,7 +1739,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { } assert(!newChildren.any((SemanticsNode node) => node.isMergedIntoParent) || isPartOfNodeMerging); - _debugPreviousSnapshot = List.of(newChildren); + _debugPreviousSnapshot = List.from(newChildren); SemanticsNode ancestor = this; while (ancestor.parent is SemanticsNode) @@ -2262,8 +2262,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { _flags = config._flags; _textDirection = config.textDirection; _sortKey = config.sortKey; - _actions = Map.of(config._actions); - _customSemanticsActions = Map.of(config._customSemanticsActions); + _actions = Map.from(config._actions); + _customSemanticsActions = Map.from(config._customSemanticsActions); _actionsAsBits = config._actionsAsBits; _textSelection = config._textSelection; _isMultiline = config.isMultiline; @@ -2304,7 +2304,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { AttributedString attributedDecreasedValue = _attributedDecreasedValue; AttributedString attributedHint = _attributedHint; TextDirection? textDirection = _textDirection; - Set? mergedTags = tags == null ? null : Set.of(tags!); + Set? mergedTags = tags == null ? null : Set.from(tags!); TextSelection? textSelection = _textSelection; int? scrollChildCount = _scrollChildCount; int? scrollIndex = _scrollIndex; diff --git a/packages/flutter/lib/src/services/binding.dart b/packages/flutter/lib/src/services/binding.dart index da2c25114f9b8..afc201bbda52f 100644 --- a/packages/flutter/lib/src/services/binding.dart +++ b/packages/flutter/lib/src/services/binding.dart @@ -6,7 +6,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; @@ -145,29 +144,42 @@ mixin ServicesBinding on BindingBase, SchedulerBinding { LicenseRegistry.addLicense(_addLicenses); } - Stream _addLicenses() { - late final StreamController controller; - controller = StreamController( - onListen: () async { - late final String rawLicenses; - if (kIsWeb) { - // NOTICES for web isn't compressed since we don't have access to - // dart:io on the client side and it's already compressed between - // the server and client. - rawLicenses = await rootBundle.loadString('NOTICES', cache: false); - } else { - // The compressed version doesn't have a more common .gz extension - // because gradle for Android non-transparently manipulates .gz files. - final ByteData licenseBytes = await rootBundle.load('NOTICES.Z'); - final List unzippedBytes = await compute, List>(gzip.decode, licenseBytes.buffer.asUint8List(), debugLabel: 'decompressLicenses'); - rawLicenses = await compute, String>(utf8.decode, unzippedBytes, debugLabel: 'utf8DecodeLicenses'); - } - final List licenses = await compute>(_parseLicenses, rawLicenses, debugLabel: 'parseLicenses'); - licenses.forEach(controller.add); - await controller.close(); - }, - ); - return controller.stream; + Stream _addLicenses() async* { + // Using _something_ here to break + // this into two parts is important because isolates take a while to copy + // data at the moment, and if we receive the data in the same event loop + // iteration as we send the data to the next isolate, we are definitely + // going to miss frames. Another solution would be to have the work all + // happen in one isolate, and we may go there eventually, but first we are + // going to see if isolate communication can be made cheaper. + // See: https://github.com/dart-lang/sdk/issues/31959 + // https://github.com/dart-lang/sdk/issues/31960 + // TODO(ianh): Remove this complexity once these bugs are fixed. + final Completer rawLicenses = Completer(); + scheduleTask(() async { + rawLicenses.complete( + kIsWeb + // NOTICES for web isn't compressed since we don't have access to + // dart:io on the client side and it's already compressed between + // the server and client. + ? rootBundle.loadString('NOTICES', cache: false) + : () async { + // The compressed version doesn't have a more common .gz extension + // because gradle for Android non-transparently manipulates .gz files. + final ByteData licenseBytes = await rootBundle.load('NOTICES.Z'); + List bytes = licenseBytes.buffer.asUint8List(); + bytes = gzip.decode(bytes); + return utf8.decode(bytes); + }(), + ); + }, Priority.animation); + await rawLicenses.future; + final Completer> parsedLicenses = Completer>(); + scheduleTask(() async { + parsedLicenses.complete(compute>(_parseLicenses, await rawLicenses.future, debugLabel: 'parseLicenses')); + }, Priority.animation); + await parsedLicenses.future; + yield* Stream.fromIterable(await parsedLicenses.future); } // This is run in another isolate created by _addLicenses above. diff --git a/packages/flutter/lib/src/services/hardware_keyboard.dart b/packages/flutter/lib/src/services/hardware_keyboard.dart index 82efc5a24e725..dca3daac4bb7b 100644 --- a/packages/flutter/lib/src/services/hardware_keyboard.dart +++ b/packages/flutter/lib/src/services/hardware_keyboard.dart @@ -516,9 +516,9 @@ class HardwareKeyboard { } catch (exception, stack) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty('Event', event), - ]; + collector = () sync* { + yield DiagnosticsProperty('Event', event); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( @@ -833,9 +833,9 @@ class KeyEventManager { } catch (exception, stack) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty('KeyMessage', message), - ]; + collector = () sync* { + yield DiagnosticsProperty('KeyMessage', message); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( diff --git a/packages/flutter/lib/src/services/keyboard_key.dart b/packages/flutter/lib/src/services/keyboard_key.dart index ff76e1f724b0a..c95e997cc4cb3 100644 --- a/packages/flutter/lib/src/services/keyboard_key.dart +++ b/packages/flutter/lib/src/services/keyboard_key.dart @@ -3600,12 +3600,6 @@ class PhysicalKeyboardKey extends KeyboardKey { /// See the function [RawKeyEvent.physicalKey] for more information. static const PhysicalKeyboardKey privacyScreenToggle = PhysicalKeyboardKey(0x00000017); - /// Represents the location of the "Microphone Mute Toggle" key on a - /// generalized keyboard. - /// - /// See the function [RawKeyEvent.physicalKey] for more information. - static const PhysicalKeyboardKey microphoneMuteToggle = PhysicalKeyboardKey(0x00000018); - /// Represents the location of the "Sleep" key on a generalized keyboard. /// /// See the function [RawKeyEvent.physicalKey] for more information. @@ -5037,7 +5031,6 @@ class PhysicalKeyboardKey extends KeyboardKey { 0x00000015: resume, 0x00000016: turbo, 0x00000017: privacyScreenToggle, - 0x00000018: microphoneMuteToggle, 0x00010082: sleep, 0x00010083: wakeUp, 0x000100b5: displayToggleIntExt, @@ -5311,7 +5304,6 @@ class PhysicalKeyboardKey extends KeyboardKey { 0x00000015: 'Resume', 0x00000016: 'Turbo', 0x00000017: 'Privacy Screen Toggle', - 0x00000018: 'Microphone Mute Toggle', 0x00010082: 'Sleep', 0x00010083: 'Wake Up', 0x000100b5: 'Display Toggle Int Ext', diff --git a/packages/flutter/lib/src/services/keyboard_maps.dart b/packages/flutter/lib/src/services/keyboard_maps.dart index 3375b30b77ec9..3827e9e774e7e 100644 --- a/packages/flutter/lib/src/services/keyboard_maps.dart +++ b/packages/flutter/lib/src/services/keyboard_maps.dart @@ -784,7 +784,6 @@ const Map kFuchsiaToPhysicalKey = kLinuxToPhysicalKey = kWebToPhysicalKey = kWindowsToLogicalKey = _binaryMessenger ?? ServicesBinding.instance!.defaultBinaryMessenger; final BinaryMessenger? _binaryMessenger; /// Backend implementation of [invokeMethod]. diff --git a/packages/flutter/lib/src/services/raw_keyboard.dart b/packages/flutter/lib/src/services/raw_keyboard.dart index 490d970eeb7d1..46501ff37c638 100644 --- a/packages/flutter/lib/src/services/raw_keyboard.dart +++ b/packages/flutter/lib/src/services/raw_keyboard.dart @@ -280,15 +280,11 @@ abstract class RawKeyEvent with Diagnosticable { const RawKeyEvent({ required this.data, this.character, - this.repeat = false, }); /// Creates a concrete [RawKeyEvent] class from a message in the form received /// on the [SystemChannels.keyEvent] channel. - /// - /// [RawKeyEvent.repeat] will be derived from the current keyboard state, - /// instead of using the message information. - factory RawKeyEvent.fromMessage(Map message) { + factory RawKeyEvent.fromMessage(Map message) { String? character; RawKeyEventData _dataFromWeb() { final String? key = message['key'] as String?; @@ -300,7 +296,6 @@ abstract class RawKeyEvent with Diagnosticable { key: key ?? '', location: message['location'] as int? ?? 0, metaState: message['metaState'] as int? ?? 0, - keyCode: message['keyCode'] as int? ?? 0, ); } @@ -308,7 +303,7 @@ abstract class RawKeyEvent with Diagnosticable { if (kIsWeb) { data = _dataFromWeb(); } else { - final String keymap = message['keymap']! as String; + final String keymap = message['keymap'] as String; switch (keymap) { case 'android': data = RawKeyEventDataAndroid( @@ -393,11 +388,10 @@ abstract class RawKeyEvent with Diagnosticable { throw FlutterError('Unknown keymap for key events: $keymap'); } } - final bool repeat = RawKeyboard.instance.physicalKeysPressed.contains(data.physicalKey); - final String type = message['type']! as String; + final String type = message['type'] as String; switch (type) { case 'keydown': - return RawKeyDownEvent(data: data, character: character, repeat: repeat); + return RawKeyDownEvent(data: data, character: character); case 'keyup': return RawKeyUpEvent(data: data); default: @@ -510,15 +504,6 @@ abstract class RawKeyEvent with Diagnosticable { /// input. final String? character; - /// Whether this is a repeated down event. - /// - /// When a key is held down, the systems usually fire a down event and then - /// a series of repeated down events. The [repeat] is false for the - /// first event and true for the following events. - /// - /// The [repeat] attribute is always false for [RawKeyUpEvent]s. - final bool repeat; - /// Platform-specific information about the key event. final RawKeyEventData data; @@ -527,8 +512,6 @@ abstract class RawKeyEvent with Diagnosticable { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('logicalKey', logicalKey)); properties.add(DiagnosticsProperty('physicalKey', physicalKey)); - if (this is RawKeyDownEvent) - properties.add(DiagnosticsProperty('repeat', repeat)); } } @@ -542,8 +525,7 @@ class RawKeyDownEvent extends RawKeyEvent { const RawKeyDownEvent({ required RawKeyEventData data, String? character, - bool repeat = false, - }) : super(data: data, character: character, repeat: repeat); + }) : super(data: data, character: character); } /// The user has released a key on the keyboard. @@ -556,7 +538,7 @@ class RawKeyUpEvent extends RawKeyEvent { const RawKeyUpEvent({ required RawKeyEventData data, String? character, - }) : super(data: data, character: character, repeat: false); + }) : super(data: data, character: character); } /// A callback type used by [RawKeyboard.keyEventHandler] to send key events to @@ -690,7 +672,7 @@ class RawKeyboard { '${event.data}', ); // Send the event to passive listeners. - for (final ValueChanged listener in List>.of(_listeners)) { + for (final ValueChanged listener in List>.from(_listeners)) { try { if (_listeners.contains(listener)) { listener(event); @@ -698,9 +680,9 @@ class RawKeyboard { } catch (exception, stack) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty('Event', event), - ]; + collector = () sync* { + yield DiagnosticsProperty('Event', event); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( @@ -790,22 +772,15 @@ class RawKeyboard { ..._keysPressed.keys, if (event is RawKeyDownEvent) event.physicalKey, }; - ModifierKey? thisKeyModifier; - for (final ModifierKey key in ModifierKey.values) { - final Set? thisModifierKeys = _modifierKeyMap[_ModifierSidePair(key, KeyboardSide.all)]; - if (thisModifierKeys == null) - continue; - if (thisModifierKeys.contains(event.physicalKey)) { - thisKeyModifier = key; - } + for (final ModifierKey key in modifiersPressed.keys) { if (modifiersPressed[key] == KeyboardSide.any) { - anySideKeys.addAll(thisModifierKeys); + final Set? thisModifierKeys = _modifierKeyMap[_ModifierSidePair(key, KeyboardSide.all)]; + anySideKeys.addAll(thisModifierKeys!); if (thisModifierKeys.any(keysPressedAfterEvent.contains)) { continue; } } - final Set? mappedKeys = modifiersPressed[key] == null ? - {} : _modifierKeyMap[_ModifierSidePair(key, modifiersPressed[key])]; + final Set? mappedKeys = _modifierKeyMap[_ModifierSidePair(key, modifiersPressed[key])]; assert(() { if (mappedKeys == null) { debugPrint( @@ -834,20 +809,6 @@ class RawKeyboard { _keysPressed.remove(PhysicalKeyboardKey.fn); } _keysPressed.addAll(modifierKeys); - // In rare cases, the event presses a modifier key but the key does not - // exist in the modifier list. Enforce the pressing state. - if (event is RawKeyDownEvent && thisKeyModifier != null - && !_keysPressed.containsKey(event.physicalKey)) { - // So far this inconsistancy is only found on Linux GTK for AltRight in a - // rare case. (See https://github.com/flutter/flutter/issues/93278 .) In - // other cases, this inconsistancy will be caught by an assertion later. - if (event.data is RawKeyEventDataLinux && event.physicalKey == PhysicalKeyboardKey.altRight) { - final LogicalKeyboardKey? logicalKey = _allModifiersExceptFn[event.physicalKey]; - if (logicalKey != null) { - _keysPressed[event.physicalKey] = logicalKey; - } - } - } } final Map _keysPressed = {}; diff --git a/packages/flutter/lib/src/services/raw_keyboard_macos.dart b/packages/flutter/lib/src/services/raw_keyboard_macos.dart index af4112c9081b4..63eab78d5cba5 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_macos.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_macos.dart @@ -10,16 +10,6 @@ import 'keyboard_key.dart'; import 'keyboard_maps.dart'; import 'raw_keyboard.dart'; -/// Convert a UTF32 rune to its lower case. -int runeToLowerCase(int rune) { - // Assume only Basic Multilingual Plane runes have lower and upper cases. - // For other characters, return them as is. - const int utf16BmpUpperBound = 0xD7FF; - if (rune > utf16BmpUpperBound) - return rune; - return String.fromCharCode(rune).toLowerCase().codeUnitAt(0); -} - /// Platform-specific key event data for macOS. /// /// This object contains information about key events obtained from macOS's @@ -95,25 +85,25 @@ class RawKeyEventDataMacOs extends RawKeyEventData { return knownKey; } - // If this key is a single printable character, generate the - // LogicalKeyboardKey from its Unicode value. Control keys such as ESC, - // CTRL, and SHIFT are not printable. HOME, DEL, arrow keys, and function - // keys are considered modifier function keys, which generate invalid - // Unicode scalar values. Multi-char characters are also discarded. - int? character; - if (keyLabel.isNotEmpty) { - final List codePoints = keyLabel.runes.toList(); - if (codePoints.length == 1 && - // Ideally we should test whether `codePoints[0]` is in the range. - // Since LogicalKeyboardKey.isControlCharacter and _isUnprintableKey - // only tests BMP, it is fine to test keyLabel instead. - !LogicalKeyboardKey.isControlCharacter(keyLabel) && - !_isUnprintableKey(keyLabel)) { - character = runeToLowerCase(codePoints[0]); + // If this key is printable, generate the LogicalKeyboardKey from its + // Unicode value. Control keys such as ESC, CTRL, and SHIFT are not + // printable. HOME, DEL, arrow keys, and function keys are considered + // modifier function keys, which generate invalid Unicode scalar values. + if (keyLabel.isNotEmpty && + !LogicalKeyboardKey.isControlCharacter(keyLabel) && + !_isUnprintableKey(keyLabel)) { + // Given that charactersIgnoringModifiers can contain a String of + // arbitrary length, limit to a maximum of two Unicode scalar values. It + // is unlikely that a keyboard would produce a code point bigger than 32 + // bits, but it is still worth defending against this case. + assert(charactersIgnoringModifiers.length <= 2); + int codeUnit = charactersIgnoringModifiers.codeUnitAt(0); + if (charactersIgnoringModifiers.length == 2) { + final int secondCode = charactersIgnoringModifiers.codeUnitAt(1); + codeUnit = (codeUnit << 16) | secondCode; } - } - if (character != null) { - final int keyId = LogicalKeyboardKey.unicodePlane | (character & LogicalKeyboardKey.valueMask); + + final int keyId = LogicalKeyboardKey.unicodePlane | (codeUnit & LogicalKeyboardKey.valueMask); return LogicalKeyboardKey.findKeyByKeyId(keyId) ?? LogicalKeyboardKey(keyId); } diff --git a/packages/flutter/lib/src/services/raw_keyboard_web.dart b/packages/flutter/lib/src/services/raw_keyboard_web.dart index 3d107397cab32..4ae924e9d4f2f 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_web.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_web.dart @@ -32,7 +32,6 @@ class RawKeyEventDataWeb extends RawKeyEventData { required this.key, this.location = 0, this.metaState = modifierNone, - this.keyCode = 0, }) : assert(code != null), assert(metaState != null); @@ -81,12 +80,6 @@ class RawKeyEventDataWeb extends RawKeyEventData { /// * [isMetaPressed], to see if a META key is pressed. final int metaState; - /// The `KeyboardEvent.keyCode` corresponding to this event. - /// - /// See - /// for more information. - final int keyCode; - @override String get keyLabel => key == 'Unidentified' ? '' : _unicodeChar(key) ?? ''; @@ -111,7 +104,7 @@ class RawKeyEventDataWeb extends RawKeyEventData { final bool isPrintable = key.length == 1; if (isPrintable) - return LogicalKeyboardKey(key.toLowerCase().codeUnitAt(0)); + return LogicalKeyboardKey(key.codeUnitAt(0)); // This is a non-printable key that we don't know about, so we mint a new // key from `code`. Don't mint with `key`, because the `key` will always be @@ -163,7 +156,6 @@ class RawKeyEventDataWeb extends RawKeyEventData { properties.add(DiagnosticsProperty('key', key)); properties.add(DiagnosticsProperty('location', location)); properties.add(DiagnosticsProperty('metaState', metaState)); - properties.add(DiagnosticsProperty('keyCode', keyCode)); } @override @@ -176,8 +168,7 @@ class RawKeyEventDataWeb extends RawKeyEventData { && other.code == code && other.key == key && other.location == location - && other.metaState == metaState - && other.keyCode == keyCode; + && other.metaState == metaState; } @override @@ -186,7 +177,6 @@ class RawKeyEventDataWeb extends RawKeyEventData { key, location, metaState, - keyCode, ); // Modifier key masks. diff --git a/packages/flutter/lib/src/services/restoration.dart b/packages/flutter/lib/src/services/restoration.dart index 3ddedf1815595..5ca2731bddf4d 100644 --- a/packages/flutter/lib/src/services/restoration.dart +++ b/packages/flutter/lib/src/services/restoration.dart @@ -304,7 +304,7 @@ class RestorationManager extends ChangeNotifier { ); } - Future _methodHandler(MethodCall call) async { + Future _methodHandler(MethodCall call) async { switch (call.method) { case 'push': _parseAndHandleRestorationUpdateFromEngine(call.arguments as Map); diff --git a/packages/flutter/lib/src/services/system_channels.dart b/packages/flutter/lib/src/services/system_channels.dart index 582daee3d456d..49af63f230c57 100644 --- a/packages/flutter/lib/src/services/system_channels.dart +++ b/packages/flutter/lib/src/services/system_channels.dart @@ -240,7 +240,7 @@ class SystemChannels { /// * [RawKeyboard], which uses this channel to expose key data. /// * [new RawKeyEvent.fromMessage], which can decode this data into the [RawKeyEvent] /// subclasses mentioned above. - static const BasicMessageChannel keyEvent = BasicMessageChannel( + static const BasicMessageChannel keyEvent = BasicMessageChannel( 'flutter/keyevent', JSONMessageCodec(), ); @@ -271,7 +271,7 @@ class SystemChannels { /// applications to release caches to free up more memory. See /// [WidgetsBindingObserver.didHaveMemoryPressure], which triggers whenever /// a message is received on this channel. - static const BasicMessageChannel system = BasicMessageChannel( + static const BasicMessageChannel system = BasicMessageChannel( 'flutter/system', JSONMessageCodec(), ); @@ -283,7 +283,7 @@ class SystemChannels { /// * [SemanticsEvent] and its subclasses for a list of valid accessibility /// events that can be sent over this channel. /// * [SemanticsNode.sendEvent], which uses this channel to dispatch events. - static const BasicMessageChannel accessibility = BasicMessageChannel( + static const BasicMessageChannel accessibility = BasicMessageChannel( 'flutter/accessibility', StandardMessageCodec(), ); @@ -311,7 +311,7 @@ class SystemChannels { /// A [MethodChannel] for configuring mouse cursors. /// - /// All outgoing methods defined for this channel uses a `Map` + /// All outgoing methods defined for this channel uses a `Map` /// to contain multiple parameters, including the following methods (invoked /// using [OptionalMethodChannel.invokeMethod]): /// diff --git a/packages/flutter/lib/src/services/text_editing.dart b/packages/flutter/lib/src/services/text_editing.dart index 8286540a88811..2e4583bacef16 100644 --- a/packages/flutter/lib/src/services/text_editing.dart +++ b/packages/flutter/lib/src/services/text_editing.dart @@ -80,31 +80,8 @@ class TextSelection extends TextRange { /// The position at which the selection originates. /// - /// {@template flutter.services.TextSelection.TextAffinity} - /// The [TextAffinity] of the resulting [TextPosition] is based on the - /// relative logical position in the text to the other selection endpoint: - /// * if [baseOffset] < [extentOffset], [base] will have - /// [TextAffinity.downstream] and [extent] will have - /// [TextAffinity.upstream]. - /// * if [baseOffset] > [extentOffset], [base] will have - /// [TextAffinity.upstream] and [extent] will have - /// [TextAffinity.downstream]. - /// * if [baseOffset] == [extentOffset], [base] and [extent] will both have - /// the collapsed selection's [affinity]. - /// {@endtemplate} - /// /// Might be larger than, smaller than, or equal to extent. - TextPosition get base { - final TextAffinity affinity; - if (!isValid || baseOffset == extentOffset) { - affinity = this.affinity; - } else if (baseOffset < extentOffset) { - affinity = TextAffinity.downstream; - } else { - affinity = TextAffinity.upstream; - } - return TextPosition(offset: baseOffset, affinity: affinity); - } + TextPosition get base => TextPosition(offset: baseOffset, affinity: affinity); /// The position at which the selection terminates. /// @@ -112,20 +89,8 @@ class TextSelection extends TextRange { /// value that changes. Similarly, if the current theme paints a caret on one /// side of the selection, this is the location at which to paint the caret. /// - /// {@macro flutter.services.TextSelection.TextAffinity} - /// /// Might be larger than, smaller than, or equal to base. - TextPosition get extent { - final TextAffinity affinity; - if (!isValid || baseOffset == extentOffset) { - affinity = this.affinity; - } else if (baseOffset < extentOffset) { - affinity = TextAffinity.upstream; - } else { - affinity = TextAffinity.downstream; - } - return TextPosition(offset: extentOffset, affinity: affinity); - } + TextPosition get extent => TextPosition(offset: extentOffset, affinity: affinity); @override String toString() { @@ -238,8 +203,8 @@ class TextSelection extends TextRange { /// [TextSelection.extentOffset] to the given [TextPosition]. /// /// In some cases, the [TextSelection.baseOffset] and - /// [TextSelection.extentOffset] may flip during this operation, and/or the - /// size of the selection may shrink. + /// [TextSelection.extentOffset] may flip during this operation, or the size + /// of the selection may shrink. /// /// ## Difference with [expandTo] /// In contrast with this method, [expandTo] is strictly growth; the diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index 4a86b2dc37722..038f3d9c60d96 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -790,9 +790,6 @@ class TextEditingValue { /// /// The [text], [selection], and [composing] arguments must not be null but /// each have default values. - /// - /// The default value of [selection] is `TextSelection.collapsed(offset: -1)`. - /// This indicates that there is no selection at all. const TextEditingValue({ this.text = '', this.selection = const TextSelection.collapsed(offset: -1), @@ -883,55 +880,6 @@ class TextEditingValue { /// programming error. bool get isComposingRangeValid => composing.isValid && composing.isNormalized && composing.end <= text.length; - /// Returns a new [TextEditingValue], which is this [TextEditingValue] with - /// its [text] partially replaced by the `replacementString`. - /// - /// The `replacementRange` parameter specifies the range of the - /// [TextEditingValue.text] that needs to be replaced. - /// - /// The `replacementString` parameter specifies the string to replace the - /// given range of text with. - /// - /// This method also adjusts the selection range and the composing range of the - /// resulting [TextEditingValue], such that they point to the same substrings - /// as the correspoinding ranges in the original [TextEditingValue]. For - /// example, if the original [TextEditingValue] is "Hello world" with the word - /// "world" selected, replacing "Hello" with a different string using this - /// method will not change the selected word. - /// - /// This method does nothing if the given `replacementRange` is not - /// [TextRange.isValid]. - TextEditingValue replaced(TextRange replacementRange, String replacementString) { - if (!replacementRange.isValid) { - return this; - } - final String newText = text.replaceRange(replacementRange.start, replacementRange.end, replacementString); - - if (replacementRange.end - replacementRange.start == replacementString.length) { - return copyWith(text: newText); - } - - int adjustIndex(int originalIndex) { - // The length added by adding the replacementString. - final int replacedLength = originalIndex <= replacementRange.start && originalIndex < replacementRange.end ? 0 : replacementString.length; - // The length removed by removing the replacementRange. - final int removedLength = originalIndex.clamp(replacementRange.start, replacementRange.end) - replacementRange.start; - return originalIndex + replacedLength - removedLength; - } - - return TextEditingValue( - text: newText, - selection: TextSelection( - baseOffset: adjustIndex(selection.baseOffset), - extentOffset: adjustIndex(selection.extentOffset), - ), - composing: TextRange( - start: adjustIndex(composing.start), - end: adjustIndex(composing.end), - ), - ); - } - /// Returns a representation of this object as a JSON object. Map toJSON() { return { diff --git a/packages/flutter/lib/src/widgets/actions.dart b/packages/flutter/lib/src/widgets/actions.dart index d52dbfd500151..ed517d7f7b291 100644 --- a/packages/flutter/lib/src/widgets/actions.dart +++ b/packages/flutter/lib/src/widgets/actions.dart @@ -142,8 +142,8 @@ abstract class Action with Diagnosticable { /// /// {@tool dartpad} /// This sample implements a custom text input field that handles the - /// [DeleteCharacterIntent] intent, as well as a US telephone number input - /// widget that consists of multiple text fields for area code, prefix and line + /// [DeleteTextIntent] intent, as well as a US telephone number input widget + /// that consists of multiple text fields for area code, prefix and line /// number. When the backspace key is pressed, the phone number input widget /// sends the focus to the preceding text field when the currently focused /// field becomes empty. @@ -341,17 +341,17 @@ abstract class Action with Diagnosticable { // Make a local copy so that a listener can unregister while the list is // being iterated over. - final List localListeners = List.of(_listeners); + final List localListeners = List.from(_listeners); for (final ActionListenerCallback listener in localListeners) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty>( + collector = () sync* { + yield DiagnosticsProperty>( 'The $runtimeType sending notification was', this, style: DiagnosticsTreeStyle.errorProperty, - ), - ]; + ); + }; return true; }()); try { @@ -1064,7 +1064,6 @@ class FocusableActionDetector extends StatefulWidget { this.focusNode, this.autofocus = false, this.descendantsAreFocusable = true, - this.descendantsAreTraversable = true, this.shortcuts, this.actions, this.onShowFocusHighlight, @@ -1096,9 +1095,6 @@ class FocusableActionDetector extends StatefulWidget { /// {@macro flutter.widgets.Focus.descendantsAreFocusable} final bool descendantsAreFocusable; - /// {@macro flutter.widgets.Focus.descendantsAreTraversable} - final bool descendantsAreTraversable; - /// {@macro flutter.widgets.actions.actions} final Map>? actions; @@ -1285,7 +1281,6 @@ class _FocusableActionDetectorState extends State { focusNode: widget.focusNode, autofocus: widget.autofocus, descendantsAreFocusable: widget.descendantsAreFocusable, - descendantsAreTraversable: widget.descendantsAreTraversable, canRequestFocus: _canRequestFocus, onFocusChange: _handleFocusChange, child: widget.child, @@ -1494,7 +1489,7 @@ class PrioritizedAction extends Action { } @override - void invoke(PrioritizedIntents intent) { + Object? invoke(PrioritizedIntents intent) { assert(_selectedAction != null); assert(_selectedIntent != null); _selectedAction.invoke(_selectedIntent); diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index a076ba31c9b95..9b8a14112a808 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -12,6 +12,7 @@ import 'actions.dart'; import 'banner.dart'; import 'basic.dart'; import 'binding.dart'; +import 'default_text_editing_actions.dart'; import 'default_text_editing_shortcuts.dart'; import 'focus_traversal.dart'; import 'framework.dart'; @@ -111,11 +112,11 @@ typedef LocaleResolutionCallback = Locale? Function(Locale? locale, Iterable with WidgetsBindingObserver { // of a particular LocalizationsDelegate.type is loaded so the // localizationsDelegate parameter can be used to override // WidgetsLocalizations.delegate. - Iterable> get _localizationsDelegates { - return >[ - if (widget.localizationsDelegates != null) - ...widget.localizationsDelegates!, - DefaultWidgetsLocalizations.delegate, - ]; + Iterable> get _localizationsDelegates sync* { + if (widget.localizationsDelegates != null) + yield* widget.localizationsDelegates!; + yield DefaultWidgetsLocalizations.delegate; } // BUILDER @@ -1495,37 +1497,35 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { if (unsupportedTypes.isEmpty) return true; - FlutterError.reportError(FlutterErrorDetails( - exception: "Warning: This application's locale, $appLocale, is not supported by all of its localization delegates.", - library: 'widgets', - informationCollector: () => [ - for (final Type unsupportedType in unsupportedTypes) - ErrorDescription( - '• A $unsupportedType delegate that supports the $appLocale locale was not found.', - ), - ErrorSpacer(), - if (unsupportedTypes.length == 1 && unsupportedTypes.single.toString() == 'CupertinoLocalizations') - // We previously explicitly avoided checking for this class so it's not uncommon for applications - // to have omitted importing the required delegate. - ...[ - ErrorHint( - 'If the application is built using GlobalMaterialLocalizations.delegate, consider using ' - 'GlobalMaterialLocalizations.delegates (plural) instead, as that will automatically declare ' - 'the appropriate Cupertino localizations.' - ), - ErrorSpacer(), - ], - ErrorHint( - 'The declared supported locales for this app are: ${widget.supportedLocales.join(", ")}' - ), - ErrorSpacer(), - ErrorDescription( - 'See https://flutter.dev/tutorials/internationalization/ for more ' - "information about configuring an app's locale, supportedLocales, " - 'and localizationsDelegates parameters.', - ), - ], - )); + // Currently the Cupertino library only provides english localizations. + // Remove this when https://github.com/flutter/flutter/issues/23847 + // is fixed. + if (listEquals(unsupportedTypes.map((Type type) => type.toString()).toList(), ['CupertinoLocalizations'])) + return true; + + final StringBuffer message = StringBuffer(); + message.writeln('\u2550' * 8); + message.writeln( + "Warning: This application's locale, $appLocale, is not supported by all of its\n" + 'localization delegates.', + ); + for (final Type unsupportedType in unsupportedTypes) { + // Currently the Cupertino library only provides english localizations. + // Remove this when https://github.com/flutter/flutter/issues/23847 + // is fixed. + if (unsupportedType.toString() == 'CupertinoLocalizations') + continue; + message.writeln( + '> A $unsupportedType delegate that supports the $appLocale locale was not found.', + ); + } + message.writeln( + 'See https://flutter.dev/tutorials/internationalization/ for more\n' + "information about configuring an app's locale, supportedLocales,\n" + 'and localizationsDelegates parameters.', + ); + message.writeln('\u2550' * 8); + debugPrint(message.toString()); return true; }()); return true; @@ -1635,7 +1635,7 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { assert(title != null, 'onGenerateTitle must return a non-null String'); return Title( title: title, - color: widget.color.withOpacity(1.0), + color: widget.color, child: result, ); }, @@ -1643,7 +1643,7 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { } else { title = Title( title: widget.title, - color: widget.color.withOpacity(1.0), + color: widget.color, child: result, ); } @@ -1678,9 +1678,11 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { child: DefaultTextEditingShortcuts( child: Actions( actions: widget.actions ?? WidgetsApp.defaultActions, - child: FocusTraversalGroup( - policy: ReadingOrderTraversalPolicy(), - child: child, + child: DefaultTextEditingActions( + child: FocusTraversalGroup( + policy: ReadingOrderTraversalPolicy(), + child: child, + ), ), ), ), diff --git a/packages/flutter/lib/src/widgets/async.dart b/packages/flutter/lib/src/widgets/async.dart index fd2fb791401d0..5f8ebc46e5e17 100644 --- a/packages/flutter/lib/src/widgets/async.dart +++ b/packages/flutter/lib/src/widgets/async.dart @@ -249,7 +249,7 @@ class AsyncSnapshot { if (hasData) return data!; if (hasError) - Error.throwWithStackTrace(error!, stackTrace!); + throw error!; // ignore: only_throw_errors, since we're just propagating an existing error throw StateError('Snapshot has neither data nor error'); } diff --git a/packages/flutter/lib/src/widgets/autocomplete.dart b/packages/flutter/lib/src/widgets/autocomplete.dart index 0b30c284000b2..5802fdeba9f86 100644 --- a/packages/flutter/lib/src/widgets/autocomplete.dart +++ b/packages/flutter/lib/src/widgets/autocomplete.dart @@ -512,12 +512,16 @@ class _AutocompleteCallbackAction extends CallbackAction { } /// An [Intent] to highlight the previous option in the autocomplete list. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} class AutocompletePreviousOptionIntent extends Intent { /// Creates an instance of AutocompletePreviousOptionIntent. const AutocompletePreviousOptionIntent(); } /// An [Intent] to highlight the next option in the autocomplete list. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} class AutocompleteNextOptionIntent extends Intent { /// Creates an instance of AutocompleteNextOptionIntent. const AutocompleteNextOptionIntent(); diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 2b088176a2f25..43c9fa2195cdc 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -1262,13 +1262,10 @@ class Transform extends SingleChildRenderObjectWidget { alignment = null, super(key: key, child: child); - /// Creates a widget that scales its child along the 2D plane. + /// Creates a widget that scales its child uniformly. /// - /// The `scaleX` argument provides the scalar by which to multiply the `x` axis, and the `scaleY` argument provides the scalar by which to multiply the `y` axis. Either may be omitted, in which case that axis defaults to 1.0. - /// - /// For convenience, to scale the child uniformly, instead of providing `scaleX` and `scaleY`, the `scale` parameter may be used. - /// - /// At least one of `scale`, `scaleX`, and `scaleY` must be non-null. If `scale` is provided, the other two must be null; similarly, if it is not provided, one of the other two must be provided. + /// The `scale` argument must not be null. It gives the scalar by which + /// to multiply the `x` and `y` axes. /// /// The [alignment] controls the origin of the scale; by default, this is /// the center of the box. @@ -1296,18 +1293,14 @@ class Transform extends SingleChildRenderObjectWidget { /// over a given duration. Transform.scale({ Key? key, - double? scale, - double? scaleX, - double? scaleY, + required double scale, this.origin, this.alignment = Alignment.center, this.transformHitTests = true, this.filterQuality, Widget? child, - }) : assert(!(scale == null && scaleX == null && scaleY == null), "At least one of 'scale', 'scaleX' and 'scaleY' is required to be non-null"), - assert(scale == null || (scaleX == null && scaleY == null), "If 'scale' is non-null then 'scaleX' and 'scaleY' must be left null"), - transform = Matrix4.diagonal3Values(scale ?? scaleX ?? 1.0, scale ?? scaleY ?? 1.0, 1.0), - super(key: key, child: child); + }) : transform = Matrix4.diagonal3Values(scale, scale, 1.0), + super(key: key, child: child); /// The matrix to transform the child by during painting. final Matrix4 transform; @@ -2138,15 +2131,6 @@ class LayoutId extends ParentDataWidget { /// Each child must be wrapped in a [LayoutId] widget to identify the widget for /// the delegate. /// -/// {@tool dartpad} -/// This example shows a [CustomMultiChildLayout] widget being used to lay out -/// colored blocks from start to finish in a cascade that has some overlap. -/// -/// It responds to changes in [Directionality] by re-laying out its children. -/// -/// ** See code in examples/api/lib/widgets/basic/custom_multi_child_layout.0.dart ** -/// {@end-tool} -/// /// See also: /// /// * [MultiChildLayoutDelegate], for details about how to control the layout of @@ -4832,8 +4816,6 @@ class Row extends Flex { /// case is typically to remove the [Expanded] or [Flexible] widgets from around /// the inner children. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=jckqXR5CrPI} -/// /// For more discussion about constraints, see [BoxConstraints]. /// /// ### The yellow and black striped banner @@ -5572,7 +5554,7 @@ class RichText extends MultiChildRenderObjectWidget { /// {@macro flutter.painting.textPainter.textWidthBasis} final TextWidthBasis textWidthBasis; - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} final ui.TextHeightBehavior? textHeightBehavior; @override @@ -6146,7 +6128,6 @@ class Listener extends SingleChildRenderObjectWidget { if (onPointerDown != null) 'down', if (onPointerMove != null) 'move', if (onPointerUp != null) 'up', - if (onPointerHover != null) 'hover', if (onPointerCancel != null) 'cancel', if (onPointerSignal != null) 'signal', ]; @@ -6157,8 +6138,6 @@ class Listener extends SingleChildRenderObjectWidget { /// A widget that tracks the movement of mice. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=1oF3pI5umck} -/// /// [MouseRegion] is used /// when it is needed to compare the list of objects that a mouse pointer is /// hovering over between this frame and the last frame. This means entering diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index b9b375f3e5391..b5d9542a5537b 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -635,7 +635,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// [SystemChannels.navigation]. @protected Future handlePopRoute() async { - for (final WidgetsBindingObserver observer in List.of(_observers)) { + for (final WidgetsBindingObserver observer in List.from(_observers)) { if (await observer.didPopRoute()) return; } @@ -655,14 +655,14 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @protected @mustCallSuper Future handlePushRoute(String route) async { - for (final WidgetsBindingObserver observer in List.of(_observers)) { + for (final WidgetsBindingObserver observer in List.from(_observers)) { if (await observer.didPushRoute(route)) return; } } Future _handlePushRouteInformation(Map routeArguments) async { - for (final WidgetsBindingObserver observer in List.of(_observers)) { + for (final WidgetsBindingObserver observer in List.from(_observers)) { if ( await observer.didPushRouteInformation( RouteInformation( diff --git a/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart b/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart index 41f181992d786..9303d6b6a8e37 100644 --- a/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart +++ b/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart @@ -24,11 +24,17 @@ class BottomNavigationBarItem { /// The argument [icon] should not be null and the argument [label] should not be null when used in a Material Design's [BottomNavigationBar]. const BottomNavigationBarItem({ required this.icon, + @Deprecated( + 'Use "label" instead, as it allows for an improved text-scaling experience. ' + 'This feature was deprecated after v1.19.0.', + ) + this.title, this.label, Widget? activeIcon, this.backgroundColor, this.tooltip, }) : activeIcon = activeIcon ?? icon, + assert(label == null || title == null), assert(icon != null); /// The icon of the item. @@ -61,6 +67,15 @@ class BottomNavigationBarItem { /// * [BottomNavigationBarItem.icon], for a description of how to pair icons. final Widget activeIcon; + /// The title of the item. If the title is not provided only the icon will be shown when not used in a Material Design [BottomNavigationBar]. + /// + /// This field is deprecated, use [label] instead. + @Deprecated( + 'Use "label" instead, as it allows for an improved text-scaling experience. ' + 'This feature was deprecated after v1.19.0.', + ) + final Widget? title; + /// The text label for this [BottomNavigationBarItem]. /// /// This will be used to create a [Text] widget to put in the bottom navigation bar. diff --git a/packages/flutter/lib/src/widgets/debug.dart b/packages/flutter/lib/src/widgets/debug.dart index be19d6b60e6a0..8c364c2b33398 100644 --- a/packages/flutter/lib/src/widgets/debug.dart +++ b/packages/flutter/lib/src/widgets/debug.dart @@ -94,18 +94,9 @@ bool debugPrintGlobalKeyedWidgetLifecycle = false; /// Adds [Timeline] events for every Widget built. /// -/// The timing information this flag exposes is not representative of the actual -/// cost of building, because the overhead of adding timeline events is -/// significant relative to the time each object takes to build. However, it can -/// expose unexpected widget behavior in the timeline. -/// -/// In debug builds, additional information is included in the trace (such as -/// the properties of widgets being built). Collecting this data is -/// expensive and further makes these traces non-representative of actual -/// performance. This data is omitted in profile builds. -/// -/// For more information about performance debugging in Flutter, see -/// . +/// For details on how to use [Timeline] events in the Dart Observatory to +/// optimize your app, see https://flutter.dev/docs/testing/debugging#tracing-any-dart-code-performance +/// and https://fuchsia.googlesource.com/topaz/+/master/shell/docs/performance.md /// /// See also: /// diff --git a/packages/flutter/lib/src/widgets/default_text_editing_actions.dart b/packages/flutter/lib/src/widgets/default_text_editing_actions.dart new file mode 100644 index 0000000000000..e0c91e79a76a2 --- /dev/null +++ b/packages/flutter/lib/src/widgets/default_text_editing_actions.dart @@ -0,0 +1,326 @@ +// 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 'actions.dart'; +import 'editable_text.dart'; +import 'framework.dart'; +import 'text_editing_action.dart'; +import 'text_editing_intents.dart'; + +/// An [Actions] widget that handles the default text editing behavior for +/// Flutter on the current platform. +/// +/// This default behavior can be overridden by placing an [Actions] widget lower +/// in the widget tree than this. See [DefaultTextEditingShortcuts] for an example of +/// remapping keyboard keys to an existing text editing [Intent]. +/// +/// See also: +/// +/// * [DefaultTextEditingShortcuts], which maps keyboard keys to many of the +/// [Intent]s that are handled here. +/// * [WidgetsApp], which creates a DefaultTextEditingShortcuts. +class DefaultTextEditingActions extends Actions { + /// Creates an instance of DefaultTextEditingActions. + DefaultTextEditingActions({ + Key? key, + required Widget child, + }) : super( + key: key, + actions: _shortcutsActions, + child: child, + ); + + // These Intents are triggered by DefaultTextEditingShortcuts. They are included + // regardless of the platform; it's up to DefaultTextEditingShortcuts to decide which + // are called on which platform. + static final Map> _shortcutsActions = >{ + DoNothingAndStopPropagationTextIntent: _DoNothingAndStopPropagationTextAction(), + DeleteTextIntent: _DeleteTextAction(), + DeleteByWordTextIntent: _DeleteByWordTextAction(), + DeleteByLineTextIntent: _DeleteByLineTextAction(), + DeleteForwardTextIntent: _DeleteForwardTextAction(), + DeleteForwardByWordTextIntent: _DeleteForwardByWordTextAction(), + DeleteForwardByLineTextIntent: _DeleteForwardByLineTextAction(), + ExtendSelectionDownTextIntent: _ExtendSelectionDownTextAction(), + ExtendSelectionLeftByLineTextIntent: _ExtendSelectionLeftByLineTextAction(), + ExtendSelectionLeftByWordTextIntent: _ExtendSelectionLeftByWordTextAction(), + ExtendSelectionLeftByWordAndStopAtReversalTextIntent: _ExtendSelectionLeftByWordAndStopAtReversalTextAction(), + ExtendSelectionLeftTextIntent: _ExtendSelectionLeftTextAction(), + ExtendSelectionRightByWordAndStopAtReversalTextIntent: _ExtendSelectionRightByWordAndStopAtReversalTextAction(), + ExtendSelectionRightByWordTextIntent: _ExtendSelectionRightByWordTextAction(), + ExtendSelectionRightByLineTextIntent: _ExtendSelectionRightByLineTextAction(), + ExtendSelectionRightTextIntent: _ExtendSelectionRightTextAction(), + ExtendSelectionUpTextIntent: _ExtendSelectionUpTextAction(), + ExpandSelectionLeftByLineTextIntent: _ExpandSelectionLeftByLineTextAction(), + ExpandSelectionRightByLineTextIntent: _ExpandSelectionRightByLineTextAction(), + ExpandSelectionToEndTextIntent: _ExpandSelectionToEndTextAction(), + ExpandSelectionToStartTextIntent: _ExpandSelectionToStartTextAction(), + MoveSelectionDownTextIntent: _MoveSelectionDownTextAction(), + MoveSelectionLeftByLineTextIntent: _MoveSelectionLeftByLineTextAction(), + MoveSelectionLeftByWordTextIntent: _MoveSelectionLeftByWordTextAction(), + MoveSelectionLeftTextIntent: _MoveSelectionLeftTextAction(), + MoveSelectionRightByLineTextIntent: _MoveSelectionRightByLineTextAction(), + MoveSelectionRightByWordTextIntent: _MoveSelectionRightByWordTextAction(), + MoveSelectionRightTextIntent: _MoveSelectionRightTextAction(), + MoveSelectionToEndTextIntent: _MoveSelectionToEndTextAction(), + MoveSelectionToStartTextIntent: _MoveSelectionToStartTextAction(), + MoveSelectionUpTextIntent: _MoveSelectionUpTextAction(), + SelectAllTextIntent: _SelectAllTextAction(), + CopySelectionTextIntent: _CopySelectionTextAction(), + CutSelectionTextIntent: _CutSelectionTextAction(), + PasteTextIntent: _PasteTextAction(), + }; +} + +// This allows the web engine to handle text editing events natively while using +// the same TextEditingAction logic to only handle events from a +// TextEditingTarget. +class _DoNothingAndStopPropagationTextAction extends TextEditingAction { + _DoNothingAndStopPropagationTextAction(); + + @override + bool consumesKey(Intent intent) => false; + + @override + void invoke(DoNothingAndStopPropagationTextIntent intent, [BuildContext? context]) {} +} + +class _DeleteTextAction extends TextEditingAction { + @override + Object? invoke(DeleteTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.delete(SelectionChangedCause.keyboard); + } +} + +class _DeleteByWordTextAction extends TextEditingAction { + @override + Object? invoke(DeleteByWordTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.deleteByWord(SelectionChangedCause.keyboard, false); + } +} + +class _DeleteByLineTextAction extends TextEditingAction { + @override + Object? invoke(DeleteByLineTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.deleteByLine(SelectionChangedCause.keyboard); + } +} + +class _DeleteForwardTextAction extends TextEditingAction { + @override + Object? invoke(DeleteForwardTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.deleteForward(SelectionChangedCause.keyboard); + } +} + +class _DeleteForwardByWordTextAction extends TextEditingAction { + @override + Object? invoke(DeleteForwardByWordTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.deleteForwardByWord(SelectionChangedCause.keyboard, false); + } +} + +class _DeleteForwardByLineTextAction extends TextEditingAction { + @override + Object? invoke(DeleteForwardByLineTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.deleteForwardByLine(SelectionChangedCause.keyboard); + } +} + +class _ExpandSelectionLeftByLineTextAction extends TextEditingAction { + @override + Object? invoke(ExpandSelectionLeftByLineTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.expandSelectionLeftByLine(SelectionChangedCause.keyboard); + } +} + +class _ExpandSelectionRightByLineTextAction extends TextEditingAction { + @override + Object? invoke(ExpandSelectionRightByLineTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.expandSelectionRightByLine(SelectionChangedCause.keyboard); + } +} + +class _ExpandSelectionToEndTextAction extends TextEditingAction { + @override + Object? invoke(ExpandSelectionToEndTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.expandSelectionToEnd(SelectionChangedCause.keyboard); + } +} + +class _ExpandSelectionToStartTextAction extends TextEditingAction { + @override + Object? invoke(ExpandSelectionToStartTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.expandSelectionToStart(SelectionChangedCause.keyboard); + } +} + +class _ExtendSelectionDownTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionDownTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionDown(SelectionChangedCause.keyboard); + } +} + +class _ExtendSelectionLeftByLineTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionLeftByLineTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionLeftByLine(SelectionChangedCause.keyboard); + } +} + +class _ExtendSelectionLeftByWordAndStopAtReversalTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionLeftByWordAndStopAtReversalTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionLeftByWord(SelectionChangedCause.keyboard, false, true); + } +} + +class _ExtendSelectionLeftByWordTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionLeftByWordTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionLeftByWord(SelectionChangedCause.keyboard, false); + } +} + +class _ExtendSelectionLeftTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionLeftTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionLeft(SelectionChangedCause.keyboard); + } +} + +class _ExtendSelectionRightByLineTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionRightByLineTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionRightByLine(SelectionChangedCause.keyboard); + } +} + +class _ExtendSelectionRightByWordAndStopAtReversalTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionRightByWordAndStopAtReversalTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionRightByWord(SelectionChangedCause.keyboard, false, true); + } +} + +class _ExtendSelectionRightByWordTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionRightByWordTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionRightByWord(SelectionChangedCause.keyboard, false); + } +} + +class _ExtendSelectionRightTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionRightTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionRight(SelectionChangedCause.keyboard); + } +} + +class _ExtendSelectionUpTextAction extends TextEditingAction { + @override + Object? invoke(ExtendSelectionUpTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.extendSelectionUp(SelectionChangedCause.keyboard); + } +} + +class _MoveSelectionDownTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionDownTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionDown(SelectionChangedCause.keyboard); + } +} + +class _MoveSelectionLeftTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionLeftTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionLeft(SelectionChangedCause.keyboard); + } +} + +class _MoveSelectionRightTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionRightTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionRight(SelectionChangedCause.keyboard); + } +} + +class _MoveSelectionUpTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionUpTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionUp(SelectionChangedCause.keyboard); + } +} + +class _MoveSelectionLeftByLineTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionLeftByLineTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionLeftByLine(SelectionChangedCause.keyboard); + } +} + +class _MoveSelectionLeftByWordTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionLeftByWordTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionLeftByWord(SelectionChangedCause.keyboard, false); + } +} + +class _MoveSelectionRightByLineTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionRightByLineTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionRightByLine(SelectionChangedCause.keyboard); + } +} + +class _MoveSelectionRightByWordTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionRightByWordTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionRightByWord(SelectionChangedCause.keyboard, false); + } +} + +class _MoveSelectionToEndTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionToEndTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionToEnd(SelectionChangedCause.keyboard); + } +} + +class _MoveSelectionToStartTextAction extends TextEditingAction { + @override + Object? invoke(MoveSelectionToStartTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionToStart(SelectionChangedCause.keyboard); + } +} + + +class _SelectAllTextAction extends TextEditingAction { + @override + Object? invoke(SelectAllTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.selectAll(SelectionChangedCause.keyboard); + } +} + +class _CopySelectionTextAction extends TextEditingAction { + @override + Object? invoke(CopySelectionTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.copySelection(SelectionChangedCause.keyboard); + } +} + +class _CutSelectionTextAction extends TextEditingAction { + @override + Object? invoke(CutSelectionTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.cutSelection(SelectionChangedCause.keyboard); + } +} + +class _PasteTextAction extends TextEditingAction { + @override + Object? invoke(PasteTextIntent intent, [BuildContext? context]) { + textEditingActionTarget!.pasteText(SelectionChangedCause.keyboard); + } +} diff --git a/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart b/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart index 370dd4b8190d7..a18dc58fcbdef 100644 --- a/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart +++ b/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart @@ -14,8 +14,8 @@ import 'text_editing_intents.dart'; /// behavior. /// /// This default behavior can be overridden by placing a [Shortcuts] widget -/// lower in the widget tree than this. See the [Action] class for an example -/// of remapping an [Intent] to a custom [Action]. +/// lower in the widget tree than this. See [DefaultTextEditingActions] for an example +/// of remapping a text editing [Intent] to a custom [Action]. /// /// {@tool snippet} /// @@ -108,7 +108,6 @@ import 'text_editing_intents.dart'; /// setState(() { /// _counter++; /// }); -/// return null; /// }, /// ), /// DecrementCounterIntent: CallbackAction( @@ -116,7 +115,6 @@ import 'text_editing_intents.dart'; /// setState(() { /// _counter--; /// }); -/// return null; /// }, /// ), /// }, @@ -145,6 +143,9 @@ import 'text_editing_intents.dart'; /// /// See also: /// +/// * [DefaultTextEditingActions], which contains all of the [Action]s that +/// respond to the [Intent]s in these shortcuts with the default text editing +/// behavior. /// * [WidgetsApp], which creates a DefaultTextEditingShortcuts. class DefaultTextEditingShortcuts extends Shortcuts { /// Creates a [Shortcuts] widget that provides the default text editing @@ -159,255 +160,376 @@ class DefaultTextEditingShortcuts extends Shortcuts { child: child, ); - // These are shortcuts are shared between most platforms except macOS for it - // uses different modifier keys as the line/word modifer. - static final Map _commonShortcuts = { - // Delete Shortcuts. - for (final bool pressShift in const [true, false]) - ...{ - SingleActivator(LogicalKeyboardKey.backspace, shift: pressShift): const DeleteCharacterIntent(forward: false), - SingleActivator(LogicalKeyboardKey.backspace, control: true, shift: pressShift): const DeleteToNextWordBoundaryIntent(forward: false), - SingleActivator(LogicalKeyboardKey.backspace, alt: true, shift: pressShift): const DeleteToLineBreakIntent(forward: false), - SingleActivator(LogicalKeyboardKey.delete, shift: pressShift): const DeleteCharacterIntent(forward: true), - SingleActivator(LogicalKeyboardKey.delete, control: true, shift: pressShift): const DeleteToNextWordBoundaryIntent(forward: true), - SingleActivator(LogicalKeyboardKey.delete, alt: true, shift: pressShift): const DeleteToLineBreakIntent(forward: true), - }, - - // Arrow: Move Selection. - const SingleActivator(LogicalKeyboardKey.arrowLeft): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowRight): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowUp): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowDown): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: true), - - // Shift + Arrow: Extend Selection. - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: false), - - const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: true), - - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: false), - - const SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowRight, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: true), - - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: false), - - const SingleActivator(LogicalKeyboardKey.keyX, control: true): const CopySelectionTextIntent.cut(SelectionChangedCause.keyboard), - const SingleActivator(LogicalKeyboardKey.keyC, control: true): CopySelectionTextIntent.copy, - const SingleActivator(LogicalKeyboardKey.keyV, control: true): const PasteTextIntent(SelectionChangedCause.keyboard), - const SingleActivator(LogicalKeyboardKey.keyA, control: true): const SelectAllTextIntent(SelectionChangedCause.keyboard), + static const Map _androidShortcuts = { + SingleActivator(LogicalKeyboardKey.backspace): DeleteTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, control: true): DeleteByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, alt: true): DeleteByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.delete): DeleteForwardTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, control: true): DeleteForwardByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, alt: true): DeleteForwardByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): MoveSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): MoveSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): MoveSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): MoveSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): ExpandSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): ExpandSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): ExpandSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): ExpandSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown): MoveSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft): MoveSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp): MoveSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): MoveSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, control: true): MoveSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): ExtendSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): ExtendSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): ExtendSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): ExtendSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): ExtendSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): ExtendSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.keyX, control: true): CutSelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyC, control: true): CopySelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyV, control: true): PasteTextIntent(), + SingleActivator(LogicalKeyboardKey.keyA, control: true): SelectAllTextIntent(), + // The following key combinations have no effect on text editing on this + // platform: + // * End + // * Home + // * Meta + X + // * Meta + C + // * Meta + V + // * Meta + A + // * Meta + arrow down + // * Meta + arrow left + // * Meta + arrow right + // * Meta + arrow up + // * Meta + shift + arrow down + // * Meta + shift + arrow left + // * Meta + shift + arrow right + // * Meta + shift + arrow up + // * Shift + end + // * Shift + home + // * Meta + delete + // * Meta + backspace }; - // The following key combinations have no effect on text editing on this - // platform: - // * End - // * Home - // * Meta + X - // * Meta + C - // * Meta + V - // * Meta + A - // * Meta + shift? + arrow down - // * Meta + shift? + arrow left - // * Meta + shift? + arrow right - // * Meta + shift? + arrow up - // * Shift + end - // * Shift + home - // * Meta + shift? + delete - // * Meta + shift? + backspace - static final Map _androidShortcuts = _commonShortcuts; - - static final Map _fuchsiaShortcuts = _androidShortcuts; - - // The following key combinations have no effect on text editing on this - // platform: - // * End - // * Home - // * Meta + X - // * Meta + C - // * Meta + V - // * Meta + A - // * Meta + shift? + arrow down - // * Meta + shift? + arrow left - // * Meta + shift? + arrow right - // * Meta + shift? + arrow up - // * Shift + end - // * Shift + home - // * Meta + shift? + delete - // * Meta + shift? + backspace - static final Map _iOSShortcuts = _commonShortcuts; - - static final Map _linuxShortcuts = { - ..._commonShortcuts, - const SingleActivator(LogicalKeyboardKey.home): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.end): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.home, shift: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.end, shift: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: false), + static const Map _fuchsiaShortcuts = { + SingleActivator(LogicalKeyboardKey.backspace): DeleteTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, control: true): DeleteByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, alt: true): DeleteByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.delete): DeleteForwardTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, control: true): DeleteForwardByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, alt: true): DeleteForwardByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): MoveSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): MoveSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): MoveSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): MoveSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): ExpandSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): ExpandSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): ExpandSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): ExpandSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown): MoveSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft): MoveSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp): MoveSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): MoveSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, control: true): MoveSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): ExtendSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): ExtendSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): ExtendSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): ExtendSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): ExtendSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): ExtendSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.keyX, control: true): CutSelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyC, control: true): CopySelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyV, control: true): PasteTextIntent(), + SingleActivator(LogicalKeyboardKey.keyA, control: true): SelectAllTextIntent(), // The following key combinations have no effect on text editing on this // platform: - // * Control + shift? + end - // * Control + shift? + home + // * End + // * Home // * Meta + X // * Meta + C // * Meta + V // * Meta + A - // * Meta + shift? + arrow down - // * Meta + shift? + arrow left - // * Meta + shift? + arrow right - // * Meta + shift? + arrow up - // * Meta + shift? + delete - // * Meta + shift? + backspace + // * Meta + arrow down + // * Meta + arrow left + // * Meta + arrow right + // * Meta + arrow up + // * Meta + shift + arrow down + // * Meta + shift + arrow left + // * Meta + shift + arrow right + // * Meta + shift + arrow up + // * Shift + end + // * Shift + home + // * Meta + delete + // * Meta + backspace }; - // macOS document shortcuts: https://support.apple.com/en-us/HT201236. - // The macOS shortcuts uses different word/line modifiers than most other - // platforms. - static final Map _macShortcuts = { - for (final bool pressShift in const [true, false]) - ...{ - SingleActivator(LogicalKeyboardKey.backspace, shift: pressShift): const DeleteCharacterIntent(forward: false), - SingleActivator(LogicalKeyboardKey.backspace, alt: true, shift: pressShift): const DeleteToNextWordBoundaryIntent(forward: false), - SingleActivator(LogicalKeyboardKey.backspace, meta: true, shift: pressShift): const DeleteToLineBreakIntent(forward: false), - SingleActivator(LogicalKeyboardKey.delete, shift: pressShift): const DeleteCharacterIntent(forward: true), - SingleActivator(LogicalKeyboardKey.delete, alt: true, shift: pressShift): const DeleteToNextWordBoundaryIntent(forward: true), - SingleActivator(LogicalKeyboardKey.delete, meta: true, shift: pressShift): const DeleteToLineBreakIntent(forward: true), - }, - - const SingleActivator(LogicalKeyboardKey.arrowLeft): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowRight): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowUp): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowDown): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: true), - - // Shift + Arrow: Extend Selection. - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): const ExtendSelectionByCharacterIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): const ExtendSelectionByCharacterIntent(forward: true, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): const ExtendSelectionVerticallyToAdjacentLineIntent(forward: true, collapseSelection: false), - - const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): const ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): const ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), - - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): const ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(forward: false), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): const ExtendSelectionToNextWordBoundaryOrCaretLocationIntent(forward: true), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: false, collapseAtReversal: true), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: false, collapseAtReversal: true), - - const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: true), - - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true): const ExpandSelectionToLineBreakIntent(forward: false), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true): const ExpandSelectionToLineBreakIntent(forward: true), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: false), + static const Map _iOSShortcuts = { + SingleActivator(LogicalKeyboardKey.backspace): DeleteTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, control: true): DeleteByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, alt: true): DeleteByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.delete): DeleteForwardTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, control: true): DeleteForwardByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, alt: true): DeleteForwardByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): MoveSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): MoveSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): MoveSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): MoveSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): ExpandSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): ExpandSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): ExpandSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): ExpandSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown): MoveSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft): MoveSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp): MoveSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, control: true): MoveSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): MoveSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): ExtendSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): ExtendSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): ExtendSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): ExtendSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): ExtendSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): ExtendSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.keyX, control: true): CutSelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyC, control: true): CopySelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyV, control: true): PasteTextIntent(), + SingleActivator(LogicalKeyboardKey.keyA, control: true): SelectAllTextIntent(), + // The following key combinations have no effect on text editing on this + // platform: + // * End + // * Home + // * Meta + X + // * Meta + C + // * Meta + V + // * Meta + A + // * Meta + arrow down + // * Meta + arrow left + // * Meta + arrow right + // * Meta + arrow up + // * Meta + shift + arrow down + // * Meta + shift + arrow left + // * Meta + shift + arrow right + // * Meta + shift + arrow up + // * Shift + end + // * Shift + home + // * Meta + delete + // * Meta + backspace + }; - const SingleActivator(LogicalKeyboardKey.home, shift: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.end, shift: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: false), + static const Map _linuxShortcuts = { + SingleActivator(LogicalKeyboardKey.backspace): DeleteTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, control: true): DeleteByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, alt: true): DeleteByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.delete): DeleteForwardTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, control: true): DeleteForwardByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, alt: true): DeleteForwardByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): MoveSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): MoveSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): MoveSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): MoveSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): ExpandSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): ExpandSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): ExpandSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): ExpandSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown): MoveSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft): MoveSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp): MoveSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): MoveSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, control: true): MoveSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): ExtendSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): ExtendSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): ExtendSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): ExtendSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): ExtendSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): ExtendSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.end): MoveSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.home): MoveSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.end, shift: true): ExtendSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.home, shift: true): ExtendSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.keyX, control: true): CutSelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyC, control: true): CopySelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyV, control: true): PasteTextIntent(), + SingleActivator(LogicalKeyboardKey.keyA, control: true): SelectAllTextIntent(), + // The following key combinations have no effect on text editing on this + // platform: + // * Meta + X + // * Meta + C + // * Meta + V + // * Meta + A + // * Meta + arrow down + // * Meta + arrow left + // * Meta + arrow right + // * Meta + arrow up + // * Meta + shift + arrow down + // * Meta + shift + arrow left + // * Meta + shift + arrow right + // * Meta + shift + arrow up + // * Meta + delete + // * Meta + backspace + }; - const SingleActivator(LogicalKeyboardKey.keyX, meta: true): const CopySelectionTextIntent.cut(SelectionChangedCause.keyboard), - const SingleActivator(LogicalKeyboardKey.keyC, meta: true): CopySelectionTextIntent.copy, - const SingleActivator(LogicalKeyboardKey.keyV, meta: true): const PasteTextIntent(SelectionChangedCause.keyboard), - const SingleActivator(LogicalKeyboardKey.keyA, meta: true): const SelectAllTextIntent(SelectionChangedCause.keyboard), + static const Map _macShortcuts = { + SingleActivator(LogicalKeyboardKey.backspace): DeleteTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, alt: true): DeleteByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, meta: true): DeleteByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.delete): DeleteForwardTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, alt: true): DeleteForwardByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, meta: true): DeleteForwardByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): MoveSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): MoveSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): MoveSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): MoveSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): ExtendSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): ExtendSelectionLeftByWordAndStopAtReversalTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): ExtendSelectionRightByWordAndStopAtReversalTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): ExtendSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown): MoveSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft): MoveSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp): MoveSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): MoveSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): MoveSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): MoveSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): MoveSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true): ExpandSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true): ExpandSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true): ExpandSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true): ExpandSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): ExtendSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): ExtendSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): ExtendSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): ExtendSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.end, shift: true): ExpandSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.home, shift: true): ExpandSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.keyX, meta: true): CutSelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyC, meta: true): CopySelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyV, meta: true): PasteTextIntent(), + SingleActivator(LogicalKeyboardKey.keyA, meta: true): SelectAllTextIntent(), // The following key combinations have no effect on text editing on this // platform: + // * Control + X + // * Control + C + // * Control + V + // * Control + A + // * Control + arrow left + // * Control + arrow right + // * Control + shift + arrow left + // * Control + shift + arrow right // * End // * Home - // * Control + shift? + end - // * Control + shift? + home + // * Control + delete + // * Control + backspace }; - // The following key combinations have no effect on text editing on this - // platform: - // * Meta + X - // * Meta + C - // * Meta + V - // * Meta + A - // * Meta + shift? + arrow down - // * Meta + shift? + arrow left - // * Meta + shift? + arrow right - // * Meta + shift? + arrow up - // * Meta + delete - // * Meta + backspace - static final Map _windowsShortcuts = { - ..._commonShortcuts, - const SingleActivator(LogicalKeyboardKey.home): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.end): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.home, shift: true): const ExtendSelectionToLineBreakIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.end, shift: true): const ExtendSelectionToLineBreakIntent(forward: true, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.home, control: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.end, control: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: true), - const SingleActivator(LogicalKeyboardKey.home, shift: true, control: true): const ExtendSelectionToDocumentBoundaryIntent(forward: false, collapseSelection: false), - const SingleActivator(LogicalKeyboardKey.end, shift: true, control: true): const ExtendSelectionToDocumentBoundaryIntent(forward: true, collapseSelection: false), + static const Map _windowsShortcuts = { + SingleActivator(LogicalKeyboardKey.backspace): DeleteTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, control: true): DeleteByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, alt: true): DeleteByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.delete): DeleteForwardTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, control: true): DeleteForwardByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, alt: true): DeleteForwardByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): MoveSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): MoveSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): MoveSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): MoveSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): ExpandSelectionToEndTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): ExpandSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): ExpandSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): ExpandSelectionToStartTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown): MoveSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft): MoveSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp): MoveSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): MoveSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, control: true): MoveSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): ExtendSelectionLeftByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): ExtendSelectionRightByWordTextIntent(), + SingleActivator(LogicalKeyboardKey.end): MoveSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.home): MoveSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): ExtendSelectionDownTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): ExtendSelectionLeftTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): ExtendSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): ExtendSelectionUpTextIntent(), + SingleActivator(LogicalKeyboardKey.end, shift: true): ExtendSelectionRightByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.home, shift: true): ExtendSelectionLeftByLineTextIntent(), + SingleActivator(LogicalKeyboardKey.keyX, control: true): CutSelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyC, control: true): CopySelectionTextIntent(), + SingleActivator(LogicalKeyboardKey.keyV, control: true): PasteTextIntent(), + SingleActivator(LogicalKeyboardKey.keyA, control: true): SelectAllTextIntent(), + // The following key combinations have no effect on text editing on this + // platform: + // * Meta + X + // * Meta + C + // * Meta + V + // * Meta + A + // * Meta + arrow down + // * Meta + arrow left + // * Meta + arrow right + // * Meta + arrow up + // * Meta + shift + arrow down + // * Meta + shift + arrow left + // * Meta + shift + arrow right + // * Meta + shift + arrow up + // * Meta + delete + // * Meta + backspace }; // Web handles its text selection natively and doesn't use any of these // shortcuts in Flutter. - static final Map _webShortcuts = { - for (final bool pressShift in const [true, false]) - ...{ - SingleActivator(LogicalKeyboardKey.backspace, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), - SingleActivator(LogicalKeyboardKey.delete, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), - SingleActivator(LogicalKeyboardKey.backspace, alt: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), - SingleActivator(LogicalKeyboardKey.delete, alt: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), - SingleActivator(LogicalKeyboardKey.backspace, control: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), - SingleActivator(LogicalKeyboardKey.delete, control: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), - SingleActivator(LogicalKeyboardKey.backspace, meta: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), - SingleActivator(LogicalKeyboardKey.delete, meta: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), - }, - const SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.end): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.home): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.end, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.home, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.end, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.home, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.space): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.keyX, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.keyX, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.keyC, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.keyC, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.keyV, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.keyV, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.keyA, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.keyA, meta: true): const DoNothingAndStopPropagationTextIntent(), + static const Map _webShortcuts = { + SingleActivator(LogicalKeyboardKey.backspace): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.delete): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.backspace, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.delete, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.end): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.home): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.end, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.home, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.space): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.keyX, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.keyX, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.keyC, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.keyC, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.keyV, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.keyV, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.keyA, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.keyA, meta: true): DoNothingAndStopPropagationTextIntent(), }; static Map get _shortcuts { diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart index 7325c8f9ed886..58a249bfbf094 100644 --- a/packages/flutter/lib/src/widgets/drag_target.dart +++ b/packages/flutter/lib/src/widgets/drag_target.dart @@ -905,19 +905,17 @@ class _DragAvatar extends Drag { _activeTarget = newTarget; } - Iterable<_DragTargetState> _getDragTargets(Iterable path) { + Iterable<_DragTargetState> _getDragTargets(Iterable path) sync* { // Look for the RenderBoxes that corresponds to the hit target (the hit target // widgets build RenderMetaData boxes for us for this purpose). - final List<_DragTargetState> targets = <_DragTargetState>[]; for (final HitTestEntry entry in path) { final HitTestTarget target = entry.target; if (target is RenderMetaData) { final dynamic metaData = target.metaData; if (metaData is _DragTargetState && metaData.isExpectedDataType(data, T)) - targets.add(metaData); + yield metaData; } } - return targets; } void _leaveAllEntered() { diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart index b515af55f22aa..60fbae424b471 100644 --- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart @@ -6,7 +6,6 @@ import 'dart:math' as math; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; -import 'package:flutter/physics.dart'; import 'basic.dart'; import 'binding.dart'; @@ -35,159 +34,6 @@ typedef ScrollableWidgetBuilder = Widget Function( ScrollController scrollController, ); -/// Controls a [DraggableScrollableSheet]. -/// -/// Draggable scrollable controllers are typically stored as member variables in -/// [State] objects and are reused in each [State.build]. Controllers can only -/// be used to control one sheet at a time. A controller can be reused with a -/// new sheet if the previous sheet has been disposed. -/// -/// The controller's methods cannot be used until after the controller has been -/// passed into a [DraggableScrollableSheet] and the sheet has run initState. -/// -/// A [DraggableScrollableController] is a [Listenable]. It notifies its -/// listeners whenever an attached sheet changes sizes. It does not notify its -/// listeners when a sheet is first attached or when an attached sheet's -/// parameters change without affecting the sheet's current size. It does not -/// fire when [pixels] changes without [size] changing. For example, if the -/// constraints provided to an attached sheet change. -class DraggableScrollableController extends ChangeNotifier { - _DraggableScrollableSheetScrollController? _attachedController; - - /// Get the current size (as a fraction of the parent height) of the attached sheet. - double get size { - _assertAttached(); - return _attachedController!.extent.currentSize; - } - - /// Get the current pixel height of the attached sheet. - double get pixels { - _assertAttached(); - return _attachedController!.extent.currentPixels; - } - - /// Convert a sheet's size (fractional value of parent container height) to pixels. - double sizeToPixels(double size) { - _assertAttached(); - return _attachedController!.extent.sizeToPixels(size); - } - - /// Convert a sheet's pixel height to size (fractional value of parent container height). - double pixelsToSize(double pixels) { - _assertAttached(); - return _attachedController!.extent.pixelsToSize(pixels); - } - - /// Animates the attached sheet from its current size to [size] to the - /// provided new `size`, a fractional value of the parent container's height. - /// - /// Any active sheet animation is canceled. If the sheet's internal scrollable - /// is currently animating (e.g. responding to a user fling), that animation is - /// canceled as well. - /// - /// An animation will be interrupted whenever the user attempts to scroll - /// manually, whenever another activity is started, or when the sheet hits its - /// max or min size (e.g. if you animate to 1 but the max size is .8, the - /// animation will stop playing when it reaches .8). - /// - /// The duration must not be zero. To jump to a particular value without an - /// animation, use [jumpTo]. - /// - /// When calling [animateTo] in widget tests, `await`ing the returned - /// [Future] may cause the test to hang and timeout. Instead, use - /// [WidgetTester.pumpAndSettle]. - Future animateTo( - double size, { - required Duration duration, - required Curve curve, - }) async { - _assertAttached(); - assert(size >= 0 && size <= 1); - assert(duration != Duration.zero); - final AnimationController animationController = AnimationController.unbounded( - vsync: _attachedController!.position.context.vsync, - value: _attachedController!.extent.currentSize, - ); - _attachedController!.position.goIdle(); - // This disables any snapping until the next user interaction with the sheet. - _attachedController!.extent.hasDragged = false; - _attachedController!.extent.startActivity(onCanceled: () { - // Don't stop the controller if it's already finished and may have been disposed. - if (animationController.isAnimating) { - animationController.stop(); - } - }); - CurvedAnimation(parent: animationController, curve: curve).addListener(() { - _attachedController!.extent.updateSize( - animationController.value, - _attachedController!.position.context.notificationContext!, - ); - if (animationController.value > _attachedController!.extent.maxSize || - animationController.value < _attachedController!.extent.minSize) { - // Animation hit the max or min size, stop animating. - animationController.stop(canceled: false); - } - }); - await animationController.animateTo(size, duration: duration); - } - - /// Jumps the attached sheet from its current size to the given [size], a - /// fractional value of the parent container's height. - /// - /// If [size] is outside of a the attached sheet's min or max child size, - /// [jumpTo] will jump the sheet to the nearest valid size instead. - /// - /// Any active sheet animation is canceled. If the sheet's inner scrollable - /// is currently animating (e.g. responding to a user fling), that animation is - /// canceled as well. - void jumpTo(double size) { - _assertAttached(); - assert(size >= 0 && size <= 1); - // Call start activity to interrupt any other playing activities. - _attachedController!.extent.startActivity(onCanceled: () {}); - _attachedController!.position.goIdle(); - _attachedController!.extent.hasDragged = false; - _attachedController!.extent.updateSize(size, _attachedController!.position.context.notificationContext!); - } - - /// Reset the attached sheet to its initial size (see: [DraggableScrollableSheet.initialChildSize]). - void reset() { - _assertAttached(); - _attachedController!.reset(); - } - - void _assertAttached() { - assert( - _attachedController != null, - 'DraggableScrollableController is not attached to a sheet. A DraggableScrollableController ' - 'must be used in a DraggableScrollableSheet before any of its methods are called.', - ); - } - - void _attach(_DraggableScrollableSheetScrollController scrollController) { - assert(_attachedController == null, 'Draggable scrollable controller is already attached to a sheet.'); - _attachedController = scrollController; - _attachedController!.extent._currentSize.addListener(notifyListeners); - } - - void _onExtentReplaced(_DraggableSheetExtent previousExtent) { - // When the extent has been replaced, the old extent is already disposed and - // the controller will point to a new extent. We have to add our listener to - // the new extent. - _attachedController!.extent._currentSize.addListener(notifyListeners); - if (previousExtent.currentSize != _attachedController!.extent.currentSize) { - // The listener won't fire for a change in size between two extent - // objects so we have to fire it manually here. - notifyListeners(); - } - } - - void _detach() { - _attachedController?.extent._currentSize.removeListener(notifyListeners); - _attachedController = null; - } -} - /// A container for a [Scrollable] that responds to drag gestures by resizing /// the scrollable until a limit is reached, and then scrolling. /// @@ -272,7 +118,6 @@ class DraggableScrollableSheet extends StatefulWidget { this.expand = true, this.snap = false, this.snapSizes, - this.controller, required this.builder, }) : assert(initialChildSize != null), assert(minChildSize != null), @@ -349,9 +194,6 @@ class DraggableScrollableSheet extends StatefulWidget { /// being built or since the last call to [DraggableScrollableActuator.reset]. final List? snapSizes; - /// A controller that can be used to programmatically control this sheet. - final DraggableScrollableController? controller; - /// The builder that creates a child to display in this widget, which will /// use the provided [ScrollController] to enable dragging and scrolling /// of the contents. @@ -451,7 +293,7 @@ class _DraggableSheetExtent { required this.initialSize, required this.onSizeChanged, ValueNotifier? currentSize, - bool? hasDragged, + bool? hasChanged, }) : assert(minSize != null), assert(maxSize != null), assert(initialSize != null), @@ -462,9 +304,7 @@ class _DraggableSheetExtent { _currentSize = (currentSize ?? ValueNotifier(initialSize)) ..addListener(onSizeChanged), availablePixels = double.infinity, - hasDragged = hasDragged ?? false; - - VoidCallback? _cancelActivity; + hasChanged = hasChanged ?? false; final double minSize; final double maxSize; @@ -475,13 +315,19 @@ class _DraggableSheetExtent { final VoidCallback onSizeChanged; double availablePixels; - // Used to disable snapping until the user has dragged on the sheet. We do - // this because we don't want to snap away from an initial or programmatically set size. - bool hasDragged; + // Used to disable snapping until the user interacts with the sheet. We set + // this to false on initialization and after programmatic interaction with the + // sheet to prevent snapping away from the initial size and after animateTo/jumpTo. + bool hasChanged; bool get isAtMin => minSize >= _currentSize.value; bool get isAtMax => maxSize <= _currentSize.value; + set currentSize(double value) { + assert(value != null); + hasChanged = true; + _currentSize.value = value.clamp(minSize, maxSize); + } double get currentSize => _currentSize.value; double get currentPixels => sizeToPixels(_currentSize.value); @@ -489,43 +335,18 @@ class _DraggableSheetExtent { double get additionalMaxSize => isAtMax ? 0.0 : 1.0; List get pixelSnapSizes => snapSizes.map(sizeToPixels).toList(); - /// Start an activity that affects the sheet and register a cancel call back - /// that will be called if another activity starts. - /// - /// Note that `onCanceled` will get called even if the subsequent activity - /// started after this one finished so `onCanceled` should be safe to call at - /// any time. - void startActivity({required VoidCallback onCanceled}) { - _cancelActivity?.call(); - _cancelActivity = onCanceled; - } - /// The scroll position gets inputs in terms of pixels, but the size is /// expected to be expressed as a number between 0..1. - /// - /// This should only be called to respond to a user drag. To update the - /// size in response to a programmatic call, use [updateSize] directly. void addPixelDelta(double delta, BuildContext context) { - // Stop any playing sheet animations. - _cancelActivity?.call(); - _cancelActivity = null; - // The user has interacted with the sheet, set `hasDragged` to true so that - // we'll snap if applicable. - hasDragged = true; if (availablePixels == 0) { return; } updateSize(currentSize + pixelsToSize(delta), context); } - /// Set the size to the new value. [newSize] should be a number between - /// [minSize] and [maxSize]. - /// - /// This can be triggered by a programmatic (e.g. controller triggered) change - /// or a user drag. + /// Set the size to the new value. [newSize] should be a number between 0..1. void updateSize(double newSize, BuildContext context) { - assert(newSize != null); - _currentSize.value = newSize.clamp(minSize, maxSize); + currentSize = newSize; DraggableScrollableNotification( minExtent: minSize, maxExtent: maxSize, @@ -539,8 +360,8 @@ class _DraggableSheetExtent { return pixels / availablePixels * maxSize; } - double sizeToPixels(double size) { - return size / maxSize * availablePixels; + double sizeToPixels(double extent) { + return extent / maxSize * availablePixels; } void dispose() { @@ -562,11 +383,11 @@ class _DraggableSheetExtent { snapSizes: snapSizes, initialSize: initialSize, onSizeChanged: onSizeChanged, - // Use the possibly updated initialSize if the user hasn't dragged yet. - currentSize: ValueNotifier(hasDragged + // Use the possibly updated initialExtent if the user hasn't dragged yet. + currentSize: ValueNotifier(hasChanged ? _currentSize.value.clamp(minSize, maxSize) : initialSize), - hasDragged: hasDragged, + hasChanged: hasChanged, ); } } @@ -584,10 +405,9 @@ class _DraggableScrollableSheetState extends State { snap: widget.snap, snapSizes: _impliedSnapSizes(), initialSize: widget.initialChildSize, - onSizeChanged: _setExtent, + onSizeChanged: _setSize, ); _scrollController = _DraggableScrollableSheetScrollController(extent: _extent); - widget.controller?._attach(_scrollController); } List _impliedSnapSizes() { @@ -598,6 +418,8 @@ class _DraggableScrollableSheetState extends State { assert(index == 0 || snapSize > widget.snapSizes![index - 1], '${_snapSizeErrorMessage(index)}\nSnap sizes must be in ascending order. '); } + widget.snapSizes?.asMap().forEach((int index, double snapSize) { + }); // Ensure the snap sizes start and end with the min and max child sizes. if (widget.snapSizes == null || widget.snapSizes!.isEmpty) { return [ @@ -622,11 +444,22 @@ class _DraggableScrollableSheetState extends State { void didChangeDependencies() { super.didChangeDependencies(); if (_InheritedResetNotifier.shouldReset(context)) { - _scrollController.reset(); + // jumpTo can result in trying to replace semantics during build. + // Just animate really fast. + // Avoid doing it at all if the offset is already 0.0. + if (_scrollController.offset != 0.0) { + _scrollController.animateTo( + 0.0, + duration: const Duration(milliseconds: 1), + curve: Curves.linear, + ); + } + _extent.hasChanged = false; + _extent._currentSize.value = _extent.initialSize; } } - void _setExtent() { + void _setSize() { setState(() { // _extent has been updated when this is called. }); @@ -649,14 +482,12 @@ class _DraggableScrollableSheetState extends State { @override void dispose() { - widget.controller?._detach(); _scrollController.dispose(); _extent.dispose(); super.dispose(); } void _replaceExtent() { - final _DraggableSheetExtent previousExtent = _extent; _extent.dispose(); _extent = _extent.copyWith( minSize: widget.minChildSize, @@ -664,14 +495,11 @@ class _DraggableScrollableSheetState extends State { snap: widget.snap, snapSizes: _impliedSnapSizes(), initialSize: widget.initialChildSize, - onSizeChanged: _setExtent, + onSizeChanged: _setSize, ); // Modify the existing scroll controller instead of replacing it so that // developers listening to the controller do not have to rebuild their listeners. _scrollController.extent = _extent; - // If an external facing controller was provided, let it know that the - // extent has been replaced. - widget.controller?._onExtentReplaced(previousExtent); if (widget.snap) { // Trigger a snap in case snap or snapSizes has changed. We put this in a // post frame callback so that `build` can update `_extent.availablePixels` @@ -685,7 +513,7 @@ class _DraggableScrollableSheetState extends State { String _snapSizeErrorMessage(int invalidIndex) { final List snapSizesWithIndicator = widget.snapSizes!.asMap().keys.map( - (int index) { + (int index) { final String snapSizeString = widget.snapSizes![index].toString(); if (index == invalidIndex) { return '>>> $snapSizeString <<<'; @@ -748,22 +576,6 @@ class _DraggableScrollableSheetScrollController extends ScrollController { @override _DraggableScrollableSheetScrollPosition get position => super.position as _DraggableScrollableSheetScrollPosition; - - void reset() { - extent._cancelActivity?.call(); - extent.hasDragged = false; - // jumpTo can result in trying to replace semantics during build. - // Just animate really fast. - // Avoid doing it at all if the offset is already 0.0. - if (offset != 0.0) { - animateTo( - 0.0, - duration: const Duration(milliseconds: 1), - curve: Curves.linear, - ); - } - extent.updateSize(extent.initialSize, position.context.notificationContext!); - } } /// A scroll position that manages scroll activities for @@ -841,7 +653,7 @@ class _DraggableScrollableSheetScrollPosition }, ); } - bool get _shouldSnap => extent.snap && extent.hasDragged && !_isAtSnapSize; + bool get _shouldSnap => extent.snap && extent.hasChanged && !_isAtSnapSize; @override void dispose() { @@ -930,13 +742,6 @@ class _DraggableScrollableSheetScrollPosition /// the user has tapped back if the sheet has started to cover more of the body /// than when at its initial position. This is important for users of assistive /// technology, where dragging may be difficult to communicate. -/// -/// This is just a wrapper on top of [DraggableScrollableController]. It is -/// primarily useful for controlling a sheet in a part of the widget tree that -/// the current code does not control (e.g. library code trying to affect a sheet -/// in library users' code). Generally, it's easier to control the sheet -/// directly by creating a controller and passing the controller to the sheet in -/// its constructor (see [DraggableScrollableSheet.controller]). class DraggableScrollableActuator extends StatelessWidget { /// Creates a widget that can notify descendent [DraggableScrollableSheet]s /// to reset to their initial position. diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 5bd340711d7ba..1231bcfb9fa8c 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -7,14 +7,12 @@ import 'dart:math' as math; import 'dart:typed_data'; import 'dart:ui' as ui hide TextStyle; -import 'package:characters/characters.dart' show CharacterRange; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; -import 'actions.dart'; import 'autofill.dart'; import 'automatic_keep_alive.dart'; import 'basic.dart'; @@ -23,7 +21,6 @@ import 'constants.dart'; import 'debug.dart'; import 'focus_manager.dart'; import 'focus_scope.dart'; -import 'focus_traversal.dart'; import 'framework.dart'; import 'localizations.dart'; import 'media_query.dart'; @@ -32,7 +29,7 @@ import 'scroll_controller.dart'; import 'scroll_physics.dart'; import 'scrollable.dart'; import 'text.dart'; -import 'text_editing_intents.dart'; +import 'text_editing_action_target.dart'; import 'text_selection.dart'; import 'ticker_provider.dart'; import 'widget_span.dart'; @@ -345,69 +342,10 @@ class ToolbarOptions { /// [onSubmitted] can be used to manually move focus to another input widget /// when a user finishes with the currently focused input widget. /// -/// When the widget has focus, it will prevent itself from disposing via -/// [AutomaticKeepAliveClientMixin.wantKeepAlive] in order to avoid losing the -/// selection. Removing the focus will allow it to be disposed. -/// /// Rather than using this widget directly, consider using [TextField], which /// is a full-featured, material-design text input field with placeholder text, /// labels, and [Form] integration. /// -/// ## Text Editing [Intent]s and Their Default [Action]s -/// -/// This widget provides default [Action]s for handling common text editing -/// [Intent]s such as deleting, copying and pasting in the text field. These -/// [Action]s can be directly invoked using [Actions.invoke] or the -/// [Actions.maybeInvoke] method. The default text editing keyboard [Shortcuts] -/// also use these [Intent]s and [Action]s to perform the text editing -/// operations they are bound to. -/// -/// The default handling of a specific [Intent] can be overridden by placing an -/// [Actions] widget above this widget. See the [Action] class and the -/// [Action.overridable] constructor for more information on how a pre-defined -/// overridable [Action] can be overridden. -/// -/// ### Intents for Deleting Text and Their Default Behavior -/// -/// | **Intent Class** | **Default Behavior when there's selected text** | **Default Behavior when there is a [caret](https://en.wikipedia.org/wiki/Caret_navigation) (The selection is [TextSelection.collapsed])** | -/// | :------------------------------- | :--------------------------------------------------- | :----------------------------------------------------------------------- | -/// | [DeleteCharacterIntent] | Deletes the selected text | Deletes the user-perceived character before or after the caret location. | -/// | [DeleteToNextWordBoundaryIntent] | Deletes the selected text and the word before/after the selection's [TextSelection.extent] position | Deletes from the caret location to the previous or the next word boundary | -/// | [DeleteToLineBreakIntent] | Deletes the selected text, and deletes to the start/end of the line from the selection's [TextSelection.extent] position | Deletes from the caret location to the logical start or end of the current line | -/// -/// ### Intents for Moving the [Caret](https://en.wikipedia.org/wiki/Caret_navigation) -/// -/// | **Intent Class** | **Default Behavior when there's selected text** | **Default Behavior when there is a caret ([TextSelection.collapsed])** | -/// | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------- | :---------------------------------------------------------------------- | -/// | [ExtendSelectionByCharacterIntent](`collapseSelection: true`) | Collapses the selection to the logical start/end of the selection | Moves the caret past the user-perceived character before or after the current caret location. | -/// | [ExtendSelectionToNextWordBoundaryIntent](`collapseSelection: true`) | Collapses the selection to the word boundary before/after the selection's [TextSelection.extent] position | Moves the caret to the previous/next word boundary. | -/// | [ExtendSelectionToNextWordBoundaryOrCaretLocationIntent](`collapseSelection: true`) | Collapses the selection to the word boundary before/after the selection's [TextSelection.extent] position, or [TextSelection.base], whichever is closest in the given direction | Moves the caret to the previous/next word boundary. | -/// | [ExtendSelectionToLineBreakIntent](`collapseSelection: true`) | Collapses the selection to the start/end of the line at the selection's [TextSelection.extent] position | Moves the caret to the start/end of the current line .| -/// | [ExtendSelectionVerticallyToAdjacentLineIntent](`collapseSelection: true`) | Collapses the selection to the position closest to the selection's [TextSelection.extent], on the previous/next adjacent line | Moves the caret to the closest position on the previous/next adjacent line. | -/// | [ExtendSelectionToDocumentBoundaryIntent](`collapseSelection: true`) | Collapses the selection to the start/end of the document | Moves the caret to the start/end of the document. | -/// -/// #### Intents for Extending the Selection -/// -/// | **Intent Class** | **Default Behavior when there's selected text** | **Default Behavior when there is a caret ([TextSelection.collapsed])** | -/// | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------- | :---------------------------------------------------------------------- | -/// | [ExtendSelectionByCharacterIntent](`collapseSelection: false`) | Moves the selection's [TextSelection.extent] past the user-perceived character before/after it | -/// | [ExtendSelectionToNextWordBoundaryIntent](`collapseSelection: false`) | Moves the selection's [TextSelection.extent] to the previous/next word boundary | -/// | [ExtendSelectionToNextWordBoundaryOrCaretLocationIntent](`collapseSelection: false`) | Moves the selection's [TextSelection.extent] to the previous/next word boundary, or [TextSelection.base] whichever is closest in the given direction | Moves the selection's [TextSelection.extent] to the previous/next word boundary. | -/// | [ExtendSelectionToLineBreakIntent](`collapseSelection: false`) | Moves the selection's [TextSelection.extent] to the start/end of the line | -/// | [ExtendSelectionVerticallyToAdjacentLineIntent](`collapseSelection: false`) | Moves the selection's [TextSelection.extent] to the closest position on the previous/next adjacent line | -/// | [ExtendSelectionToDocumentBoundaryIntent](`collapseSelection: false`) | Moves the selection's [TextSelection.extent] to the start/end of the document | -/// | [SelectAllTextIntent] | Selects the entire document | -/// -/// ### Other Intents -/// -/// | **Intent Class** | **Default Behavior** | -/// | :-------------------------------------- | :--------------------------------------------------- | -/// | [DoNothingAndStopPropagationTextIntent] | Does nothing in the input field, and prevents the key event from further propagating in the widget tree. | -/// | [ReplaceTextIntent] | Replaces the current [TextEditingValue] in the input field's [TextEditingController], and triggers all related user callbacks and [TextInputFormatter]s. | -/// | [UpdateSelectionIntent] | Updates the current selection in the input field's [TextEditingController], and triggers the [onSelectionChanged] callback. | -/// | [CopySelectionTextIntent] | Copies or cuts the selected text into the clipboard | -/// | [PasteTextIntent] | Inserts the current text in the clipboard after the caret location, or replaces the selected text if the selection is not collapsed. | -/// /// ## Gesture Events Handling /// /// This widget provides rudimentary, platform-agnostic gesture handling for @@ -510,11 +448,16 @@ class EditableText extends StatefulWidget { this.scrollPadding = const EdgeInsets.all(20.0), this.keyboardAppearance = Brightness.light, this.dragStartBehavior = DragStartBehavior.start, - bool? enableInteractiveSelection, + this.enableInteractiveSelection = true, this.scrollController, this.scrollPhysics, this.autocorrectionTextRectColor, - ToolbarOptions? toolbarOptions, + this.toolbarOptions = const ToolbarOptions( + copy: true, + cut: true, + paste: true, + selectAll: true, + ), this.autofillHints = const [], this.autofillClient, this.contentCommitMimeTypes = const [], @@ -531,6 +474,7 @@ class EditableText extends StatefulWidget { smartQuotesType = smartQuotesType ?? (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), assert(enableSuggestions != null), assert(showSelectionHandles != null), + assert(enableInteractiveSelection != null), assert(readOnly != null), assert(forceLine != null), assert(style != null), @@ -557,31 +501,7 @@ class EditableText extends StatefulWidget { assert(rendererIgnoresPointer != null), assert(scrollPadding != null), assert(dragStartBehavior != null), - enableInteractiveSelection = enableInteractiveSelection ?? (!readOnly || !obscureText), - toolbarOptions = toolbarOptions ?? - (obscureText - ? (readOnly - // No point in even offering "Select All" in a read-only obscured - // field. - ? const ToolbarOptions() - // Writable, but obscured. - : const ToolbarOptions( - selectAll: true, - paste: true, - )) - : (readOnly - // Read-only, not obscured. - ? const ToolbarOptions( - selectAll: true, - copy: true, - ) - // Writable, not obscured. - : const ToolbarOptions( - copy: true, - cut: true, - selectAll: true, - paste: true, - ))), + assert(toolbarOptions != null), assert(clipBehavior != null), assert(enableIMEPersonalizedLearning != null), assert(contentCommitMimeTypes != null), @@ -615,15 +535,13 @@ class EditableText extends StatefulWidget { /// Whether to hide the text being edited (e.g., for passwords). /// /// When this is set to true, all the characters in the text field are - /// replaced by [obscuringCharacter], and the text in the field cannot be - /// copied with copy or cut. If [readOnly] is also true, then the text cannot - /// be selected. + /// replaced by [obscuringCharacter]. /// /// Defaults to false. Cannot be null. /// {@endtemplate} final bool obscureText; - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} final TextHeightBehavior? textHeightBehavior; /// {@macro flutter.painting.textPainter.textWidthBasis} @@ -653,10 +571,8 @@ class EditableText extends StatefulWidget { /// Configuration of toolbar options. /// - /// By default, all options are enabled. If [readOnly] is true, paste and cut - /// will be disabled regardless. If [obscureText] is true, cut and copy will - /// be disabled regardless. If [readOnly] and [obscureText] are both true, - /// select all will also be disabled. + /// By default, all options are enabled. If [readOnly] is true, + /// paste and cut will be disabled regardless. final ToolbarOptions toolbarOptions; /// Whether to show selection handles. @@ -1608,7 +1524,6 @@ class EditableText extends StatefulWidget { properties.add(DiagnosticsProperty('controller', controller)); properties.add(DiagnosticsProperty('focusNode', focusNode)); properties.add(DiagnosticsProperty('obscureText', obscureText, defaultValue: false)); - properties.add(DiagnosticsProperty('readOnly', readOnly, defaultValue: false)); properties.add(DiagnosticsProperty('autocorrect', autocorrect, defaultValue: true)); properties.add(EnumProperty('smartDashesType', smartDashesType, defaultValue: obscureText ? SmartDashesType.disabled : SmartDashesType.enabled)); properties.add(EnumProperty('smartQuotesType', smartQuotesType, defaultValue: obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled)); @@ -1628,12 +1543,12 @@ class EditableText extends StatefulWidget { properties.add(DiagnosticsProperty>('autofillHints', autofillHints, defaultValue: null)); properties.add(DiagnosticsProperty('textHeightBehavior', textHeightBehavior, defaultValue: null)); properties.add(DiagnosticsProperty('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true)); - properties.add(DiagnosticsProperty('enableInteractiveSelection', enableInteractiveSelection, defaultValue: true)); + properties.add(DiagnosticsProperty>('contentCommitMimeTypes', contentCommitMimeTypes, defaultValue: null)); } } /// State for a [EditableText]. -class EditableTextState extends State with AutomaticKeepAliveClientMixin, WidgetsBindingObserver, TickerProviderStateMixin, TextSelectionDelegate implements TextInputClient, AutofillClient { +class EditableTextState extends State with AutomaticKeepAliveClientMixin, WidgetsBindingObserver, TickerProviderStateMixin, TextSelectionDelegate, TextEditingActionTarget implements TextInputClient, AutofillClient { Timer? _cursorTimer; bool _targetCursorVisibility = false; final ValueNotifier _cursorVisibilityNotifier = ValueNotifier(true); @@ -1646,13 +1561,17 @@ class EditableTextState extends State with AutomaticKeepAliveClien ScrollController? _internalScrollController; ScrollController get _scrollController => widget.scrollController ?? (_internalScrollController ??= ScrollController()); - AnimationController? _cursorBlinkOpacityController; + late final AnimationController _cursorBlinkOpacityController = AnimationController( + vsync: this, + duration: _fadeDuration, + )..addListener(_onCursorColorTick); final LayerLink _toolbarLayerLink = LayerLink(); final LayerLink _startHandleLayerLink = LayerLink(); final LayerLink _endHandleLayerLink = LayerLink(); bool _didAutoFocus = false; + FocusAttachment? _focusAttachment; AutofillGroupState? _currentAutofillScope; @override @@ -1683,24 +1602,26 @@ class EditableTextState extends State with AutomaticKeepAliveClien // cursor position after the user has finished placing it. static const Duration _floatingCursorResetTime = Duration(milliseconds: 125); - AnimationController? _floatingCursorResetController; + late final AnimationController _floatingCursorResetController = AnimationController( + vsync: this, + )..addListener(_onFloatingCursorResetTick); @override bool get wantKeepAlive => widget.focusNode.hasFocus; - Color get _cursorColor => widget.cursorColor.withOpacity(_cursorBlinkOpacityController!.value); + Color get _cursorColor => widget.cursorColor.withOpacity(_cursorBlinkOpacityController.value); @override - bool get cutEnabled => widget.toolbarOptions.cut && !widget.readOnly && !widget.obscureText; + bool get cutEnabled => widget.toolbarOptions.cut && !widget.readOnly; @override - bool get copyEnabled => widget.toolbarOptions.copy && !widget.obscureText; + bool get copyEnabled => widget.toolbarOptions.copy; @override bool get pasteEnabled => widget.toolbarOptions.paste && !widget.readOnly; @override - bool get selectAllEnabled => widget.toolbarOptions.selectAll && (!widget.readOnly || !widget.obscureText) && widget.enableInteractiveSelection; + bool get selectAllEnabled => widget.toolbarOptions.selectAll; void _onChangedClipboardStatus() { setState(() { @@ -1708,24 +1629,62 @@ class EditableTextState extends State with AutomaticKeepAliveClien }); } - TextEditingValue get _textEditingValueforTextLayoutMetrics { - final Widget? editableWidget =_editableKey.currentContext?.widget; - if (editableWidget is! _Editable) { - throw StateError('_Editable must be mounted.'); + // Start TextEditingActionTarget. + + @override + TextLayoutMetrics get textLayoutMetrics => renderEditable; + + @override + bool get readOnly => widget.readOnly; + + @override + bool get obscureText => widget.obscureText; + + @override + bool get selectionEnabled => widget.selectionEnabled; + + @override + void debugAssertLayoutUpToDate() => renderEditable.debugAssertLayoutUpToDate(); + + /// {@macro flutter.widgets.TextEditingActionTarget.setSelection} + @override + void setSelection(TextSelection nextSelection, SelectionChangedCause cause) { + if (nextSelection == textEditingValue.selection) { + return; } - return editableWidget.value; + if (nextSelection.isValid) { + // The nextSelection is calculated based on _plainText, which can be out + // of sync with the textSelectionDelegate.textEditingValue by one frame. + // This is due to the render editable and editable text handle pointer + // event separately. If the editable text changes the text during the + // event handler, the render editable will use the outdated text stored in + // the _plainText when handling the pointer event. + // + // If this happens, we need to make sure the new selection is still valid. + final int textLength = textEditingValue.text.length; + nextSelection = nextSelection.copyWith( + baseOffset: math.min(nextSelection.baseOffset, textLength), + extentOffset: math.min(nextSelection.extentOffset, textLength), + ); + } + _handleSelectionChange(nextSelection, cause); + return super.setSelection(nextSelection, cause); } - /// Copy current selection to [Clipboard]. + /// {@macro flutter.widgets.TextEditingActionTarget.setTextEditingValue} @override - void copySelection(SelectionChangedCause cause) { - final TextSelection selection = textEditingValue.selection; - assert(selection != null); - if (selection.isCollapsed || widget.obscureText) { + void setTextEditingValue(TextEditingValue newValue, SelectionChangedCause cause) { + if (newValue == textEditingValue) { return; } - final String text = textEditingValue.text; - Clipboard.setData(ClipboardData(text: selection.textInside(text))); + textEditingValue = newValue; + userUpdateTextEditingValue(newValue, cause); + } + + /// {@macro flutter.widgets.TextEditingActionTarget.copySelection} + @override + void copySelection(SelectionChangedCause cause) { + super.copySelection(cause); if (cause == SelectionChangedCause.toolbar) { bringIntoView(textEditingValue.selection.extent); hideToolbar(false); @@ -1751,45 +1710,20 @@ class EditableTextState extends State with AutomaticKeepAliveClien } } - /// Cut current selection to [Clipboard]. + /// {@macro flutter.widgets.TextEditingActionTarget.cutSelection} @override void cutSelection(SelectionChangedCause cause) { - if (widget.readOnly || widget.obscureText) { - return; - } - final TextSelection selection = textEditingValue.selection; - final String text = textEditingValue.text; - assert(selection != null); - if (selection.isCollapsed) { - return; - } - Clipboard.setData(ClipboardData(text: selection.textInside(text))); - _replaceText(ReplaceTextIntent(textEditingValue, '', selection, cause)); + super.cutSelection(cause); if (cause == SelectionChangedCause.toolbar) { bringIntoView(textEditingValue.selection.extent); hideToolbar(); } } - /// Paste text from [Clipboard]. + /// {@macro flutter.widgets.TextEditingActionTarget.pasteText} @override Future pasteText(SelectionChangedCause cause) async { - if (widget.readOnly) { - return; - } - final TextSelection selection = textEditingValue.selection; - assert(selection != null); - if (!selection.isValid) { - return; - } - // Snapshot the input before using `await`. - // See https://github.com/flutter/flutter/issues/11427 - final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); - if (data == null) { - return; - } - - _replaceText(ReplaceTextIntent(textEditingValue, data.text!, selection, cause)); + super.pasteText(cause); if (cause == SelectionChangedCause.toolbar) { bringIntoView(textEditingValue.selection.extent); hideToolbar(); @@ -1799,33 +1733,37 @@ class EditableTextState extends State with AutomaticKeepAliveClien /// Select the entire text value. @override void selectAll(SelectionChangedCause cause) { - if (widget.readOnly && widget.obscureText) { - // If we can't modify it, and we can't copy it, there's no point in - // selecting it. - return; - } - userUpdateTextEditingValue( - textEditingValue.copyWith( - selection: TextSelection(baseOffset: 0, extentOffset: textEditingValue.text.length), - ), - cause, - ); + super.selectAll(cause); if (cause == SelectionChangedCause.toolbar) { bringIntoView(textEditingValue.selection.extent); } } + // End TextEditingActionTarget. + + void _handleSelectionChange( + TextSelection nextSelection, + SelectionChangedCause cause, + ) { + // Changes made by the keyboard can sometimes be "out of band" for listening + // components, so always send those events, even if we didn't think it + // changed. Also, focusing an empty field is sent as a selection change even + // if the selection offset didn't change. + final bool focusingEmpty = nextSelection.baseOffset == 0 && nextSelection.extentOffset == 0 && !_hasFocus; + if (nextSelection == textEditingValue.selection && cause != SelectionChangedCause.keyboard && !focusingEmpty) { + return; + } + widget.onSelectionChanged?.call(nextSelection, cause); + } + // State lifecycle: @override void initState() { super.initState(); - _cursorBlinkOpacityController = AnimationController( - vsync: this, - duration: _fadeDuration, - )..addListener(_onCursorColorTick); _clipboardStatus?.addListener(_onChangedClipboardStatus); widget.controller.addListener(_didChangeTextEditingValue); + _focusAttachment = widget.focusNode.attach(context); widget.focusNode.addListener(_handleFocusChanged); _scrollController.addListener(_updateSelectionOverlayForScroll); _cursorVisibilityNotifier.value = widget.showCursor; @@ -1889,6 +1827,8 @@ class EditableTextState extends State with AutomaticKeepAliveClien if (widget.focusNode != oldWidget.focusNode) { oldWidget.focusNode.removeListener(_handleFocusChanged); + _focusAttachment?.detach(); + _focusAttachment = widget.focusNode.attach(context); widget.focusNode.addListener(_handleFocusChanged); updateKeepAlive(); } @@ -1934,16 +1874,15 @@ class EditableTextState extends State with AutomaticKeepAliveClien _internalScrollController?.dispose(); _currentAutofillScope?.unregister(autofillId); widget.controller.removeListener(_didChangeTextEditingValue); - _floatingCursorResetController?.dispose(); - _floatingCursorResetController = null; + _floatingCursorResetController.dispose(); _closeInputConnectionIfNeeded(); assert(!_hasInputConnection); _cursorTimer?.cancel(); _cursorTimer = null; - _cursorBlinkOpacityController?.dispose(); - _cursorBlinkOpacityController = null; + _cursorBlinkOpacityController.dispose(); _selectionOverlay?.dispose(); _selectionOverlay = null; + _focusAttachment!.detach(); widget.focusNode.removeListener(_handleFocusChanged); WidgetsBinding.instance!.removeObserver(this); _clipboardStatus?.removeListener(_onChangedClipboardStatus); @@ -2085,13 +2024,10 @@ class EditableTextState extends State with AutomaticKeepAliveClien @override void updateFloatingCursor(RawFloatingCursorPoint point) { - _floatingCursorResetController ??= AnimationController( - vsync: this, - )..addListener(_onFloatingCursorResetTick); switch(point.state) { case FloatingCursorDragState.Start: - if (_floatingCursorResetController!.isAnimating) { - _floatingCursorResetController!.stop(); + if (_floatingCursorResetController.isAnimating) { + _floatingCursorResetController.stop(); _onFloatingCursorResetTick(); } // We want to send in points that are centered around a (0,0) origin, so @@ -2116,8 +2052,8 @@ class EditableTextState extends State with AutomaticKeepAliveClien case FloatingCursorDragState.End: // We skip animation if no update has happened. if (_lastTextPosition != null && _lastBoundedOffset != null) { - _floatingCursorResetController!.value = 0.0; - _floatingCursorResetController!.animateTo(1.0, duration: _floatingCursorResetTime, curve: Curves.decelerate); + _floatingCursorResetController.value = 0.0; + _floatingCursorResetController.animateTo(1.0, duration: _floatingCursorResetTime, curve: Curves.decelerate); } break; } @@ -2125,7 +2061,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien void _onFloatingCursorResetTick() { final Offset finalPosition = renderEditable.getLocalRectForCaret(_lastTextPosition!).centerLeft - _floatingCursorOffset; - if (_floatingCursorResetController!.isCompleted) { + if (_floatingCursorResetController.isCompleted) { renderEditable.setFloatingCursor(FloatingCursorDragState.End, finalPosition, _lastTextPosition!); if (_lastTextPosition!.offset != renderEditable.selection!.baseOffset) // The cause is technically the force cursor, but the cause is listed as tap as the desired functionality is the same. @@ -2135,7 +2071,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien _pointOffsetOrigin = null; _lastBoundedOffset = null; } else { - final double lerpValue = _floatingCursorResetController!.value; + final double lerpValue = _floatingCursorResetController.value; final double lerpX = ui.lerpDouble(_lastBoundedOffset!.dx, finalPosition.dx, lerpValue)!; final double lerpY = ui.lerpDouble(_lastBoundedOffset!.dy, finalPosition.dy, lerpValue)!; @@ -2319,7 +2255,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien bool get _hasInputConnection => _textInputConnection?.attached ?? false; /// Whether to send the autofill information to the autofill service. True by /// default. - bool get _needsAutofill => _effectiveAutofillClient.textInputConfiguration.autofillConfiguration.enabled; + bool get _needsAutofill => widget.autofillHints?.isNotEmpty ?? true; void _openInputConnection() { if (!_shouldCreateInputConnection) { @@ -2339,9 +2275,16 @@ class EditableTextState extends State with AutomaticKeepAliveClien _textInputConnection = _needsAutofill && currentAutofillScope != null ? currentAutofillScope!.attach(this, _effectiveAutofillClient.textInputConfiguration) : TextInput.attach(this, _effectiveAutofillClient.textInputConfiguration); + _textInputConnection!.show(); _updateSizeAndTransform(); _updateComposingRectIfNeeded(); _updateCaretRectIfNeeded(); + if (_needsAutofill) { + // Request autofill AFTER the size and the transform have been sent to + // the platform text input plugin. + _textInputConnection!.requestAutofill(); + } + final TextStyle style = widget.style; _textInputConnection! ..setStyle( @@ -2351,14 +2294,8 @@ class EditableTextState extends State with AutomaticKeepAliveClien textDirection: _textDirection, textAlign: widget.textAlign, ) - ..setEditingState(localValue) - ..show(); - if (_needsAutofill) { - // Request autofill AFTER the size and the transform have been sent to - // the platform text input plugin. - _textInputConnection!.requestAutofill(); - } - _lastKnownRemoteTextEditingValue = localValue; + ..setEditingState(localValue); + _lastKnownRemoteTextEditingValue = localValue; } else { _textInputConnection!.show(); } @@ -2663,14 +2600,14 @@ class EditableTextState extends State with AutomaticKeepAliveClien } void _onCursorColorTick() { - renderEditable.cursorColor = widget.cursorColor.withOpacity(_cursorBlinkOpacityController!.value); - _cursorVisibilityNotifier.value = widget.showCursor && _cursorBlinkOpacityController!.value > 0; + renderEditable.cursorColor = widget.cursorColor.withOpacity(_cursorBlinkOpacityController.value); + _cursorVisibilityNotifier.value = widget.showCursor && _cursorBlinkOpacityController.value > 0; } /// Whether the blinking cursor is actually visible at this precise moment /// (it's hidden half the time, since it blinks). @visibleForTesting - bool get cursorCurrentlyVisible => _cursorBlinkOpacityController!.value > 0; + bool get cursorCurrentlyVisible => _cursorBlinkOpacityController.value > 0; /// The cursor blink interval (the amount of time the cursor is in the "on" /// state or the "off" state). A complete cursor blink period is twice this @@ -2696,9 +2633,9 @@ class EditableTextState extends State with AutomaticKeepAliveClien // // These values and curves have been obtained through eyeballing, so are // likely not exactly the same as the values for native iOS. - _cursorBlinkOpacityController!.animateTo(targetOpacity, curve: Curves.easeOut); + _cursorBlinkOpacityController.animateTo(targetOpacity, curve: Curves.easeOut); } else { - _cursorBlinkOpacityController!.value = targetOpacity; + _cursorBlinkOpacityController.value = targetOpacity; } if (_obscureShowCharTicksPending > 0) { @@ -2726,7 +2663,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien return; } _targetCursorVisibility = true; - _cursorBlinkOpacityController!.value = 1.0; + _cursorBlinkOpacityController.value = 1.0; if (EditableText.debugDeterministicCursor) return; if (widget.cursorOpacityAnimates) { @@ -2741,14 +2678,14 @@ class EditableTextState extends State with AutomaticKeepAliveClien _cursorTimer?.cancel(); _cursorTimer = null; _targetCursorVisibility = false; - _cursorBlinkOpacityController!.value = 0.0; + _cursorBlinkOpacityController.value = 0.0; if (EditableText.debugDeterministicCursor) return; if (resetCharTicks) _obscureShowCharTicksPending = 0; if (widget.cursorOpacityAnimates) { - _cursorBlinkOpacityController!.stop(); - _cursorBlinkOpacityController!.value = 0.0; + _cursorBlinkOpacityController.stop(); + _cursorBlinkOpacityController.value = 0.0; } } @@ -2766,7 +2703,6 @@ class EditableTextState extends State with AutomaticKeepAliveClien // TODO(abarth): Teach RenderEditable about ValueNotifier // to avoid this setState(). setState(() { /* We use widget.controller.value in build(). */ }); - _adjacentLineAction.stopCurrentVerticalRunIfSelectionChanges(); } void _handleFocusChanged() { @@ -2983,221 +2919,87 @@ class EditableTextState extends State with AutomaticKeepAliveClien : null; } - - // --------------------------- Text Editing Actions --------------------------- - - _TextBoundary _characterBoundary(DirectionalTextEditingIntent intent) { - final _TextBoundary atomicTextBoundary = widget.obscureText ? _CodeUnitBoundary(_value) : _CharacterBoundary(_value); - return _CollapsedSelectionBoundary(atomicTextBoundary, intent.forward); - } - - _TextBoundary _nextWordBoundary(DirectionalTextEditingIntent intent) { - final _TextBoundary atomicTextBoundary; - final _TextBoundary boundary; - - if (widget.obscureText) { - atomicTextBoundary = _CodeUnitBoundary(_value); - boundary = _DocumentBoundary(_value); - } else { - final TextEditingValue textEditingValue = _textEditingValueforTextLayoutMetrics; - atomicTextBoundary = _CharacterBoundary(textEditingValue); - // This isn't enough. Newline characters. - boundary = _ExpandedTextBoundary(_WhitespaceBoundary(textEditingValue), _WordBoundary(renderEditable, textEditingValue)); - } - - final _MixedBoundary mixedBoundary = intent.forward - ? _MixedBoundary(atomicTextBoundary, boundary) - : _MixedBoundary(boundary, atomicTextBoundary); - // Use a _MixedBoundary to make sure we don't leave invalid codepoints in - // the field after deletion. - return _CollapsedSelectionBoundary(mixedBoundary, intent.forward); - } - - _TextBoundary _linebreak(DirectionalTextEditingIntent intent) { - final _TextBoundary atomicTextBoundary; - final _TextBoundary boundary; - - if (widget.obscureText) { - atomicTextBoundary = _CodeUnitBoundary(_value); - boundary = _DocumentBoundary(_value); - } else { - final TextEditingValue textEditingValue = _textEditingValueforTextLayoutMetrics; - atomicTextBoundary = _CharacterBoundary(textEditingValue); - boundary = _LineBreak(renderEditable, textEditingValue); - } - - // The _MixedBoundary is to make sure we don't leave invalid code units in - // the field after deletion. - // `boundary` doesn't need to be wrapped in a _CollapsedSelectionBoundary, - // since the document boundary is unique and the linebreak boundary is - // already caret-location based. - return intent.forward - ? _MixedBoundary(_CollapsedSelectionBoundary(atomicTextBoundary, true), boundary) - : _MixedBoundary(boundary, _CollapsedSelectionBoundary(atomicTextBoundary, false)); - } - - _TextBoundary _documentBoundary(DirectionalTextEditingIntent intent) => _DocumentBoundary(_value); - - Action _makeOverridable(Action defaultAction) { - return Action.overridable(context: context, defaultAction: defaultAction); - } - - void _replaceText(ReplaceTextIntent intent) { - userUpdateTextEditingValue( - intent.currentTextEditingValue.replaced(intent.replacementRange, intent.replacementText), - intent.cause, - ); - } - late final Action _replaceTextAction = CallbackAction(onInvoke: _replaceText); - - void _updateSelection(UpdateSelectionIntent intent) { - userUpdateTextEditingValue( - intent.currentTextEditingValue.copyWith(selection: intent.newSelection), - intent.cause, - ); - } - late final Action _updateSelectionAction = CallbackAction(onInvoke: _updateSelection); - - late final _UpdateTextSelectionToAdjacentLineAction _adjacentLineAction = _UpdateTextSelectionToAdjacentLineAction(this); - - void _expandSelection(ExpandSelectionToLineBreakIntent intent) { - final _TextBoundary textBoundary = _linebreak(intent); - final TextSelection textBoundarySelection = textBoundary.textEditingValue.selection; - if (!textBoundarySelection.isValid) { - return; - } - - final bool inOrder = textBoundarySelection.baseOffset <= textBoundarySelection.extentOffset; - final bool towardsExtent = intent.forward == inOrder; - final TextPosition position = towardsExtent - ? textBoundarySelection.extent - : textBoundarySelection.base; - - final TextPosition newExtent = intent.forward - ? textBoundary.getTrailingTextBoundaryAt(position) - : textBoundary.getLeadingTextBoundaryAt(position); - - final TextSelection newSelection = textBoundarySelection.expandTo(newExtent, textBoundarySelection.isCollapsed); - userUpdateTextEditingValue( - _value.copyWith(selection: newSelection), - SelectionChangedCause.keyboard, - ); - } - - late final Map> _actions = >{ - DoNothingAndStopPropagationTextIntent: DoNothingAction(consumesKey: false), - ReplaceTextIntent: _replaceTextAction, - UpdateSelectionIntent: _updateSelectionAction, - DirectionalFocusIntent: DirectionalFocusAction.forTextField(), - - // Delete - DeleteCharacterIntent: _makeOverridable(_DeleteTextAction(this, _characterBoundary)), - DeleteToNextWordBoundaryIntent: _makeOverridable(_DeleteTextAction(this, _nextWordBoundary)), - DeleteToLineBreakIntent: _makeOverridable(_DeleteTextAction(this, _linebreak)), - - // Extend/Move Selection - ExtendSelectionByCharacterIntent: _makeOverridable(_UpdateTextSelectionAction(this, false, _characterBoundary,)), - ExtendSelectionToNextWordBoundaryIntent: _makeOverridable(_UpdateTextSelectionAction(this, true, _nextWordBoundary)), - ExtendSelectionToLineBreakIntent: _makeOverridable(_UpdateTextSelectionAction(this, true, _linebreak)), - ExpandSelectionToLineBreakIntent: _makeOverridable(CallbackAction(onInvoke: _expandSelection)), - ExtendSelectionVerticallyToAdjacentLineIntent: _makeOverridable(_adjacentLineAction), - ExtendSelectionToDocumentBoundaryIntent: _makeOverridable(_UpdateTextSelectionAction(this, true, _documentBoundary)), - ExtendSelectionToNextWordBoundaryOrCaretLocationIntent: _makeOverridable(_ExtendSelectionOrCaretPositionAction(this, _nextWordBoundary)), - - // Copy Paste - SelectAllTextIntent: _makeOverridable(_SelectAllAction(this)), - CopySelectionTextIntent: _makeOverridable(_CopySelectionAction(this)), - PasteTextIntent: _makeOverridable(CallbackAction(onInvoke: (PasteTextIntent intent) => pasteText(intent.cause))), - }; - @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); + _focusAttachment!.reparent(); super.build(context); // See AutomaticKeepAliveClientMixin. final TextSelectionControls? controls = widget.selectionControls; return MouseRegion( cursor: widget.mouseCursor ?? SystemMouseCursors.text, - child: Actions( - actions: _actions, - child: Focus( - focusNode: widget.focusNode, - includeSemantics: false, - debugLabel: 'EditableText', - child: Scrollable( - excludeFromSemantics: true, - axisDirection: _isMultiline ? AxisDirection.down : AxisDirection.right, - controller: _scrollController, - physics: widget.scrollPhysics, - dragStartBehavior: widget.dragStartBehavior, - restorationId: widget.restorationId, - // If a ScrollBehavior is not provided, only apply scrollbars when - // multiline. The overscroll indicator should not be applied in - // either case, glowing or stretching. - scrollBehavior: widget.scrollBehavior ?? ScrollConfiguration.of(context).copyWith( - scrollbars: _isMultiline, - overscroll: false, - ), - viewportBuilder: (BuildContext context, ViewportOffset offset) { - return CompositedTransformTarget( - link: _toolbarLayerLink, - child: Semantics( - onCopy: _semanticsOnCopy(controls), - onCut: _semanticsOnCut(controls), - onPaste: _semanticsOnPaste(controls), - child: _Editable( - key: _editableKey, - startHandleLayerLink: _startHandleLayerLink, - endHandleLayerLink: _endHandleLayerLink, - inlineSpan: buildTextSpan(), - value: _value, - cursorColor: _cursorColor, - backgroundCursorColor: widget.backgroundCursorColor, - showCursor: EditableText.debugDeterministicCursor - ? ValueNotifier(widget.showCursor) - : _cursorVisibilityNotifier, - forceLine: widget.forceLine, - readOnly: widget.readOnly, - hasFocus: _hasFocus, - maxLines: widget.maxLines, - minLines: widget.minLines, - expands: widget.expands, - strutStyle: widget.strutStyle, - selectionColor: widget.selectionColor, - textScaleFactor: widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context), - textAlign: widget.textAlign, - textDirection: _textDirection, - locale: widget.locale, - textHeightBehavior: widget.textHeightBehavior ?? DefaultTextHeightBehavior.of(context), - textWidthBasis: widget.textWidthBasis, - obscuringCharacter: widget.obscuringCharacter, - obscureText: widget.obscureText, - autocorrect: widget.autocorrect, - smartDashesType: widget.smartDashesType, - smartQuotesType: widget.smartQuotesType, - enableSuggestions: widget.enableSuggestions, - offset: offset, - onCaretChanged: _handleCaretChanged, - rendererIgnoresPointer: widget.rendererIgnoresPointer, - cursorWidth: widget.cursorWidth, - cursorHeight: widget.cursorHeight, - cursorRadius: widget.cursorRadius, - cursorOffset: widget.cursorOffset ?? Offset.zero, - selectionHeightStyle: widget.selectionHeightStyle, - selectionWidthStyle: widget.selectionWidthStyle, - paintCursorAboveText: widget.paintCursorAboveText, - enableInteractiveSelection: widget.enableInteractiveSelection && (!widget.readOnly || !widget.obscureText), - textSelectionDelegate: this, - devicePixelRatio: _devicePixelRatio, - promptRectRange: _currentPromptRectRange, - promptRectColor: widget.autocorrectionTextRectColor, - clipBehavior: widget.clipBehavior, - ), - ), - ); - }, - ), + child: Scrollable( + excludeFromSemantics: true, + axisDirection: _isMultiline ? AxisDirection.down : AxisDirection.right, + controller: _scrollController, + physics: widget.scrollPhysics, + dragStartBehavior: widget.dragStartBehavior, + restorationId: widget.restorationId, + // If a ScrollBehavior is not provided, only apply scrollbars when + // multiline. The overscroll indicator should not be applied in + // either case, glowing or stretching. + scrollBehavior: widget.scrollBehavior ?? ScrollConfiguration.of(context).copyWith( + scrollbars: _isMultiline, + overscroll: false, ), + viewportBuilder: (BuildContext context, ViewportOffset offset) { + return CompositedTransformTarget( + link: _toolbarLayerLink, + child: Semantics( + onCopy: _semanticsOnCopy(controls), + onCut: _semanticsOnCut(controls), + onPaste: _semanticsOnPaste(controls), + child: _Editable( + key: _editableKey, + startHandleLayerLink: _startHandleLayerLink, + endHandleLayerLink: _endHandleLayerLink, + inlineSpan: buildTextSpan(), + value: _value, + cursorColor: _cursorColor, + backgroundCursorColor: widget.backgroundCursorColor, + showCursor: EditableText.debugDeterministicCursor + ? ValueNotifier(widget.showCursor) + : _cursorVisibilityNotifier, + forceLine: widget.forceLine, + readOnly: widget.readOnly, + hasFocus: _hasFocus, + maxLines: widget.maxLines, + minLines: widget.minLines, + expands: widget.expands, + strutStyle: widget.strutStyle, + selectionColor: widget.selectionColor, + textScaleFactor: widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context), + textAlign: widget.textAlign, + textDirection: _textDirection, + locale: widget.locale, + textHeightBehavior: widget.textHeightBehavior ?? DefaultTextHeightBehavior.of(context), + textWidthBasis: widget.textWidthBasis, + obscuringCharacter: widget.obscuringCharacter, + obscureText: widget.obscureText, + autocorrect: widget.autocorrect, + smartDashesType: widget.smartDashesType, + smartQuotesType: widget.smartQuotesType, + enableSuggestions: widget.enableSuggestions, + offset: offset, + onCaretChanged: _handleCaretChanged, + rendererIgnoresPointer: widget.rendererIgnoresPointer, + cursorWidth: widget.cursorWidth, + cursorHeight: widget.cursorHeight, + cursorRadius: widget.cursorRadius, + cursorOffset: widget.cursorOffset ?? Offset.zero, + selectionHeightStyle: widget.selectionHeightStyle, + selectionWidthStyle: widget.selectionWidthStyle, + paintCursorAboveText: widget.paintCursorAboveText, + enableInteractiveSelection: widget.enableInteractiveSelection, + textSelectionDelegate: this, + devicePixelRatio: _devicePixelRatio, + promptRectRange: _currentPromptRectRange, + promptRectColor: widget.autocorrectionTextRectColor, + clipBehavior: widget.clipBehavior, + ), + ), + ); + }, ), ); } @@ -3416,7 +3218,6 @@ class _Editable extends MultiChildRenderObjectWidget { ..cursorOffset = cursorOffset ..selectionHeightStyle = selectionHeightStyle ..selectionWidthStyle = selectionWidthStyle - ..enableInteractiveSelection = enableInteractiveSelection ..textSelectionDelegate = textSelectionDelegate ..devicePixelRatio = devicePixelRatio ..paintCursorAboveText = paintCursorAboveText @@ -3426,550 +3227,36 @@ class _Editable extends MultiChildRenderObjectWidget { } } -/// An interface for retriving the logical text boundary (left-closed-right-open) -/// at a given location in a document. -/// -/// Depending on the implementation of the [_TextBoundary], the input -/// [TextPosition] can either point to a code unit, or a position between 2 code -/// units (which can be visually represented by the caret if the selection were -/// to collapse to that position). -/// -/// For example, [_LineBreak] interprets the input [TextPosition] as a caret -/// location, since in Flutter the caret is generally painted between the -/// character the [TextPosition] points to and its previous character, and -/// [_LineBreak] cares about the affinity of the input [TextPosition]. Most -/// other text boundaries however, interpret the input [TextPosition] as the -/// location of a code unit in the document, since it's easier to reason about -/// the text boundary given a code unit in the text. -/// -/// To convert a "code-unit-based" [_TextBoundary] to "caret-location-based", -/// use the [_CollapsedSelectionBoundary] combinator. -abstract class _TextBoundary { - const _TextBoundary(); - - TextEditingValue get textEditingValue; - - /// Returns the leading text boundary at the given location, inclusive. - TextPosition getLeadingTextBoundaryAt(TextPosition position); - - /// Returns the trailing text boundary at the given location, exclusive. - TextPosition getTrailingTextBoundaryAt(TextPosition position); - - TextRange getTextBoundaryAt(TextPosition position) { - return TextRange( - start: getLeadingTextBoundaryAt(position).offset, - end: getTrailingTextBoundaryAt(position).offset, - ); - } -} - -// ----------------------------- Text Boundaries ----------------------------- - -class _CodeUnitBoundary extends _TextBoundary { - const _CodeUnitBoundary(this.textEditingValue); - - @override - final TextEditingValue textEditingValue; - - @override - TextPosition getLeadingTextBoundaryAt(TextPosition position) => TextPosition(offset: position.offset); - @override - TextPosition getTrailingTextBoundaryAt(TextPosition position) => TextPosition(offset: math.min(position.offset + 1, textEditingValue.text.length)); -} - -// The word modifier generally removes the word boundaries around white spaces -// (and newlines), IOW white spaces and some other punctuations are considered -// a part of the next word in the search direction. -class _WhitespaceBoundary extends _TextBoundary { - const _WhitespaceBoundary(this.textEditingValue); - - @override - final TextEditingValue textEditingValue; - - @override - TextPosition getLeadingTextBoundaryAt(TextPosition position) { - for (int index = position.offset; index >= 0; index -= 1) { - if (!TextLayoutMetrics.isWhitespace(textEditingValue.text.codeUnitAt(index))) { - return TextPosition(offset: index); - } - } - return const TextPosition(offset: 0); - } - - @override - TextPosition getTrailingTextBoundaryAt(TextPosition position) { - for (int index = position.offset; index < textEditingValue.text.length; index += 1) { - if (!TextLayoutMetrics.isWhitespace(textEditingValue.text.codeUnitAt(index))) { - return TextPosition(offset: index + 1); - } - } - return TextPosition(offset: textEditingValue.text.length); - } -} - -// Most apps delete the entire grapheme when the backspace key is pressed. -// Also always put the new caret location to character boundaries to avoid -// sending malformed UTF-16 code units to the paragraph builder. -class _CharacterBoundary extends _TextBoundary { - const _CharacterBoundary(this.textEditingValue); - - @override - final TextEditingValue textEditingValue; - - @override - TextPosition getLeadingTextBoundaryAt(TextPosition position) { - final int endOffset = math.min(position.offset + 1, textEditingValue.text.length); - return TextPosition( - offset: CharacterRange.at(textEditingValue.text, position.offset, endOffset).stringBeforeLength, - ); - } - - @override - TextPosition getTrailingTextBoundaryAt(TextPosition position) { - final int endOffset = math.min(position.offset + 1, textEditingValue.text.length); - final CharacterRange range = CharacterRange.at(textEditingValue.text, position.offset, endOffset); - return TextPosition( - offset: textEditingValue.text.length - range.stringAfterLength, - ); - } - - @override - TextRange getTextBoundaryAt(TextPosition position) { - final int endOffset = math.min(position.offset + 1, textEditingValue.text.length); - final CharacterRange range = CharacterRange.at(textEditingValue.text, position.offset, endOffset); - return TextRange( - start: range.stringBeforeLength, - end: textEditingValue.text.length - range.stringAfterLength, - ); - } -} - -// [UAX #29](https://unicode.org/reports/tr29/) defined word boundaries. -class _WordBoundary extends _TextBoundary { - const _WordBoundary(this.textLayout, this.textEditingValue); +class CommittedContent { + String? mimeType; + String? uri; + Uint8List? data; - final TextLayoutMetrics textLayout; + bool get hasData => data != null && data!.isNotEmpty; - @override - final TextEditingValue textEditingValue; - - @override - TextPosition getLeadingTextBoundaryAt(TextPosition position) { - return TextPosition( - offset: textLayout.getWordBoundary(position).start, - // Word boundary seems to always report downstream on many platforms. - affinity: TextAffinity.downstream, // ignore: avoid_redundant_argument_values - ); - } - @override - TextPosition getTrailingTextBoundaryAt(TextPosition position) { - return TextPosition( - offset: textLayout.getWordBoundary(position).end, - // Word boundary seems to always report downstream on many platforms. - affinity: TextAffinity.downstream, // ignore: avoid_redundant_argument_values - ); - } -} - -// The linebreaks of the current text layout. The input [TextPosition]s are -// interpreted as caret locations because [TextPainter.getLineAtOffset] is -// text-affinity-aware. -class _LineBreak extends _TextBoundary { - const _LineBreak(this.textLayout, this.textEditingValue); - - final TextLayoutMetrics textLayout; - - @override - final TextEditingValue textEditingValue; - - @override - TextPosition getLeadingTextBoundaryAt(TextPosition position) { - return TextPosition( - offset: textLayout.getLineAtOffset(position).start, - ); - } - @override - TextPosition getTrailingTextBoundaryAt(TextPosition position) { - return TextPosition( - offset: textLayout.getLineAtOffset(position).end, - affinity: TextAffinity.upstream, - ); - } -} - -// The document boundary is unique and is a constant function of the input -// position. -class _DocumentBoundary extends _TextBoundary { - const _DocumentBoundary(this.textEditingValue); - - @override - final TextEditingValue textEditingValue; - - @override - TextPosition getLeadingTextBoundaryAt(TextPosition position) => const TextPosition(offset: 0); - @override - TextPosition getTrailingTextBoundaryAt(TextPosition position) { - return TextPosition( - offset: textEditingValue.text.length, - affinity: TextAffinity.upstream, - ); - } -} - -// ------------------------ Text Boundary Combinators ------------------------ - -// Expands the innerTextBoundary with outerTextBoundary. -class _ExpandedTextBoundary extends _TextBoundary { - _ExpandedTextBoundary(this.innerTextBoundary, this.outerTextBoundary); - - final _TextBoundary innerTextBoundary; - final _TextBoundary outerTextBoundary; - - @override - TextEditingValue get textEditingValue { - assert(innerTextBoundary.textEditingValue == outerTextBoundary.textEditingValue); - return innerTextBoundary.textEditingValue; - } - - @override - TextPosition getLeadingTextBoundaryAt(TextPosition position) { - return outerTextBoundary.getLeadingTextBoundaryAt( - innerTextBoundary.getLeadingTextBoundaryAt(position), - ); - } - - @override - TextPosition getTrailingTextBoundaryAt(TextPosition position) { - return outerTextBoundary.getTrailingTextBoundaryAt( - innerTextBoundary.getTrailingTextBoundaryAt(position), - ); - } -} - -// Force the innerTextBoundary to interpret the input [TextPosition]s as caret -// locations instead of code unit positions. -// -// The innerTextBoundary must be a [_TextBoundary] that interprets the input -// [TextPosition]s as code unit positions. -class _CollapsedSelectionBoundary extends _TextBoundary { - _CollapsedSelectionBoundary(this.innerTextBoundary, this.isForward); - - final _TextBoundary innerTextBoundary; - final bool isForward; - - @override - TextEditingValue get textEditingValue => innerTextBoundary.textEditingValue; - - @override - TextPosition getLeadingTextBoundaryAt(TextPosition position) { - return isForward - ? innerTextBoundary.getLeadingTextBoundaryAt(position) - : position.offset <= 0 ? const TextPosition(offset: 0) : innerTextBoundary.getLeadingTextBoundaryAt(TextPosition(offset: position.offset - 1)); - } - - @override - TextPosition getTrailingTextBoundaryAt(TextPosition position) { - return isForward - ? innerTextBoundary.getTrailingTextBoundaryAt(position) - : position.offset <= 0 ? const TextPosition(offset: 0) : innerTextBoundary.getTrailingTextBoundaryAt(TextPosition(offset: position.offset - 1)); - } -} - -// A _TextBoundary that creates a [TextRange] where its start is from the -// specified leading text boundary and its end is from the specified trailing -// text boundary. -class _MixedBoundary extends _TextBoundary { - _MixedBoundary(this.leadingTextBoundary, this.trailingTextBoundary); - - final _TextBoundary leadingTextBoundary; - final _TextBoundary trailingTextBoundary; - - @override - TextEditingValue get textEditingValue { - assert(leadingTextBoundary.textEditingValue == trailingTextBoundary.textEditingValue); - return leadingTextBoundary.textEditingValue; - } - - @override - TextPosition getLeadingTextBoundaryAt(TextPosition position) => leadingTextBoundary.getLeadingTextBoundaryAt(position); - - @override - TextPosition getTrailingTextBoundaryAt(TextPosition position) => trailingTextBoundary.getTrailingTextBoundaryAt(position); -} - -// ------------------------------- Text Actions ------------------------------- -class _DeleteTextAction extends ContextAction { - _DeleteTextAction(this.state, this.getTextBoundariesForIntent); - - final EditableTextState state; - final _TextBoundary Function(T intent) getTextBoundariesForIntent; - - TextRange _expandNonCollapsedRange(TextEditingValue value) { - final TextRange selection = value.selection; - assert(selection.isValid); - assert(!selection.isCollapsed); - final _TextBoundary atomicBoundary = state.widget.obscureText - ? _CodeUnitBoundary(value) - : _CharacterBoundary(value); - - return TextRange( - start: atomicBoundary.getLeadingTextBoundaryAt(TextPosition(offset: selection.start)).offset, - end: atomicBoundary.getTrailingTextBoundaryAt(TextPosition(offset: selection.end - 1)).offset, - ); - } - - @override - Object? invoke(T intent, [BuildContext? context]) { - final TextSelection selection = state._value.selection; - assert(selection.isValid); - - if (!selection.isCollapsed) { - return Actions.invoke( - context!, - ReplaceTextIntent(state._value, '', _expandNonCollapsedRange(state._value), SelectionChangedCause.keyboard), - ); - } - - final _TextBoundary textBoundary = getTextBoundariesForIntent(intent); - if (!textBoundary.textEditingValue.selection.isValid) { - return null; - } - if (!textBoundary.textEditingValue.selection.isCollapsed) { - return Actions.invoke( - context!, - ReplaceTextIntent(state._value, '', _expandNonCollapsedRange(textBoundary.textEditingValue), SelectionChangedCause.keyboard), - ); - } - - return Actions.invoke( - context!, - ReplaceTextIntent( - textBoundary.textEditingValue, - '', - textBoundary.getTextBoundaryAt(textBoundary.textEditingValue.selection.base), - SelectionChangedCause.keyboard, - ), - ); - } - - @override - bool get isActionEnabled => !state.widget.readOnly && state._value.selection.isValid; -} - -class _UpdateTextSelectionAction extends ContextAction { - _UpdateTextSelectionAction(this.state, this.ignoreNonCollapsedSelection, this.getTextBoundariesForIntent); - - final EditableTextState state; - final bool ignoreNonCollapsedSelection; - final _TextBoundary Function(T intent) getTextBoundariesForIntent; - - @override - Object? invoke(T intent, [BuildContext? context]) { - final TextSelection selection = state._value.selection; - assert(selection.isValid); - - final bool collapseSelection = intent.collapseSelection || !state.widget.selectionEnabled; - // Collapse to the logical start/end. - TextSelection _collapse(TextSelection selection) { - assert(selection.isValid); - assert(!selection.isCollapsed); - return selection.copyWith( - baseOffset: intent.forward ? selection.end : selection.start, - extentOffset: intent.forward ? selection.end : selection.start, - ); - } - - if (!selection.isCollapsed && !ignoreNonCollapsedSelection && collapseSelection) { - return Actions.invoke( - context!, - UpdateSelectionIntent(state._value, _collapse(selection), SelectionChangedCause.keyboard), - ); - } - - final _TextBoundary textBoundary = getTextBoundariesForIntent(intent); - final TextSelection textBoundarySelection = textBoundary.textEditingValue.selection; - if (!textBoundarySelection.isValid) { - return null; - } - if (!textBoundarySelection.isCollapsed && !ignoreNonCollapsedSelection && collapseSelection) { - return Actions.invoke( - context!, - UpdateSelectionIntent(state._value, _collapse(textBoundarySelection), SelectionChangedCause.keyboard), - ); - } - - final TextPosition extent = textBoundarySelection.extent; - final TextPosition newExtent = intent.forward - ? textBoundary.getTrailingTextBoundaryAt(extent) - : textBoundary.getLeadingTextBoundaryAt(extent); - - final TextSelection newSelection = collapseSelection - ? TextSelection.fromPosition(newExtent) - : textBoundarySelection.extendTo(newExtent); - - // If collapseAtReversal is true and would have an effect, collapse it. - if (!selection.isCollapsed && intent.collapseAtReversal - && (selection.baseOffset < selection.extentOffset != - newSelection.baseOffset < newSelection.extentOffset)) { - return Actions.invoke( - context!, - UpdateSelectionIntent( - state._value, - TextSelection.fromPosition(selection.base), - SelectionChangedCause.keyboard, - ), - ); - } + CommittedContent({this.mimeType, this.uri, this.data}); - return Actions.invoke( - context!, - UpdateSelectionIntent(textBoundary.textEditingValue, newSelection, SelectionChangedCause.keyboard), + static CommittedContent fromMap(Map? data) { + if (data == null || data.isEmpty) return CommittedContent(); + return CommittedContent( + mimeType: data['mimeType'] as String?, + uri: data['uri'] as String?, + data: Uint8List.fromList(List.from(data['data'] as Iterable)) ); } @override - bool get isActionEnabled => state._value.selection.isValid; -} - -class _ExtendSelectionOrCaretPositionAction extends ContextAction { - _ExtendSelectionOrCaretPositionAction(this.state, this.getTextBoundariesForIntent); - - final EditableTextState state; - final _TextBoundary Function(ExtendSelectionToNextWordBoundaryOrCaretLocationIntent intent) getTextBoundariesForIntent; - - @override - Object? invoke(ExtendSelectionToNextWordBoundaryOrCaretLocationIntent intent, [BuildContext? context]) { - final TextSelection selection = state._value.selection; - assert(selection.isValid); - - final _TextBoundary textBoundary = getTextBoundariesForIntent(intent); - final TextSelection textBoundarySelection = textBoundary.textEditingValue.selection; - if (!textBoundarySelection.isValid) { - return null; - } - - final TextPosition extent = textBoundarySelection.extent; - final TextPosition newExtent = intent.forward - ? textBoundary.getTrailingTextBoundaryAt(extent) - : textBoundary.getLeadingTextBoundaryAt(extent); - - final TextSelection newSelection = (newExtent.offset - textBoundarySelection.baseOffset) * (textBoundarySelection.extentOffset - textBoundarySelection.baseOffset) < 0 - ? textBoundarySelection.copyWith( - extentOffset: textBoundarySelection.baseOffset, - affinity: textBoundarySelection.extentOffset > textBoundarySelection.baseOffset ? TextAffinity.downstream : TextAffinity.upstream, - ) - : textBoundarySelection.extendTo(newExtent); - - return Actions.invoke( - context!, - UpdateSelectionIntent(textBoundary.textEditingValue, newSelection, SelectionChangedCause.keyboard), - ); - } + String toString() => '${objectRuntimeType(this, 'CommittedContent')}($mimeType, $uri, $data)'; @override - bool get isActionEnabled => state.widget.selectionEnabled && state._value.selection.isValid; -} - -class _UpdateTextSelectionToAdjacentLineAction extends ContextAction { - _UpdateTextSelectionToAdjacentLineAction(this.state); - - final EditableTextState state; - - VerticalCaretMovementRun? _verticalMovementRun; - TextSelection? _runSelection; - - void stopCurrentVerticalRunIfSelectionChanges() { - final TextSelection? runSelection = _runSelection; - if (runSelection == null) { - assert(_verticalMovementRun == null); - return; - } - _runSelection = state._value.selection; - final TextSelection currentSelection = state.widget.controller.selection; - final bool continueCurrentRun = currentSelection.isValid && currentSelection.isCollapsed - && currentSelection.baseOffset == runSelection.baseOffset - && currentSelection.extentOffset == runSelection.extentOffset; - if (!continueCurrentRun) { - _verticalMovementRun = null; - _runSelection = null; - } - } - - @override - void invoke(T intent, [BuildContext? context]) { - assert(state._value.selection.isValid); - - final bool collapseSelection = intent.collapseSelection || !state.widget.selectionEnabled; - final TextEditingValue value = state._textEditingValueforTextLayoutMetrics; - if (!value.selection.isValid) { - return; - } - - if (_verticalMovementRun?.isValid == false) { - _verticalMovementRun = null; - _runSelection = null; - } - - final VerticalCaretMovementRun currentRun = _verticalMovementRun - ?? state.renderEditable.startVerticalCaretMovement(state.renderEditable.selection!.extent); - - final bool shouldMove = intent.forward ? currentRun.moveNext() : currentRun.movePrevious(); - final TextPosition newExtent = shouldMove - ? currentRun.current - : (intent.forward ? TextPosition(offset: state._value.text.length) : const TextPosition(offset: 0)); - final TextSelection newSelection = collapseSelection - ? TextSelection.fromPosition(newExtent) - : value.selection.extendTo(newExtent); - - Actions.invoke( - context!, - UpdateSelectionIntent(value, newSelection, SelectionChangedCause.keyboard), - ); - if (state._value.selection == newSelection) { - _verticalMovementRun = currentRun; - _runSelection = newSelection; - } - } - - @override - bool get isActionEnabled => state._value.selection.isValid; -} - -class _SelectAllAction extends ContextAction { - _SelectAllAction(this.state); - - final EditableTextState state; - - @override - Object? invoke(SelectAllTextIntent intent, [BuildContext? context]) { - return Actions.invoke( - context!, - UpdateSelectionIntent( - state._value, - TextSelection(baseOffset: 0, extentOffset: state._value.text.length), - intent.cause, - ), - ); - } - - @override - bool get isActionEnabled => state.widget.selectionEnabled; -} - -class _CopySelectionAction extends ContextAction { - _CopySelectionAction(this.state); - - final EditableTextState state; - - @override - void invoke(CopySelectionTextIntent intent, [BuildContext? context]) { - if (intent.collapseSelection) { - state.cutSelection(intent.cause); - } else { - state.copySelection(intent.cause); - } + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) return false; + return other is CommittedContent + && other.mimeType == mimeType + && other.uri == uri + && other.data == data; } @override - bool get isActionEnabled => state._value.selection.isValid && !state._value.selection.isCollapsed; + int get hashCode => hashValues(mimeType, uri, data); } diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index cd1c2e318b83d..c1ca4d4d213bf 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -409,14 +409,12 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { bool skipTraversal = false, bool canRequestFocus = true, bool descendantsAreFocusable = true, - bool descendantsAreTraversable = true, }) : assert(skipTraversal != null), assert(canRequestFocus != null), assert(descendantsAreFocusable != null), _skipTraversal = skipTraversal, _canRequestFocus = canRequestFocus, - _descendantsAreFocusable = descendantsAreFocusable, - _descendantsAreTraversable = descendantsAreTraversable { + _descendantsAreFocusable = descendantsAreFocusable { // Set it via the setter so that it does nothing on release builds. this.debugLabel = debugLabel; } @@ -431,17 +429,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { /// This is different from [canRequestFocus] because it only implies that the /// node can't be reached via traversal, not that it can't be focused. It may /// still be focused explicitly. - bool get skipTraversal { - if (_skipTraversal) { - return true; - } - for (final FocusNode ancestor in ancestors) { - if (!ancestor.descendantsAreTraversable) { - return true; - } - } - return false; - } + bool get skipTraversal => _skipTraversal; bool _skipTraversal; set skipTraversal(bool value) { if (value != _skipTraversal) { @@ -458,15 +446,15 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { /// If set to false on a [FocusScopeNode], will cause all of the children of /// the scope node to not be focusable. /// - /// If set to false on a [FocusNode], it will not affect the focusability of - /// children of the node. + /// If set to false on a [FocusNode], it will not affect the children of the + /// node. /// /// The [hasFocus] member can still return true if this node is the ancestor /// of a node with primary focus. /// /// This is different than [skipTraversal] because [skipTraversal] still /// allows the node to be focused, just not traversed to via the - /// [FocusTraversalPolicy]. + /// [FocusTraversalPolicy] /// /// Setting [canRequestFocus] to false implies that the node will also be /// skipped for traversal purposes. @@ -523,17 +511,13 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { /// /// See also: /// - /// * [ExcludeFocus], a widget that uses this property to conditionally - /// exclude focus for a subtree. - /// * [descendantsAreTraversable], which makes this widget's descendants - /// untraversable. - /// * [ExcludeFocusTraversal], a widget that conditionally excludes focus - /// traversal for a subtree. - /// * [Focus], a widget that exposes this setting as a parameter. - /// * [FocusTraversalGroup], a widget used to group together and configure - /// the focus traversal policy for a widget subtree that also has an - /// `descendantsAreFocusable` parameter that prevents its children from - /// being focused. + /// * [ExcludeFocus], a widget that uses this property to conditionally + /// exclude focus for a subtree. + /// * [Focus], a widget that exposes this setting as a parameter. + /// * [FocusTraversalGroup], a widget used to group together and configure + /// the focus traversal policy for a widget subtree that also has an + /// `descendantsAreFocusable` parameter that prevents its children from + /// being focused. bool get descendantsAreFocusable => _descendantsAreFocusable; bool _descendantsAreFocusable; @mustCallSuper @@ -550,36 +534,6 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { _manager?._markPropertiesChanged(this); } - /// If false, tells the focus traversal policy to skip over for all of this - /// node's descendants for purposes of the traversal algorithm. - /// - /// Defaults to true. Does not affect the focus traversal of this node: for - /// that, use [skipTraversal]. - /// - /// Does not affect the value of [FocusNode.skipTraversal] on the - /// descendants. Does not affect focusability of the descendants. - /// - /// See also: - /// - /// * [ExcludeFocusTraversal], a widget that uses this property to conditionally - /// exclude focus traversal for a subtree. - /// * [descendantsAreFocusable], which makes this widget's descendants - /// unfocusable. - /// * [ExcludeFocus], a widget that conditionally excludes focus for a subtree. - /// * [FocusTraversalGroup], a widget used to group together and configure - /// the focus traversal policy for a widget subtree that also has an - /// `descendantsAreFocusable` parameter that prevents its children from - /// being focused. - bool get descendantsAreTraversable => _descendantsAreTraversable; - bool _descendantsAreTraversable; - @mustCallSuper - set descendantsAreTraversable(bool value) { - if (value != _descendantsAreTraversable) { - _descendantsAreTraversable = value; - _manager?._markPropertiesChanged(this); - } - } - /// The context that was supplied to [attach]. /// /// This is typically the context for the widget that is being focused, as it @@ -621,18 +575,9 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { /// An iterator over the children that are allowed to be traversed by the /// [FocusTraversalPolicy]. - /// - /// Returns the list of focusable, traversable children of this node, - /// regardless of those settings on this focus node. Will return an empty - /// iterable if [descendantsAreFocusable] is false. - /// - /// See also - /// - /// * [traversalDescendants], which traverses all of the node's descendants, - /// not just the immediate children. Iterable get traversalChildren { - if (!descendantsAreFocusable) { - return const Iterable.empty(); + if (!canRequestFocus) { + return const []; } return children.where( (FocusNode node) => !node.skipTraversal && node.canRequestFocus, @@ -670,12 +615,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { /// Returns all descendants which do not have the [skipTraversal] and do have /// the [canRequestFocus] flag set. - Iterable get traversalDescendants { - if (!descendantsAreFocusable) { - return const Iterable.empty(); - } - return descendants.where((FocusNode node) => !node.skipTraversal && node.canRequestFocus); - } + Iterable get traversalDescendants => descendants.where((FocusNode node) => !node.skipTraversal && node.canRequestFocus); /// An [Iterable] over the ancestors of this node. /// @@ -1151,7 +1091,6 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('context', context, defaultValue: null)); properties.add(FlagProperty('descendantsAreFocusable', value: descendantsAreFocusable, ifFalse: 'DESCENDANTS UNFOCUSABLE', defaultValue: true)); - properties.add(FlagProperty('descendantsAreTraversable', value: descendantsAreTraversable, ifFalse: 'DESCENDANTS UNTRAVERSABLE', defaultValue: true)); properties.add(FlagProperty('canRequestFocus', value: canRequestFocus, ifFalse: 'NOT FOCUSABLE', defaultValue: true)); properties.add(FlagProperty('hasFocus', value: hasFocus && !hasPrimaryFocus, ifTrue: 'IN FOCUS PATH', defaultValue: false)); properties.add(FlagProperty('hasPrimaryFocus', value: hasPrimaryFocus, ifTrue: 'PRIMARY FOCUS', defaultValue: false)); @@ -1245,37 +1184,6 @@ class FocusScopeNode extends FocusNode { // last (which is the top of the stack). final List _focusedChildren = []; - /// An iterator over the children that are allowed to be traversed by the - /// [FocusTraversalPolicy]. - /// - /// Will return an empty iterable if this scope node is not focusable, or if - /// [descendantsAreFocusable] is false. - /// - /// See also: - /// - /// * [traversalDescendants], which traverses all of the node's descendants, - /// not just the immediate children. - @override - Iterable get traversalChildren { - if (!canRequestFocus) { - return const Iterable.empty(); - } - return super.traversalChildren; - } - - /// Returns all descendants which do not have the [skipTraversal] and do have - /// the [canRequestFocus] flag set. - /// - /// Will return an empty iterable if this scope node is not focusable, or if - /// [descendantsAreFocusable] is false. - @override - Iterable get traversalDescendants { - if (!canRequestFocus) { - return const Iterable.empty(); - } - return super.traversalDescendants; - } - /// Make the given [scope] the active child scope for this scope. /// /// If the given [scope] is not yet a part of the focus tree, then add it to @@ -1351,7 +1259,7 @@ class FocusScopeNode extends FocusNode { final List childList = _focusedChildren.reversed.map((FocusNode child) { return child.toStringShort(); }).toList(); - properties.add(IterableProperty('focusedChildren', childList, defaultValue: const Iterable.empty())); + properties.add(IterableProperty('focusedChildren', childList, defaultValue: [])); } } @@ -1603,7 +1511,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { if (_listeners.isEmpty) { return; } - final List> localListeners = List>.of(_listeners); + final List> localListeners = List>.from(_listeners); for (final ValueChanged listener in localListeners) { try { if (_listeners.contains(listener)) { @@ -1612,13 +1520,13 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { } catch (exception, stack) { InformationCollector? collector; assert(() { - collector = () => [ - DiagnosticsProperty( + collector = () sync* { + yield DiagnosticsProperty( 'The $runtimeType sending notification was', this, style: DiagnosticsTreeStyle.errorProperty, - ), - ]; + ); + }; return true; }()); FlutterError.reportError(FlutterErrorDetails( diff --git a/packages/flutter/lib/src/widgets/focus_scope.dart b/packages/flutter/lib/src/widgets/focus_scope.dart index fa787348adf53..034f27dcf119e 100644 --- a/packages/flutter/lib/src/widgets/focus_scope.dart +++ b/packages/flutter/lib/src/widgets/focus_scope.dart @@ -124,7 +124,6 @@ class Focus extends StatefulWidget { bool? canRequestFocus, bool? skipTraversal, bool? descendantsAreFocusable, - bool? descendantsAreTraversable, this.includeSemantics = true, String? debugLabel, }) : _onKeyEvent = onKeyEvent, @@ -132,7 +131,6 @@ class Focus extends StatefulWidget { _canRequestFocus = canRequestFocus, _skipTraversal = skipTraversal, _descendantsAreFocusable = descendantsAreFocusable, - _descendantsAreTraversable = descendantsAreTraversable, _debugLabel = debugLabel, assert(child != null), assert(autofocus != null), @@ -281,17 +279,10 @@ class Focus extends StatefulWidget { /// Does not affect the value of [FocusNode.canRequestFocus] on the /// descendants. /// - /// If a descendant node loses focus when this value is changed, the focus - /// will move to the scope enclosing this node. - /// /// See also: /// /// * [ExcludeFocus], a widget that uses this property to conditionally /// exclude focus for a subtree. - /// * [descendantsAreTraversable], which makes this widget's descendants - /// untraversable. - /// * [ExcludeFocusTraversal], a widget that conditionally excludes focus - /// traversal for a subtree. /// * [FocusTraversalGroup], a widget used to group together and configure the /// focus traversal policy for a widget subtree that has a /// `descendantsAreFocusable` parameter to conditionally block focus for a @@ -300,30 +291,6 @@ class Focus extends StatefulWidget { bool get descendantsAreFocusable => _descendantsAreFocusable ?? focusNode?.descendantsAreFocusable ?? true; final bool? _descendantsAreFocusable; - /// {@template flutter.widgets.Focus.descendantsAreTraversable} - /// If false, will make this widget's descendants untraversable. - /// - /// Defaults to true. Does not affect traversablility of this node (just its - /// descendants): for that, use [FocusNode.skipTraversal]. - /// - /// Does not affect the value of [FocusNode.skipTraversal] on the - /// descendants. Does not affect focusability of the descendants. - /// - /// See also: - /// - /// * [ExcludeFocusTraversal], a widget that uses this property to - /// conditionally exclude focus traversal for a subtree. - /// * [descendantsAreFocusable], which makes this widget's descendants - /// unfocusable. - /// * [ExcludeFocus], a widget that conditionally excludes focus for a subtree. - /// * [FocusTraversalGroup], a widget used to group together and configure the - /// focus traversal policy for a widget subtree that has a - /// `descendantsAreFocusable` parameter to conditionally block focus for a - /// subtree. - /// {@endtemplate} - bool get descendantsAreTraversable => _descendantsAreTraversable ?? focusNode?.descendantsAreTraversable ?? true; - final bool? _descendantsAreTraversable; - /// {@template flutter.widgets.Focus.includeSemantics} /// Include semantics information in this widget. /// @@ -453,7 +420,6 @@ class Focus extends StatefulWidget { properties.add(FlagProperty('autofocus', value: autofocus, ifTrue: 'AUTOFOCUS', defaultValue: false)); properties.add(FlagProperty('canRequestFocus', value: canRequestFocus, ifFalse: 'NOT FOCUSABLE', defaultValue: false)); properties.add(FlagProperty('descendantsAreFocusable', value: descendantsAreFocusable, ifFalse: 'DESCENDANTS UNFOCUSABLE', defaultValue: true)); - properties.add(FlagProperty('descendantsAreTraversable', value: descendantsAreTraversable, ifFalse: 'DESCENDANTS UNTRAVERSABLE', defaultValue: true)); properties.add(DiagnosticsProperty('focusNode', focusNode, defaultValue: null)); } @@ -493,8 +459,6 @@ class _FocusWithExternalFocusNode extends Focus { @override bool get descendantsAreFocusable => focusNode!.descendantsAreFocusable; @override - bool? get _descendantsAreTraversable => focusNode!.descendantsAreTraversable; - @override String? get debugLabel => focusNode!.debugLabel; } @@ -504,7 +468,6 @@ class _FocusState extends State { late bool _hadPrimaryFocus; late bool _couldRequestFocus; late bool _descendantsWereFocusable; - late bool _descendantsWereTraversable; bool _didAutofocus = false; FocusAttachment? _focusAttachment; @@ -522,16 +485,14 @@ class _FocusState extends State { _internalNode ??= _createNode(); } focusNode.descendantsAreFocusable = widget.descendantsAreFocusable; - focusNode.descendantsAreTraversable = widget.descendantsAreTraversable; if (widget.skipTraversal != null) { focusNode.skipTraversal = widget.skipTraversal; } - if (widget._canRequestFocus != null) { - focusNode.canRequestFocus = widget._canRequestFocus!; + if (widget.canRequestFocus != null) { + focusNode.canRequestFocus = widget.canRequestFocus; } _couldRequestFocus = focusNode.canRequestFocus; _descendantsWereFocusable = focusNode.descendantsAreFocusable; - _descendantsWereTraversable = focusNode.descendantsAreTraversable; _hadPrimaryFocus = focusNode.hasPrimaryFocus; _focusAttachment = focusNode.attach(context, onKeyEvent: widget.onKeyEvent, onKey: widget.onKey); @@ -546,7 +507,6 @@ class _FocusState extends State { debugLabel: widget.debugLabel, canRequestFocus: widget.canRequestFocus, descendantsAreFocusable: widget.descendantsAreFocusable, - descendantsAreTraversable: widget.descendantsAreTraversable, skipTraversal: widget.skipTraversal, ); } @@ -615,11 +575,10 @@ class _FocusState extends State { if (widget.skipTraversal != null) { focusNode.skipTraversal = widget.skipTraversal; } - if (widget._canRequestFocus != null) { - focusNode.canRequestFocus = widget._canRequestFocus!; + if (widget.canRequestFocus != null) { + focusNode.canRequestFocus = widget.canRequestFocus; } focusNode.descendantsAreFocusable = widget.descendantsAreFocusable; - focusNode.descendantsAreTraversable = widget.descendantsAreTraversable; } } else { _focusAttachment!.detach(); @@ -636,7 +595,6 @@ class _FocusState extends State { final bool hasPrimaryFocus = focusNode.hasPrimaryFocus; final bool canRequestFocus = focusNode.canRequestFocus; final bool descendantsAreFocusable = focusNode.descendantsAreFocusable; - final bool descendantsAreTraversable = focusNode.descendantsAreTraversable; widget.onFocusChange?.call(focusNode.hasFocus); // Check the cached states that matter here, and call setState if they have // changed. @@ -655,11 +613,6 @@ class _FocusState extends State { _descendantsWereFocusable = descendantsAreFocusable; }); } - if (_descendantsWereTraversable != descendantsAreTraversable) { - setState(() { - _descendantsWereTraversable = descendantsAreTraversable; - }); - } } @override @@ -831,8 +784,6 @@ class _FocusScopeWithExternalFocusNode extends FocusScope { @override bool get descendantsAreFocusable => focusNode!.descendantsAreFocusable; @override - bool get descendantsAreTraversable => focusNode!.descendantsAreTraversable; - @override String? get debugLabel => focusNode!.debugLabel; } diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 7a2d49030fc6e..a1407568b365f 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'actions.dart'; import 'basic.dart'; +import 'editable_text.dart'; import 'focus_manager.dart'; import 'focus_scope.dart'; import 'framework.dart'; @@ -388,11 +389,6 @@ abstract class FocusTraversalPolicy with Diagnosticable { } } final List sortedNodes = _sortAllDescendants(nearestScope, currentNode); - if (sortedNodes.isEmpty) { - // If there are no nodes to traverse to, like when descendantsAreTraversable - // is false or skipTraversal for all the nodes is true. - return false; - } if (forward && focusedChild == sortedNodes.last) { _focusAndEnsureVisible(sortedNodes.first, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd); return true; @@ -1451,12 +1447,10 @@ class FocusTraversalGroup extends StatefulWidget { Key? key, FocusTraversalPolicy? policy, this.descendantsAreFocusable = true, - this.descendantsAreTraversable = true, required this.child, - }) : assert(descendantsAreFocusable != null), - assert(descendantsAreTraversable != null), - policy = policy ?? ReadingOrderTraversalPolicy(), - super(key: key); + }) : assert(descendantsAreFocusable != null), + policy = policy ?? ReadingOrderTraversalPolicy(), + super(key: key); /// The policy used to move the focus from one focus node to another when /// traversing them using a keyboard. @@ -1478,9 +1472,6 @@ class FocusTraversalGroup extends StatefulWidget { /// {@macro flutter.widgets.Focus.descendantsAreFocusable} final bool descendantsAreFocusable; - /// {@macro flutter.widgets.Focus.descendantsAreTraversable} - final bool descendantsAreTraversable; - /// The child widget of this [FocusTraversalGroup]. /// /// {@macro flutter.widgets.ProxyWidget.child} @@ -1583,7 +1574,6 @@ class _FocusTraversalGroupState extends State { skipTraversal: true, includeSemantics: false, descendantsAreFocusable: widget.descendantsAreFocusable, - descendantsAreTraversable: widget.descendantsAreTraversable, child: widget.child, ), ); @@ -1732,78 +1722,10 @@ class DirectionalFocusIntent extends Intent { /// [LogicalKeyboardKey.arrowLeft], and [LogicalKeyboardKey.arrowRight] keys in /// the [WidgetsApp], with the appropriate associated directions. class DirectionalFocusAction extends Action { - /// Creates a [DirectionalFocusAction]. - DirectionalFocusAction() : _isForTextField = false; - - /// Creates a [DirectionalFocusAction] that ignores [DirectionalFocusIntent]s - /// whose `ignoreTextFields` field is true. - DirectionalFocusAction.forTextField() : _isForTextField = true; - - // Whether this action is defined in a text field. - final bool _isForTextField; @override void invoke(DirectionalFocusIntent intent) { - if (!intent.ignoreTextFields || !_isForTextField) { + if (!intent.ignoreTextFields || primaryFocus!.context!.widget is! EditableText) { primaryFocus!.focusInDirection(intent.direction); } } } - -/// A widget that controls whether or not the descendants of this widget are -/// traversable. -/// -/// Does not affect the value of [FocusNode.skipTraversal] of the descendants. -/// -/// See also: -/// -/// * [Focus], a widget for adding and managing a [FocusNode] in the widget tree. -/// * [ExcludeFocus], a widget that excludes its descendants from focusability. -/// * [FocusTraversalGroup], a widget that groups widgets for focus traversal, -/// and can also be used in the same way as this widget by setting its -/// `descendantsAreFocusable` attribute. -class ExcludeFocusTraversal extends StatelessWidget { - /// Const constructor for [ExcludeFocusTraversal] widget. - /// - /// The [excluding] argument must not be null. - /// - /// The [child] argument is required, and must not be null. - const ExcludeFocusTraversal({ - Key? key, - this.excluding = true, - required this.child, - }) : assert(excluding != null), - assert(child != null), - super(key: key); - - /// If true, will make this widget's descendants untraversable. - /// - /// Defaults to true. - /// - /// Does not affect the value of [FocusNode.skipTraversal] on the descendants. - /// - /// See also: - /// - /// * [Focus.descendantsAreTraversable], the attribute of a [Focus] widget that - /// controls this same property for focus widgets. - /// * [FocusTraversalGroup], a widget used to group together and configure the - /// focus traversal policy for a widget subtree that has a - /// `descendantsAreFocusable` parameter to conditionally block focus for a - /// subtree. - final bool excluding; - - /// The child widget of this [ExcludeFocusTraversal]. - /// - /// {@macro flutter.widgets.ProxyWidget.child} - final Widget child; - - @override - Widget build(BuildContext context) { - return Focus( - canRequestFocus: false, - skipTraversal: true, - includeSemantics: false, - descendantsAreTraversable: !excluding, - child: child, - ); - } -} diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 189f3e21b5ee2..ed0424f23c039 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -37,22 +37,6 @@ export 'package:flutter/rendering.dart' show RenderObject, RenderBox, debugDumpR // abstract class FrogJar extends RenderObjectWidget { const FrogJar({Key? key}) : super(key: key); } // abstract class FrogJarParentData extends ParentData { late Size size; } -// An annotation used by test_analysis package to verify patterns are followed -// that allow for tree-shaking of both fields and their initializers. This -// annotation has no impact on code by itself, but indicates the following pattern -// should be followed for a given field: -// -// ```dart -// class Foo { -// final bar = kDebugMode ? Object() : null; -// } -// ``` -class _DebugOnly { - const _DebugOnly(); -} - -const _DebugOnly _debugOnly = _DebugOnly(); - // KEYS /// A key that is only equal to itself. @@ -451,20 +435,6 @@ abstract class Widget extends DiagnosticableTree { /// part of the build function that builds the inner-most widget into its own /// widget, so that only the inner-most widget needs to be rebuilt when the /// theme changes. -/// {@template flutter.flutter.widgets.framework.prefer_const_over_helper} -/// * When trying to create a reusable piece of UI, prefer using a widget -/// rather than a helper method. For example, if there was a function used to -/// build a widget, a [State.setState] call would require Flutter to entirely -/// rebuild the returned wrapping widget. If a [Widget] was used instead, -/// Flutter would be able to efficiently re-render only those parts that -/// really need to be updated. Even better, if the created widget is `const`, -/// Flutter would short-circuit most of the rebuild work. -/// {@endtemplate} -/// -/// This video gives more explainations on why `const` constructors are important -/// and why a [Widget] is better than a helper method. -/// -/// {@youtube 560 315 https://www.youtube.com/watch?v=IOyq-eTRhvo} /// /// {@tool snippet} /// @@ -656,12 +626,11 @@ abstract class StatelessWidget extends Widget { /// this ideal, the more efficient it will be.) /// /// * If a subtree does not change, cache the widget that represents that -/// subtree and re-use it each time it can be used. To do this, simply assign -/// a widget to a `final` state variable and re-use it in the build method. It -/// is massively more efficient for a widget to be re-used than for a new (but -/// identically-configured) widget to be created. Another caching stragegy -/// consists in extracting the mutable part of the widget into a [StatefulWidget] -/// which accepts a child parameter. +/// subtree and re-use it each time it can be used. It is massively more +/// efficient for a widget to be re-used than for a new (but +/// identically-configured) widget to be created. Factoring out the stateful +/// part into a widget that takes a child argument is a common way of doing +/// this. /// /// * Use `const` widgets where possible. (This is equivalent to caching a /// widget and re-using it.) @@ -682,18 +651,11 @@ abstract class StatelessWidget extends Widget { /// [KeyedSubtree] widget may be useful for this purpose if no other widget /// can conveniently be assigned the key.) /// -/// {@macro flutter.flutter.widgets.framework.prefer_const_over_helper} -/// -/// This video gives more explainations on why `const` constructors are important -/// and why a [Widget] is better than a helper method. -/// -/// {@youtube 560 315 https://www.youtube.com/watch?v=IOyq-eTRhvo} -/// /// {@tool snippet} /// /// This is a skeleton of a stateful widget subclass called `YellowBird`. /// -/// In this example, the [State] has no actual state. State is normally +/// In this example. the [State] has no actual state. State is normally /// represented as private member fields. Also, normally widgets have more /// constructor arguments, each of which corresponds to a `final` property. /// @@ -1493,34 +1455,35 @@ abstract class ParentDataWidget extends ProxyWidget { required ParentData? parentData, RenderObjectWidget? parentDataCreator, DiagnosticsNode? ownershipChain, - }) { + }) sync* { assert(T != dynamic); assert(T != ParentData); assert(debugTypicalAncestorWidgetClass != null); final String description = 'The ParentDataWidget $this wants to apply ParentData of type $T to a RenderObject'; - return [ - if (parentData == null) - ErrorDescription( - '$description, which has not been set up to receive any ParentData.', - ) - else - ErrorDescription( - '$description, which has been set up to accept ParentData of incompatible type ${parentData.runtimeType}.', - ), - ErrorHint( - 'Usually, this means that the $runtimeType widget has the wrong ancestor RenderObjectWidget. ' - 'Typically, $runtimeType widgets are placed directly inside $debugTypicalAncestorWidgetClass widgets.', - ), - if (parentDataCreator != null) - ErrorHint( - 'The offending $runtimeType is currently placed inside a ${parentDataCreator.runtimeType} widget.', - ), - if (ownershipChain != null) - ErrorDescription( - 'The ownership chain for the RenderObject that received the incompatible parent data was:\n $ownershipChain', - ), - ]; + if (parentData == null) { + yield ErrorDescription( + '$description, which has not been set up to receive any ParentData.', + ); + } else { + yield ErrorDescription( + '$description, which has been set up to accept ParentData of incompatible type ${parentData.runtimeType}.', + ); + } + yield ErrorHint( + 'Usually, this means that the $runtimeType widget has the wrong ancestor RenderObjectWidget. ' + 'Typically, $runtimeType widgets are placed directly inside $debugTypicalAncestorWidgetClass widgets.', + ); + if (parentDataCreator != null) { + yield ErrorHint( + 'The offending $runtimeType is currently placed inside a ${parentDataCreator.runtimeType} widget.', + ); + } + if (ownershipChain != null) { + yield ErrorDescription( + 'The ownership chain for the RenderObject that received the incompatible parent data was:\n $ownershipChain', + ); + } } /// Write the data from this widget into the given render object's parent data. @@ -1714,13 +1677,6 @@ abstract class InheritedWidget extends ProxyWidget { /// RenderObjectWidgets provide the configuration for [RenderObjectElement]s, /// which wrap [RenderObject]s, which provide the actual rendering of the /// application. -/// -/// See also: -/// -/// * [MultiChildRenderObjectWidget], which configures a [RenderObject] with -/// a single list of children. -/// * [SlottedMultiChildRenderObjectWidgetMixin], which configures a -/// [RenderObject] that organizes its children in different named slots. abstract class RenderObjectWidget extends Widget { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -1811,11 +1767,7 @@ abstract class SingleChildRenderObjectWidget extends RenderObjectWidget { /// See also: /// /// * [Stack], which uses [MultiChildRenderObjectWidget]. -/// * [RenderStack], for an example implementation of the associated render -/// object. -/// * [SlottedMultiChildRenderObjectWidgetMixin], which configures a -/// [RenderObject] that instead of having a single list of children organizes -/// its children in named slots. +/// * [RenderStack], for an example implementation of the associated render object. abstract class MultiChildRenderObjectWidget extends RenderObjectWidget { /// Initializes fields for subclasses. /// @@ -1891,7 +1843,7 @@ abstract class MultiChildRenderObjectWidget extends RenderObjectWidget { /// /// Widget build(...) { /// // Always create a new list of children as a Widget is immutable. - /// return Row(children: List.of(_children)); + /// return Row(children: List.from(_children)); /// } /// } /// ``` @@ -2070,8 +2022,6 @@ typedef ElementVisitor = void Function(Element element); /// the methods on this class should not be cached beyond the execution of a /// single synchronous function. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=rIaaH87z1-g} -/// /// [BuildContext] objects are actually [Element] objects. The [BuildContext] /// interface is used to discourage direct manipulation of [Element] objects. abstract class BuildContext { @@ -2345,18 +2295,10 @@ abstract class BuildContext { /// data down to them. void visitChildElements(ElementVisitor visitor); - /// Returns a description of the [Element] associated with the current build context. - /// - /// The `name` is typically something like "The element being rebuilt was". - /// - /// See also: - /// - /// * [Element.describeElements], which can be used to describe a list of elements. + /// Returns a description of an [Element] from the current build context. DiagnosticsNode describeElement(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty}); /// Returns a description of the [Widget] associated with the current build context. - /// - /// The `name` is typically something like "The widget being rebuilt was". DiagnosticsNode describeWidget(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty}); /// Adds a description of a specific type of widget missing from the current @@ -2572,25 +2514,7 @@ class BuildOwner { _debugBuilding = true; return true; }()); - if (!kReleaseMode) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - if (debugProfileBuildsEnabled) { - debugTimelineArguments = { - ...debugTimelineArguments, - 'dirty count': '${_dirtyElements.length}', - 'dirty list': '$_dirtyElements', - 'lock level': '$_debugStateLockLevel', - 'scope context': '$context', - }; - } - return true; - }()); - Timeline.startSync( - 'BUILD', - arguments: debugTimelineArguments - ); - } + Timeline.startSync('Build', arguments: timelineArgumentsIndicatingLandmarkEvent); try { _scheduledFlushDirtyElements = true; if (callback != null) { @@ -2620,11 +2544,10 @@ class BuildOwner { int dirtyCount = _dirtyElements.length; int index = 0; while (index < dirtyCount) { - final Element element = _dirtyElements[index]; - assert(element != null); - assert(element._inDirtyList); + assert(_dirtyElements[index] != null); + assert(_dirtyElements[index]._inDirtyList); assert(() { - if (element._lifecycleState == _ElementLifecycle.active && !element._debugIsInScope(context)) { + if (_dirtyElements[index]._lifecycleState == _ElementLifecycle.active && !_dirtyElements[index]._debugIsInScope(context)) { throw FlutterError.fromParts([ ErrorSummary('Tried to build dirty widget in the wrong build scope.'), ErrorDescription( @@ -2644,43 +2567,30 @@ class BuildOwner { ), DiagnosticsProperty( 'The offending element (which does not appear to be a descendant of the root of the build scope) was', - element, + _dirtyElements[index], style: DiagnosticsTreeStyle.errorProperty, ), ]); } return true; }()); - if (!kReleaseMode && debugProfileBuildsEnabled) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - debugTimelineArguments = element.widget.toDiagnosticsNode().toTimelineArguments(); - return true; - }()); - Timeline.startSync( - '${element.widget.runtimeType}', - arguments: debugTimelineArguments, - ); - } try { - element.rebuild(); + _dirtyElements[index].rebuild(); } catch (e, stack) { _debugReportException( ErrorDescription('while rebuilding dirty elements'), e, stack, - informationCollector: () => [ - if (kDebugMode && index < _dirtyElements.length) - DiagnosticsDebugCreator(DebugCreator(element)), - if (index < _dirtyElements.length) - element.describeElement('The element being rebuilt at the time was index $index of $dirtyCount') - else - ErrorHint('The element being rebuilt at the time was index $index of $dirtyCount, but _dirtyElements only had ${_dirtyElements.length} entries. This suggests some confusion in the framework internals.'), - ], + informationCollector: () sync* { + if (index < _dirtyElements.length) { + yield DiagnosticsDebugCreator(DebugCreator(_dirtyElements[index])); + yield _dirtyElements[index].describeElement('The element being rebuilt at the time was index $index of $dirtyCount'); + } else { + yield ErrorHint('The element being rebuilt at the time was index $index of $dirtyCount, but _dirtyElements only had ${_dirtyElements.length} entries. This suggests some confusion in the framework internals.'); + } + }, ); } - if (!kReleaseMode && debugProfileBuildsEnabled) - Timeline.finishSync(); index += 1; if (dirtyCount < _dirtyElements.length || _dirtyElementsNeedsResorting!) { _dirtyElements.sort(Element._sort); @@ -2716,9 +2626,7 @@ class BuildOwner { _dirtyElements.clear(); _scheduledFlushDirtyElements = false; _dirtyElementsNeedsResorting = null; - if (!kReleaseMode) { - Timeline.finishSync(); - } + Timeline.finishSync(); assert(_debugBuilding); assert(() { _debugBuilding = false; @@ -2745,21 +2653,12 @@ class BuildOwner { } final Map _globalKeyRegistry = {}; - - // In Profile/Release mode this field is initialized to `null`. The Dart compiler can - // eliminate unused fields, but not their initializers. - @_debugOnly - final Set? _debugIllFatedElements = kDebugMode ? HashSet() : null; - + final Set _debugIllFatedElements = HashSet(); // This map keeps track which child reserves the global key with the parent. // Parent, child -> global key. // This provides us a way to remove old reservation while parent rebuilds the // child in the same slot. - // - // In Profile/Release mode this field is initialized to `null`. The Dart compiler can - // eliminate unused fields, but not their initializers. - @_debugOnly - final Map>? _debugGlobalKeyReservations = kDebugMode ? >{} : null; + final Map> _debugGlobalKeyReservations = >{}; /// The number of [GlobalKey] instances that are currently associated with /// [Element]s that have been built by this build owner. @@ -2769,7 +2668,7 @@ class BuildOwner { assert(() { assert(parent != null); assert(child != null); - _debugGlobalKeyReservations?[parent]?.remove(child); + _debugGlobalKeyReservations[parent]?.remove(child); return true; }()); } @@ -2781,7 +2680,7 @@ class BuildOwner { final Element oldElement = _globalKeyRegistry[key]!; assert(oldElement.widget != null); assert(element.widget.runtimeType != oldElement.widget.runtimeType); - _debugIllFatedElements?.add(oldElement); + _debugIllFatedElements.add(oldElement); } return true; }()); @@ -2806,8 +2705,8 @@ class BuildOwner { assert(() { assert(parent != null); assert(child != null); - _debugGlobalKeyReservations?[parent] ??= {}; - _debugGlobalKeyReservations?[parent]![child] = key; + _debugGlobalKeyReservations[parent] ??= {}; + _debugGlobalKeyReservations[parent]![child] = key; return true; }()); } @@ -2815,7 +2714,7 @@ class BuildOwner { void _debugVerifyGlobalKeyReservation() { assert(() { final Map keyToParent = {}; - _debugGlobalKeyReservations?.forEach((Element parent, Map childToKey) { + _debugGlobalKeyReservations.forEach((Element parent, Map childToKey) { // We ignore parent that are unmounted or detached. if (parent._lifecycleState == _ElementLifecycle.defunct || parent.renderObject?.attached == false) return; @@ -2878,7 +2777,7 @@ class BuildOwner { } }); }); - _debugGlobalKeyReservations?.clear(); + _debugGlobalKeyReservations.clear(); return true; }()); } @@ -2886,7 +2785,7 @@ class BuildOwner { void _debugVerifyIllFatedPopulation() { assert(() { Map>? duplicates; - for (final Element element in _debugIllFatedElements ?? const {}) { + for (final Element element in _debugIllFatedElements) { if (element._lifecycleState != _ElementLifecycle.defunct) { assert(element != null); assert(element.widget != null); @@ -2900,7 +2799,7 @@ class BuildOwner { elements.add(_globalKeyRegistry[key]!); } } - _debugIllFatedElements?.clear(); + _debugIllFatedElements.clear(); if (duplicates != null) { final List information = []; information.add(ErrorSummary('Multiple widgets used the same GlobalKey.')); @@ -2932,11 +2831,11 @@ class BuildOwner { /// about changes to global keys will run. @pragma('vm:notify-debugger-on-exception') void finalizeTree() { - if (!kReleaseMode) { - Timeline.startSync('FINALIZE TREE', arguments: timelineArgumentsIndicatingLandmarkEvent); - } + Timeline.startSync('Finalize tree', arguments: timelineArgumentsIndicatingLandmarkEvent); try { - lockState(_inactiveElements._unmountAll); // this unregisters the GlobalKeys + lockState(() { + _inactiveElements._unmountAll(); // this unregisters the GlobalKeys + }); assert(() { try { _debugVerifyGlobalKeyReservation(); @@ -3027,9 +2926,7 @@ class BuildOwner { // cause more exceptions. _debugReportException(ErrorSummary('while finalizing the widget tree'), e, stack); } finally { - if (!kReleaseMode) { - Timeline.finishSync(); - } + Timeline.finishSync(); } } @@ -3040,18 +2937,14 @@ class BuildOwner { /// /// This is expensive and should not be called except during development. void reassemble(Element root, DebugReassembleConfig? reassembleConfig) { - if (!kReleaseMode) { - Timeline.startSync('Preparing Hot Reload (widgets)'); - } + Timeline.startSync('Dirty Element Tree'); try { assert(root._parent == null); assert(root.owner == this); root._debugReassembleConfig = reassembleConfig; root.reassemble(); } finally { - if (!kReleaseMode) { - Timeline.finishSync(); - } + Timeline.finishSync(); } } } @@ -3117,29 +3010,34 @@ abstract class Element extends DiagnosticableTree implements BuildContext { Element? _parent; DebugReassembleConfig? _debugReassembleConfig; - /// Compare two widgets for equality. - /// - /// When a widget is rebuilt with another that compares equal according - /// to `operator ==`, it is assumed that the update is redundant and the - /// work to update that branch of the tree is skipped. - /// - /// It is generally discouraged to override `operator ==` on any widget that - /// has children, since a correct implementation would have to defer to the - /// children's equality operator also, and that is an O(N²) operation: each - /// child would need to itself walk all its children, each step of the tree. - /// - /// It is sometimes reasonable for a leaf widget (one with no children) to - /// implement this method, if rebuilding the widget is known to be much more - /// expensive than checking the widgets' parameters for equality and if the - /// widget is expected to often be rebuilt with identical parameters. - /// - /// In general, however, it is more efficient to cache the widgets used - /// in a build method if it is known that they will not change. + // Custom implementation of `operator ==` optimized for the ".of" pattern + // used with `InheritedWidgets`. @nonVirtual @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, hash_and_equals + // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) => identical(this, other); + // Custom implementation of hash code optimized for the ".of" pattern used + // with `InheritedWidgets`. + // + // `Element.dependOnInheritedWidgetOfExactType` relies heavily on hash-based + // `Set` look-ups, putting this getter on the performance critical path. + // + // The value is designed to fit within the SMI representation. This makes + // the cached value use less memory (one field and no extra heap objects) and + // cheap to compare (no indirection). + // + // See also: + // + // * https://dart.dev/articles/dart-vm/numeric-computation, which + // explains how numbers are represented in Dart. + @nonVirtual + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _cachedHash; + final int _cachedHash = _nextHashCode = (_nextHashCode + 1) % 0xffffff; + static int _nextHashCode = 1; + /// Information set by parent to define where this child fits in its parent's /// child list. /// @@ -3438,7 +3336,6 @@ abstract class Element extends DiagnosticableTree implements BuildContext { deactivateChild(child); return null; } - final Element newChild; if (child != null) { bool hasSameSuperclass = true; @@ -3464,29 +3361,13 @@ abstract class Element extends DiagnosticableTree implements BuildContext { return true; }()); if (hasSameSuperclass && child.widget == newWidget) { - // We don't insert a timeline event here, because otherwise it's - // confusing that widgets that "don't update" (because they didn't - // change) get "charged" on the timeline. if (child.slot != newSlot) updateSlotForChild(child, newSlot); newChild = child; } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) { if (child.slot != newSlot) updateSlotForChild(child, newSlot); - if (!kReleaseMode && debugProfileBuildsEnabled) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - debugTimelineArguments = newWidget.toDiagnosticsNode().toTimelineArguments(); - return true; - }()); - Timeline.startSync( - '${newWidget.runtimeType}', - arguments: debugTimelineArguments, - ); - } child.update(newWidget); - if (!kReleaseMode && debugProfileBuildsEnabled) - Timeline.finishSync(); assert(child.widget == newWidget); assert(() { child.owner!._debugElementWasRebuilt(child); @@ -3496,36 +3377,10 @@ abstract class Element extends DiagnosticableTree implements BuildContext { } else { deactivateChild(child); assert(child._parent == null); - if (!kReleaseMode && debugProfileBuildsEnabled) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - debugTimelineArguments = newWidget.toDiagnosticsNode().toTimelineArguments(); - return true; - }()); - Timeline.startSync( - '${newWidget.runtimeType}', - arguments: debugTimelineArguments, - ); - } newChild = inflateWidget(newWidget, newSlot); - if (!kReleaseMode && debugProfileBuildsEnabled) - Timeline.finishSync(); } } else { - if (!kReleaseMode && debugProfileBuildsEnabled) { - Map debugTimelineArguments = timelineArgumentsIndicatingLandmarkEvent; - assert(() { - debugTimelineArguments = newWidget.toDiagnosticsNode().toTimelineArguments(); - return true; - }()); - Timeline.startSync( - '${newWidget.runtimeType}', - arguments: debugTimelineArguments, - ); - } newChild = inflateWidget(newWidget, newSlot); - if (!kReleaseMode && debugProfileBuildsEnabled) - Timeline.finishSync(); } assert(() { @@ -3614,8 +3469,8 @@ abstract class Element extends DiagnosticableTree implements BuildContext { // never updates (the forgotten children are not removed from the tree // until the call to update happens) assert(() { - _debugForgottenChildrenWithGlobalKey?.forEach(_debugRemoveGlobalKeyReservation); - _debugForgottenChildrenWithGlobalKey?.clear(); + _debugForgottenChildrenWithGlobalKey.forEach(_debugRemoveGlobalKeyReservation); + _debugForgottenChildrenWithGlobalKey.clear(); return true; }()); _widget = newWidget; @@ -3821,11 +3676,7 @@ abstract class Element extends DiagnosticableTree implements BuildContext { // The children that have been forgotten by forgetChild. This will be used in // [update] to remove the global key reservations of forgotten children. - // - // In Profile/Release mode this field is initialized to `null`. The Dart compiler can - // eliminate unused fields, but not their initializers. - @_debugOnly - final Set? _debugForgottenChildrenWithGlobalKey = kDebugMode ? HashSet() : null; + final Set _debugForgottenChildrenWithGlobalKey = HashSet(); /// Remove the given child from the element's child list, in preparation for /// the child being reused elsewhere in the element tree. @@ -3851,7 +3702,7 @@ abstract class Element extends DiagnosticableTree implements BuildContext { // key duplication that we need to catch. assert(() { if (child.widget.key is GlobalKey) - _debugForgottenChildrenWithGlobalKey?.add(child); + _debugForgottenChildrenWithGlobalKey.add(child); return true; }()); } @@ -4429,9 +4280,6 @@ abstract class Element extends DiagnosticableTree implements BuildContext { owner!.scheduleBuildFor(this); } - /// Cause the widget to update itself. In debug builds, also verify various - /// invariants. - /// /// Called by the [BuildOwner] when [BuildOwner.scheduleBuildFor] has been /// called to mark this element dirty, by [mount] when the element is first /// built, and by [update] when the widget has changed. @@ -4469,9 +4317,7 @@ abstract class Element extends DiagnosticableTree implements BuildContext { assert(!_dirty); } - /// Cause the widget to update itself. - /// - /// Called by [rebuild] after the appropriate checks have been made. + /// Called by rebuild() after the appropriate checks have been made. @protected void performRebuild(); } @@ -4717,8 +4563,7 @@ abstract class ComponentElement extends Element { } void _firstBuild() { - // StatefulElement overrides this to also call state.didChangeDependencies. - rebuild(); // This eventually calls performRebuild. + rebuild(); } /// Calls the [StatelessWidget.build] method of the [StatelessWidget] object @@ -4730,6 +4575,9 @@ abstract class ComponentElement extends Element { @override @pragma('vm:notify-debugger-on-exception') void performRebuild() { + if (!kReleaseMode && debugProfileBuildsEnabled) + Timeline.startSync('${widget.runtimeType}', arguments: timelineArgumentsIndicatingLandmarkEvent); + assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(true)); Widget? built; try { @@ -4750,10 +4598,9 @@ abstract class ComponentElement extends Element { ErrorDescription('building $this'), e, stack, - informationCollector: () => [ - if (kDebugMode) - DiagnosticsDebugCreator(DebugCreator(this)), - ], + informationCollector: () sync* { + yield DiagnosticsDebugCreator(DebugCreator(this)); + }, ), ); } finally { @@ -4771,14 +4618,16 @@ abstract class ComponentElement extends Element { ErrorDescription('building $this'), e, stack, - informationCollector: () => [ - if (kDebugMode) - DiagnosticsDebugCreator(DebugCreator(this)), - ], + informationCollector: () sync* { + yield DiagnosticsDebugCreator(DebugCreator(this)); + }, ), ); _child = updateChild(null, built, slot); } + + if (!kReleaseMode && debugProfileBuildsEnabled) + Timeline.finishSync(); } /// Subclasses should override this function to actually call the appropriate @@ -5193,7 +5042,7 @@ class InheritedElement extends ProxyElement { assert(_lifecycleState == _ElementLifecycle.active); final Map? incomingWidgets = _parent?._inheritedWidgets; if (incomingWidgets != null) - _inheritedWidgets = HashMap.of(incomingWidgets); + _inheritedWidgets = HashMap.from(incomingWidgets); else _inheritedWidgets = HashMap(); _inheritedWidgets![widget.runtimeType] = this; @@ -5630,7 +5479,16 @@ abstract class RenderObjectElement extends Element { _debugUpdateRenderObjectOwner(); return true; }()); - _performRebuild(); // calls widget.updateRenderObject() + assert(() { + _debugDoingBuild = true; + return true; + }()); + widget.updateRenderObject(this, renderObject); + assert(() { + _debugDoingBuild = false; + return true; + }()); + _dirty = false; } void _debugUpdateRenderObjectOwner() { @@ -5642,11 +5500,6 @@ abstract class RenderObjectElement extends Element { @override void performRebuild() { - _performRebuild(); // calls widget.updateRenderObject() - } - - @pragma('vm:prefer-inline') - void _performRebuild() { assert(() { _debugDoingBuild = true; return true; @@ -6503,10 +6356,8 @@ class IndexedSlot { int get hashCode => hashValues(index, value); } -/// Used as a placeholder in [List] objects when the actual -/// elements are not yet determined. class _NullElement extends Element { - _NullElement() : super(const _NullWidget()); + _NullElement() : super(_NullWidget()); static _NullElement instance = _NullElement(); @@ -6514,12 +6365,10 @@ class _NullElement extends Element { bool get debugDoingBuild => throw UnimplementedError(); @override - void performRebuild() => throw UnimplementedError(); + void performRebuild() { } } class _NullWidget extends Widget { - const _NullWidget(); - @override Element createElement() => throw UnimplementedError(); } diff --git a/packages/flutter/lib/src/widgets/gesture_detector.dart b/packages/flutter/lib/src/widgets/gesture_detector.dart index 67beb0ad38d31..bbdbbdda1ec02 100644 --- a/packages/flutter/lib/src/widgets/gesture_detector.dart +++ b/packages/flutter/lib/src/widgets/gesture_detector.dart @@ -114,8 +114,6 @@ class GestureRecognizerFactoryWithHandlers extends /// If this widget has a child, it defers to that child for its sizing behavior. /// If it does not have a child, it grows to fit the parent instead. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=WhVXkCFPmK4} -/// /// By default a GestureDetector with an invisible child ignores touches; /// this behavior can be controlled with [behavior]. /// diff --git a/packages/flutter/lib/src/widgets/icon.dart b/packages/flutter/lib/src/widgets/icon.dart index e5f158568f744..dd97ffeae8556 100644 --- a/packages/flutter/lib/src/widgets/icon.dart +++ b/packages/flutter/lib/src/widgets/icon.dart @@ -30,7 +30,7 @@ import 'icon_theme_data.dart'; /// sizes. The first [Icon] uses a [semanticLabel] to announce in accessibility /// modes like TalkBack and VoiceOver. /// -/// ![The following code snippet would generate a row of icons consisting of a pink heart, a green musical note, and a blue umbrella, each progressively bigger than the last.](https://flutter.github.io/assets-for-api-docs/assets/widgets/icon.png) +/// ![A row of icons representing a pink heart, a green musical note, and a blue umbrella](https://flutter.github.io/assets-for-api-docs/assets/widgets/icon.png) /// /// ```dart /// Row( diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart index 79ec368d4abb1..81ed66599fb18 100644 --- a/packages/flutter/lib/src/widgets/image.dart +++ b/packages/flutter/lib/src/widgets/image.dart @@ -244,7 +244,7 @@ typedef ImageErrorWidgetBuilder = Widget Function( /// * [new Image.file], for obtaining an image from a [File]. /// * [new Image.memory], for obtaining an image from a [Uint8List]. /// -/// The following image formats are supported: {@macro dart.ui.imageFormats} +/// The following image formats are supported: {@macro flutter.dart:ui.imageFormats} /// /// To automatically perform pixel-density-aware asset resolution, specify the /// image using an [AssetImage] and make sure that a [MaterialApp], [WidgetsApp], @@ -464,14 +464,7 @@ class Image extends StatefulWidget { this.filterQuality = FilterQuality.low, int? cacheWidth, int? cacheHeight, - }) : - // FileImage is not supported on Flutter Web therefore neither this method. - assert( - !kIsWeb, - 'Image.file is not supported on Flutter Web. ' - 'Consider using either Image.asset or Image.network instead.', - ), - image = ResizeImage.resizeIfNeeded(cacheWidth, cacheHeight, FileImage(file, scale: scale)), + }) : image = ResizeImage.resizeIfNeeded(cacheWidth, cacheHeight, FileImage(file, scale: scale)), loadingBuilder = null, assert(alignment != null), assert(repeat != null), @@ -654,7 +647,7 @@ class Image extends StatefulWidget { /// /// The `bytes` argument specifies encoded image bytes, which can be encoded /// in any of the following supported image formats: - /// {@macro dart.ui.imageFormats} + /// {@macro flutter.dart:ui.imageFormats} /// /// The `scale` argument specifies the linear scale factor for drawing this /// image at its intended size and applies to both the width and the height. diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart index 9725dfad914bb..de3923065ebf3 100644 --- a/packages/flutter/lib/src/widgets/implicit_animations.dart +++ b/packages/flutter/lib/src/widgets/implicit_animations.dart @@ -541,7 +541,7 @@ abstract class ImplicitlyAnimatedWidgetState /// A base class for widgets with implicit animations that need to rebuild their /// widget tree as the animation runs. /// -/// This class calls [build] each frame that the animation ticks. For a +/// This class calls [build] each frame that the animation tickets. For a /// variant that does not rebuild each frame, consider subclassing /// [ImplicitlyAnimatedWidgetState] directly. /// @@ -1945,7 +1945,7 @@ class AnimatedDefaultTextStyle extends ImplicitlyAnimatedWidget { /// See [TextWidthBasis] for possible values and their implications. final TextWidthBasis textWidthBasis; - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} final ui.TextHeightBehavior? textHeightBehavior; @override diff --git a/packages/flutter/lib/src/widgets/interactive_viewer.dart b/packages/flutter/lib/src/widgets/interactive_viewer.dart index 4137b929f979f..02bda6fa7c2df 100644 --- a/packages/flutter/lib/src/widgets/interactive_viewer.dart +++ b/packages/flutter/lib/src/widgets/interactive_viewer.dart @@ -72,7 +72,6 @@ class InteractiveViewer extends StatefulWidget { this.onInteractionUpdate, this.panEnabled = true, this.scaleEnabled = true, - this.scaleFactor = 200.0, this.transformationController, required Widget this.child, }) : assert(alignPanAxis != null), @@ -119,7 +118,6 @@ class InteractiveViewer extends StatefulWidget { this.onInteractionUpdate, this.panEnabled = true, this.scaleEnabled = true, - this.scaleFactor = 200.0, this.transformationController, required InteractiveViewerWidgetBuilder this.builder, }) : assert(alignPanAxis != null), @@ -251,22 +249,6 @@ class InteractiveViewer extends StatefulWidget { /// * [panEnabled], which is similar but for panning. final bool scaleEnabled; - /// Determines the amount of scale to be performed per pointer scroll. - /// - /// Defaults to 200.0, which was arbitrarily chosen to feel natural for most - /// trackpads and mousewheels on all supported platforms. - /// - /// Increasing this value above the default causes scaling to feel slower, - /// while decreasing it causes scaling to feel faster. - /// - /// The amount of scale is calculated as the exponential function of the - /// [PointerScrollEvent.scrollDelta] to [scaleFactor] ratio. In the Flutter - /// engine, the mousewheel [PointerScrollEvent.scrollDelta] is hardcoded to 20 - /// per scroll, while a trackpad scroll can be any amount. - /// - /// Affects only pointer device scrolling, not pinch to zoom. - final double scaleFactor; - /// The maximum allowed scale. /// /// The scale will be clamped between this and [minScale] inclusively. @@ -899,7 +881,12 @@ class _InteractiveViewerState extends State with TickerProvid localFocalPoint: event.localPosition, ), ); - final double scaleChange = math.exp(-event.scrollDelta.dy / widget.scaleFactor); + + // In the Flutter engine, the mousewheel scrollDelta is hardcoded to 20 + // per scroll, while a trackpad scroll can be any amount. The calculation + // for scaleChange here was arbitrarily chosen to feel natural for both + // trackpads and mousewheels on all platforms. + final double scaleChange = math.exp(-event.scrollDelta.dy / 200); if (!_gestureIsSupported(_GestureType.scale)) { widget.onInteractionUpdate?.call(ScaleUpdateDetails( diff --git a/packages/flutter/lib/src/widgets/layout_builder.dart b/packages/flutter/lib/src/widgets/layout_builder.dart index 5ad7102138864..41720af68e43c 100644 --- a/packages/flutter/lib/src/widgets/layout_builder.dart +++ b/packages/flutter/lib/src/widgets/layout_builder.dart @@ -127,10 +127,9 @@ class _LayoutBuilderElement extends RenderOb ErrorDescription('building $widget'), e, stack, - informationCollector: () => [ - if (kDebugMode) - DiagnosticsDebugCreator(DebugCreator(this)), - ], + informationCollector: () sync* { + yield DiagnosticsDebugCreator(DebugCreator(this)); + }, ), ); } @@ -143,10 +142,9 @@ class _LayoutBuilderElement extends RenderOb ErrorDescription('building $widget'), e, stack, - informationCollector: () => [ - if (kDebugMode) - DiagnosticsDebugCreator(DebugCreator(this)), - ], + informationCollector: () sync* { + yield DiagnosticsDebugCreator(DebugCreator(this)); + }, ), ); _child = updateChild(null, built, slot); diff --git a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart index a7740e999758e..31eead2164e4d 100644 --- a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart @@ -766,26 +766,24 @@ class _ListWheelScrollViewState extends State { } } - bool _handleScrollNotification(ScrollNotification notification) { - if (notification.depth == 0 - && widget.onSelectedItemChanged != null - && notification is ScrollUpdateNotification - && notification.metrics is FixedExtentMetrics) { - final FixedExtentMetrics metrics = notification.metrics as FixedExtentMetrics; - final int currentItemIndex = metrics.itemIndex; - if (currentItemIndex != _lastReportedItemIndex) { - _lastReportedItemIndex = currentItemIndex; - final int trueIndex = widget.childDelegate.trueIndexOf(currentItemIndex); - widget.onSelectedItemChanged!(trueIndex); - } - } - return false; - } - @override Widget build(BuildContext context) { return NotificationListener( - onNotification: _handleScrollNotification, + onNotification: (ScrollNotification notification) { + if (notification.depth == 0 + && widget.onSelectedItemChanged != null + && notification is ScrollUpdateNotification + && notification.metrics is FixedExtentMetrics) { + final FixedExtentMetrics metrics = notification.metrics as FixedExtentMetrics; + final int currentItemIndex = metrics.itemIndex; + if (currentItemIndex != _lastReportedItemIndex) { + _lastReportedItemIndex = currentItemIndex; + final int trueIndex = widget.childDelegate.trueIndexOf(currentItemIndex); + widget.onSelectedItemChanged!(trueIndex); + } + } + return false; + }, child: _FixedExtentScrollable( controller: scrollController, physics: widget.physics, diff --git a/packages/flutter/lib/src/widgets/localizations.dart b/packages/flutter/lib/src/widgets/localizations.dart index dc8399ac492f6..d8a771921fa9e 100644 --- a/packages/flutter/lib/src/widgets/localizations.dart +++ b/packages/flutter/lib/src/widgets/localizations.dart @@ -448,7 +448,7 @@ class Localizations extends StatefulWidget { assert(context != null); final _LocalizationsScope? scope = context.dependOnInheritedWidgetOfExactType<_LocalizationsScope>(); assert(scope != null, 'a Localizations ancestor was not found'); - return List>.of(scope!.localizationsState.widget.delegates); + return List>.from(scope!.localizationsState.widget.delegates); } /// Returns the localized resources object of the given `type` for the widget diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart index 8314292dcd672..9da58dd8238e3 100644 --- a/packages/flutter/lib/src/widgets/media_query.dart +++ b/packages/flutter/lib/src/widgets/media_query.dart @@ -105,8 +105,7 @@ class MediaQueryData { this.disableAnimations = false, this.boldText = false, this.navigationMode = NavigationMode.traditional, - this.gestureSettings = const DeviceGestureSettings(touchSlop: kTouchSlop), - this.displayFeatures = const [], + this.gestureSettings = const DeviceGestureSettings(touchSlop: kTouchSlop) }) : assert(size != null), assert(devicePixelRatio != null), assert(textScaleFactor != null), @@ -122,8 +121,7 @@ class MediaQueryData { assert(disableAnimations != null), assert(boldText != null), assert(navigationMode != null), - assert(gestureSettings != null), - assert(displayFeatures != null); + assert(gestureSettings != null); /// Creates data for a media query based on the given window. /// @@ -148,8 +146,7 @@ class MediaQueryData { highContrast = window.accessibilityFeatures.highContrast, alwaysUse24HourFormat = window.alwaysUse24HourFormat, navigationMode = NavigationMode.traditional, - gestureSettings = DeviceGestureSettings.fromWindow(window), - displayFeatures = window.displayFeatures; + gestureSettings = DeviceGestureSettings.fromWindow(window); /// The size of the media in logical pixels (e.g, the size of the screen). /// @@ -354,17 +351,6 @@ class MediaQueryData { /// gesture behavior over the framework constants. final DeviceGestureSettings gestureSettings; - /// {@macro dart.ui.ViewConfiguration.displayFeatures} - /// - /// See also: - /// - /// * [dart:ui.DisplayFeatureType], which lists the different types of - /// display features and explains the differences between them. - /// * [dart:ui.DisplayFeatureState], which lists the possible states for - /// folding features ([dart:ui.DisplayFeatureType.fold] and - /// [dart:ui.DisplayFeatureType.hinge]). - final List displayFeatures; - /// The orientation of the media (e.g., whether the device is in landscape or /// portrait mode). Orientation get orientation { @@ -390,7 +376,6 @@ class MediaQueryData { bool? boldText, NavigationMode? navigationMode, DeviceGestureSettings? gestureSettings, - List? displayFeatures, }) { return MediaQueryData( size: size ?? this.size, @@ -409,7 +394,6 @@ class MediaQueryData { boldText: boldText ?? this.boldText, navigationMode: navigationMode ?? this.navigationMode, gestureSettings: gestureSettings ?? this.gestureSettings, - displayFeatures: displayFeatures ?? this.displayFeatures, ); } @@ -461,7 +445,6 @@ class MediaQueryData { accessibleNavigation: accessibleNavigation, boldText: boldText, gestureSettings: gestureSettings, - displayFeatures: displayFeatures, ); } @@ -511,7 +494,6 @@ class MediaQueryData { accessibleNavigation: accessibleNavigation, boldText: boldText, gestureSettings: gestureSettings, - displayFeatures: displayFeatures, ); } @@ -561,7 +543,6 @@ class MediaQueryData { accessibleNavigation: accessibleNavigation, boldText: boldText, gestureSettings: gestureSettings, - displayFeatures: displayFeatures, ); } @@ -584,8 +565,7 @@ class MediaQueryData { && other.accessibleNavigation == accessibleNavigation && other.boldText == boldText && other.navigationMode == navigationMode - && other.gestureSettings == gestureSettings - && listEquals(other.displayFeatures, displayFeatures); + && other.gestureSettings == gestureSettings; } @override @@ -606,7 +586,6 @@ class MediaQueryData { boldText, navigationMode, gestureSettings, - hashList(displayFeatures), ); } @@ -626,9 +605,8 @@ class MediaQueryData { 'disableAnimations: $disableAnimations', 'invertColors: $invertColors', 'boldText: $boldText', - 'navigationMode: ${navigationMode.name}', + 'navigationMode: ${describeEnum(navigationMode)}', 'gestureSettings: $gestureSettings', - 'displayFeatures: $displayFeatures', ]; return '${objectRuntimeType(this, 'MediaQueryData')}(${properties.join(', ')})'; } diff --git a/packages/flutter/lib/src/widgets/modal_barrier.dart b/packages/flutter/lib/src/widgets/modal_barrier.dart index c70df59de131f..7e77ef95aea96 100644 --- a/packages/flutter/lib/src/widgets/modal_barrier.dart +++ b/packages/flutter/lib/src/widgets/modal_barrier.dart @@ -34,7 +34,6 @@ class ModalBarrier extends StatelessWidget { Key? key, this.color, this.dismissible = true, - this.onDismiss, this.semanticsLabel, this.barrierSemanticsDismissible = true, }) : super(key: key); @@ -47,12 +46,7 @@ class ModalBarrier extends StatelessWidget { /// [ModalBarrier] built by [ModalRoute] pages. final Color? color; - /// Specifies if the barrier will be dismissed when the user taps on it. - /// - /// If true, and [onDismiss] is non-null, [onDismiss] will be called, - /// otherwise the current route will be popped from the ambient [Navigator]. - /// - /// If false, tapping on the barrier will do nothing. + /// Whether touching the barrier will pop the current route off the [Navigator]. /// /// See also: /// @@ -60,16 +54,6 @@ class ModalBarrier extends StatelessWidget { /// [ModalBarrier] built by [ModalRoute] pages. final bool dismissible; - /// Called when the barrier is being dismissed. - /// - /// If non-null [onDismiss] will be called in place of popping the current - /// route. It is up to the callback to handle dismissing the barrier. - /// - /// If null, the ambient [Navigator]'s current route will be popped. - /// - /// This field is ignored if [dismissible] is false. - final VoidCallback? onDismiss; - /// Whether the modal barrier semantics are included in the semantics tree. /// /// See also: @@ -110,15 +94,7 @@ class ModalBarrier extends StatelessWidget { final bool modalBarrierSemanticsDismissible = barrierSemanticsDismissible ?? semanticsDismissible; void handleDismiss() { - if (dismissible) { - if (onDismiss != null) { - onDismiss!(); - } else { - Navigator.maybePop(context); - } - } else { - SystemSound.play(SystemSoundType.alert); - } + Navigator.maybePop(context); } return BlockSemantics( @@ -127,7 +103,12 @@ class ModalBarrier extends StatelessWidget { // modal barriers are not dismissible in accessibility mode. excluding: !semanticsDismissible || !modalBarrierSemanticsDismissible, child: _ModalBarrierGestureDetector( - onDismiss: handleDismiss, + onDismiss: () { + if (dismissible) + handleDismiss(); + else + SystemSound.play(SystemSoundType.alert); + }, child: Semantics( label: semanticsDismissible ? semanticsLabel : null, onDismiss: semanticsDismissible ? handleDismiss : null, diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 65eb30883c515..f149ea10ff3f4 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -2697,11 +2697,8 @@ class Navigator extends StatefulWidget { // \ / / // idle--+-----+ // / \ -// / +------+ -// / | | -// / | complete* -// | | / -// pop* remove* +// / \ +// pop* remove* // / \ // / removing# // popping# | @@ -2738,7 +2735,6 @@ enum _RouteLifecycle { // // routes that should be included in route announcement and should still listen to transition changes. pop, // we'll want to call didPop - complete, // we'll want to call didComplete, remove, // we'll want to run didReplace/didRemove etc // routes should not be included in route announcement but should still listen to transition changes. popping, // we're waiting for the route to call finalizeRoute to switch to dispose @@ -2874,38 +2870,14 @@ class _RouteEntry extends RouteTransitionRecord { lastAnnouncedPoppedNextRoute = poppedRoute; } - /// Process the to-be-popped route. - /// - /// A route can be marked for pop by transition delegate or Navigator.pop, - /// this method actually pops the route by calling Route.didPop. - /// - /// Returns true if the route is popped; otherwise, returns false if the route - /// refuses to be popped. - bool handlePop({ required NavigatorState navigator, required Route? previousPresent }) { + void handlePop({ required NavigatorState navigator, required Route? previousPresent }) { assert(navigator != null); assert(navigator._debugLocked); assert(route._navigator == navigator); currentState = _RouteLifecycle.popping; - if (route._popCompleter.isCompleted) { - // This is a page-based route popped through the Navigator.pop. The - // didPop should have been called. No further action is needed. - assert(hasPage); - assert(pendingResult == null); - return true; - } - if (!route.didPop(pendingResult)) { - currentState = _RouteLifecycle.idle; - return false; - } - pendingResult = null; - return true; - } - - void handleComplete() { - route.didComplete(pendingResult); - pendingResult = null; - assert(route._popCompleter.isCompleted); // implies didComplete was called - currentState = _RouteLifecycle.remove; + navigator._observedRouteDeletions.add( + _NavigatorPopObservation(route, previousPresent), + ); } void handleRemoval({ required NavigatorState navigator, required Route? previousPresent }) { @@ -2920,6 +2892,8 @@ class _RouteEntry extends RouteTransitionRecord { } } + bool doingPop = false; + void didAdd({ required NavigatorState navigator, required bool isNewFirst}) { route.didAdd(); currentState = _RouteLifecycle.idle; @@ -2928,12 +2902,13 @@ class _RouteEntry extends RouteTransitionRecord { } } - Object? pendingResult; - void pop(T? result) { assert(isPresent); - pendingResult = result; - currentState = _RouteLifecycle.pop; + doingPop = true; + if (route.didPop(result) && doingPop) { + currentState = _RouteLifecycle.pop; + } + doingPop = false; } bool _reportRemovalToObserver = true; @@ -2963,8 +2938,9 @@ class _RouteEntry extends RouteTransitionRecord { return; assert(isPresent); _reportRemovalToObserver = !isReplaced; - pendingResult = result; - currentState = _RouteLifecycle.complete; + route.didComplete(result); + assert(route._popCompleter.isCompleted); // implies didComplete was called + currentState = _RouteLifecycle.remove; } void finalize() { @@ -3515,11 +3491,9 @@ class NavigatorState extends State with TickerProviderStateMixin, Res /// The overlay this navigator uses for its visual presentation. OverlayState? get overlay => _overlayKey.currentState; - Iterable get _allRouteOverlayEntries { - return [ - for (final _RouteEntry entry in _history) - ...entry.route.overlayEntries, - ]; + Iterable get _allRouteOverlayEntries sync* { + for (final _RouteEntry entry in _history) + yield* entry.route.overlayEntries; } String? _lastAnnouncedRouteName; @@ -3789,11 +3763,8 @@ class NavigatorState extends State with TickerProviderStateMixin, Res assert(() { _debugLocked = false; return true; }()); } - bool _flushingHistory = false; - void _flushHistoryUpdates({bool rearrangeOverlay = true}) { assert(_debugLocked && !_debugUpdatingPage); - _flushingHistory = true; // Clean up the list, sending updates to the routes that changed. Notably, // we don't send the didChangePrevious/didChangeNext updates to those that // did not change at this point, because we're not yet sure exactly what the @@ -3857,35 +3828,21 @@ class NavigatorState extends State with TickerProviderStateMixin, Res canRemoveOrAdd = true; break; case _RouteLifecycle.pop: - if (!entry.handlePop( - navigator: this, - previousPresent: _getRouteBefore(index, _RouteEntry.willBePresentPredicate)?.route)){ - assert(entry.currentState == _RouteLifecycle.idle); - continue; - } if (!seenTopActiveRoute) { if (poppedRoute != null) entry.handleDidPopNext(poppedRoute); poppedRoute = entry.route; } - _observedRouteDeletions.add( - _NavigatorPopObservation(entry.route, _getRouteBefore(index, _RouteEntry.willBePresentPredicate)?.route), + entry.handlePop( + navigator: this, + previousPresent: _getRouteBefore(index, _RouteEntry.willBePresentPredicate)?.route, ); - if (entry.currentState == _RouteLifecycle.dispose) { - // The pop finished synchronously. This can happen if transition - // duration is zero. - continue; - } assert(entry.currentState == _RouteLifecycle.popping); canRemoveOrAdd = true; break; case _RouteLifecycle.popping: // Will exit this state when animation completes. break; - case _RouteLifecycle.complete: - entry.handleComplete(); - assert(entry.currentState == _RouteLifecycle.remove); - continue; case _RouteLifecycle.remove: if (!seenTopActiveRoute) { if (poppedRoute != null) @@ -3920,6 +3877,7 @@ class NavigatorState extends State with TickerProviderStateMixin, Res entry = previous; previous = index > 0 ? _history[index - 1] : null; } + // Informs navigator observers about route changes. _flushObserverNotifications(); @@ -3952,7 +3910,6 @@ class NavigatorState extends State with TickerProviderStateMixin, Res if (bucket != null) { _serializableHistory.update(_history); } - _flushingHistory = false; } void _flushObserverNotifications() { @@ -4889,18 +4846,17 @@ class NavigatorState extends State with TickerProviderStateMixin, Res }()); final _RouteEntry entry = _history.lastWhere(_RouteEntry.isPresentPredicate); if (entry.hasPage) { - if (widget.onPopPage!(entry.route, result) && entry.currentState == _RouteLifecycle.idle) { - // The entry may have been disposed if the pop finishes synchronously. - assert(entry.route._popCompleter.isCompleted); + if (widget.onPopPage!(entry.route, result)) entry.currentState = _RouteLifecycle.pop; - } } else { entry.pop(result); - assert (entry.currentState == _RouteLifecycle.pop); } - if (entry.currentState == _RouteLifecycle.pop) + if (entry.currentState == _RouteLifecycle.pop) { + // Flush the history if the route actually wants to be popped (the pop + // wasn't handled internally). _flushHistoryUpdates(rearrangeOverlay: false); - assert(entry.currentState == _RouteLifecycle.idle || entry.route._popCompleter.isCompleted); + assert(entry.route._popCompleter.isCompleted); + } assert(() { _debugLocked = false; return true; @@ -5016,16 +4972,15 @@ class NavigatorState extends State with TickerProviderStateMixin, Res assert(() { wasDebugLocked = _debugLocked; _debugLocked = true; return true; }()); assert(_history.where(_RouteEntry.isRoutePredicate(route)).length == 1); final _RouteEntry entry = _history.firstWhere(_RouteEntry.isRoutePredicate(route)); - // For page-based route, the didPop can be called on any life cycle above - // pop. - assert(entry.currentState == _RouteLifecycle.popping || - (entry.hasPage && entry.currentState.index < _RouteLifecycle.pop.index)); - entry.finalize(); - // finalizeRoute can be called during _flushHistoryUpdates if a pop - // finishes synchronously. - if (!_flushingHistory) + if (entry.doingPop) { + // We were called synchronously from Route.didPop(), but didn't process + // the pop yet. Let's do that now before finalizing. + entry.currentState = _RouteLifecycle.pop; _flushHistoryUpdates(rearrangeOverlay: false); - + } + assert(entry.currentState != _RouteLifecycle.pop); + entry.finalize(); + _flushHistoryUpdates(rearrangeOverlay: false); assert(() { _debugLocked = wasDebugLocked!; return true; }()); } diff --git a/packages/flutter/lib/src/widgets/nested_scroll_view.dart b/packages/flutter/lib/src/widgets/nested_scroll_view.dart index a44118b9bcd62..f951b6c47c516 100644 --- a/packages/flutter/lib/src/widgets/nested_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/nested_scroll_view.dart @@ -55,7 +55,7 @@ typedef NestedScrollViewHeaderSliversBuilder = List Function(BuildContex /// (those inside the [TabBarView], hooking them together so that they appear, /// to the user, as one coherent scroll view. /// -/// {@tool dartpad} +/// {@tool sample} /// This example shows a [NestedScrollView] whose header is the combination of a /// [TabBar] in a [SliverAppBar] and whose body is a [TabBarView]. It uses a /// [SliverOverlapAbsorber]/[SliverOverlapInjector] pair to make the inner lists @@ -110,7 +110,7 @@ typedef NestedScrollViewHeaderSliversBuilder = List Function(BuildContex /// configuration, the flexible space of the app bar will open and collapse, /// while the primary portion of the app bar remains pinned. /// -/// {@tool dartpad} +/// {@tool sample} /// This simple example shows a [NestedScrollView] whose header contains a /// floating [SliverAppBar]. By using the [floatHeaderSlivers] property, the /// floating behavior is coordinated between the outer and inner [Scrollable]s, @@ -140,7 +140,7 @@ typedef NestedScrollViewHeaderSliversBuilder = List Function(BuildContex /// for the nested "inner" scroll view below to end up under the [SliverAppBar] /// even when the inner scroll view thinks it has not been scrolled. /// -/// {@tool dartpad} +/// {@tool sample} /// This simple example shows a [NestedScrollView] whose header contains a /// snapping, floating [SliverAppBar]. _Without_ setting any additional flags, /// e.g [NestedScrollView.floatHeaderSlivers], the [SliverAppBar] will animate @@ -890,9 +890,6 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont } void pointerScroll(double delta) { - // If an update is made to pointer scrolling here, consider if the same - // (or similar) change should be made in - // ScrollPositionWithSingleContext.pointerScroll. assert(delta != 0.0); goIdle(); @@ -900,15 +897,12 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont delta < 0.0 ? ScrollDirection.forward : ScrollDirection.reverse, ); - // Handle notifications. Even if only one position actually receives + // Set the isScrollingNotifier. Even if only one position actually receives // the delta, the NestedScrollView's intention is to treat multiple // ScrollPositions as one. _outerPosition!.isScrollingNotifier.value = true; - _outerPosition!.didStartScroll(); - for (final _NestedScrollPosition position in _innerPositions) { + for (final _NestedScrollPosition position in _innerPositions) position.isScrollingNotifier.value = true; - position.didStartScroll(); - } if (_innerPositions.isEmpty) { // Does not enter overscroll. @@ -956,11 +950,6 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont _outerPosition!.applyClampedPointerSignalUpdate(outerDelta); } } - - _outerPosition!.didEndScroll(); - for (final _NestedScrollPosition position in _innerPositions) { - position.didEndScroll(); - } goBallistic(0.0); } @@ -1144,9 +1133,9 @@ class _NestedScrollController extends ScrollController { ); } - Iterable<_NestedScrollPosition> get nestedPositions { + Iterable<_NestedScrollPosition> get nestedPositions sync* { // TODO(vegorov): use instance method version of castFrom when it is available. - return Iterable.castFrom(positions); + yield* Iterable.castFrom(positions); } } diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart index 75444e2cd89c8..1c7a100eab27d 100644 --- a/packages/flutter/lib/src/widgets/overlay.dart +++ b/packages/flutter/lib/src/widgets/overlay.dart @@ -437,7 +437,7 @@ class OverlayState extends State with TickerProviderStateMixin { return; if (listEquals(_entries, newEntriesList)) return; - final LinkedHashSet old = LinkedHashSet.of(_entries); + final LinkedHashSet old = LinkedHashSet.from(_entries); for (final OverlayEntry entry in newEntriesList) { entry._overlay ??= this; } diff --git a/packages/flutter/lib/src/widgets/overscroll_indicator.dart b/packages/flutter/lib/src/widgets/overscroll_indicator.dart index 93168bfe61cb8..35b196931ad79 100644 --- a/packages/flutter/lib/src/widgets/overscroll_indicator.dart +++ b/packages/flutter/lib/src/widgets/overscroll_indicator.dart @@ -526,11 +526,6 @@ class _GlowController extends ChangeNotifier { canvas.drawCircle(center, radius, paint); canvas.restore(); } - - @override - String toString() { - return '_GlowController(color: $color, axis: ${describeEnum(axis)})'; - } } class _GlowingOverscrollIndicatorPainter extends CustomPainter { @@ -600,11 +595,6 @@ class _GlowingOverscrollIndicatorPainter extends CustomPainter { return oldDelegate.leadingController != leadingController || oldDelegate.trailingController != trailingController; } - - @override - String toString() { - return '_GlowingOverscrollIndicatorPainter($leadingController, $trailingController)'; - } } /// A Material Design visual indication that a scroll view has overscrolled. @@ -901,9 +891,6 @@ class _StretchController extends ChangeNotifier { _stretchController.dispose(); super.dispose(); } - - @override - String toString() => '_StretchController()'; } /// A notification that either a [GlowingOverscrollIndicator] or a diff --git a/packages/flutter/lib/src/widgets/placeholder.dart b/packages/flutter/lib/src/widgets/placeholder.dart index ec6ee1176e45f..01b4a6eaf1a8d 100644 --- a/packages/flutter/lib/src/widgets/placeholder.dart +++ b/packages/flutter/lib/src/widgets/placeholder.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. -import 'package:flutter/foundation.dart'; - import 'basic.dart'; import 'framework.dart'; @@ -97,13 +95,4 @@ class Placeholder extends StatelessWidget { ), ); } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(ColorProperty('color', color, defaultValue: const Color(0xFF455A64))); - properties.add(DoubleProperty('strokeWidth', strokeWidth, defaultValue: 2.0)); - properties.add(DoubleProperty('fallbackWidth', fallbackWidth, defaultValue: 400.0)); - properties.add(DoubleProperty('fallbackHeight', fallbackHeight, defaultValue: 400.0)); - } } diff --git a/packages/flutter/lib/src/widgets/reorderable_list.dart b/packages/flutter/lib/src/widgets/reorderable_list.dart index a87176e176a22..fb7a77fcda1ce 100644 --- a/packages/flutter/lib/src/widgets/reorderable_list.dart +++ b/packages/flutter/lib/src/widgets/reorderable_list.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:math' as math; +import 'dart:math'; import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; @@ -16,6 +16,7 @@ import 'media_query.dart'; import 'overlay.dart'; import 'scroll_controller.dart'; import 'scroll_physics.dart'; +import 'scroll_position.dart'; import 'scroll_view.dart'; import 'scrollable.dart'; import 'sliver.dart'; @@ -521,7 +522,7 @@ class SliverReorderableListState extends State with Ticke int? _insertIndex; Offset? _finalDropPosition; MultiDragGestureRecognizer? _recognizer; - int? _recognizerPointer; + bool _autoScrolling = false; // To implement the gap for the dragged item, we replace the dragged item // with a zero sized box, and then translate all of the later items down // by the size of the dragged item. This allows us to keep the order of the @@ -532,8 +533,6 @@ class SliverReorderableListState extends State with Ticke // so the gap calculation can compensate for it. bool _dragStartTransitionComplete = false; - _EdgeDraggingAutoScroller? _autoScroller; - late ScrollableState _scrollable; Axis get _scrollDirection => axisDirectionToAxis(_scrollable.axisDirection); bool get _reverse => @@ -544,13 +543,6 @@ class SliverReorderableListState extends State with Ticke void didChangeDependencies() { super.didChangeDependencies(); _scrollable = Scrollable.of(context)!; - if (_autoScroller?.scrollable != _scrollable) { - _autoScroller?.stopAutoScroll(); - _autoScroller = _EdgeDraggingAutoScroller( - _scrollable, - onScrollViewScrolled: _handleScrollableAutoScrolled - ); - } } @override @@ -564,7 +556,6 @@ class SliverReorderableListState extends State with Ticke @override void dispose() { _dragInfo?.dispose(); - _autoScroller?.stopAutoScroll(); super.dispose(); } @@ -588,18 +579,12 @@ class SliverReorderableListState extends State with Ticke setState(() { if (_dragInfo != null) { cancelReorder(); - } else if (_recognizer != null && _recognizerPointer != event.pointer) { - _recognizer!.dispose(); - _recognizer = null; - _recognizerPointer = null; } - if (_items.containsKey(index)) { _dragIndex = index; _recognizer = recognizer ..onStart = _dragStart ..addPointer(event); - _recognizerPointer = event.pointer; } else { // TODO(darrenaustin): Can we handle this better, maybe scroll to the item? throw Exception('Attempting to start a drag on a non-visible item'); @@ -677,7 +662,7 @@ class SliverReorderableListState extends State with Ticke setState(() { _overlayEntry?.markNeedsBuild(); _dragUpdateItems(); - _autoScroller?.startAutoScrollIfNecessary(_dragTargetRect); + _autoScrollIfNecessary(); }); } @@ -724,7 +709,6 @@ class SliverReorderableListState extends State with Ticke } _dragInfo?.dispose(); _dragInfo = null; - _autoScroller?.stopAutoScroll(); _resetItemGap(); _recognizer?.dispose(); _recognizer = null; @@ -741,14 +725,6 @@ class SliverReorderableListState extends State with Ticke } } - void _handleScrollableAutoScrolled() { - if (_dragInfo == null) - return; - _dragUpdateItems(); - // Continue scrolling if the drag is still in progress. - _autoScroller?.startAutoScrollIfNecessary(_dragTargetRect); - } - void _dragUpdateItems() { assert(_dragInfo != null); final double gapExtent = _dragInfo!.itemExtent; @@ -827,9 +803,55 @@ class SliverReorderableListState extends State with Ticke } } - Rect get _dragTargetRect { - final Offset origin = _dragInfo!.dragPosition - _dragInfo!.dragOffset; - return Rect.fromLTWH(origin.dx, origin.dy, _dragInfo!.itemSize.width, _dragInfo!.itemSize.height); + Future _autoScrollIfNecessary() async { + if (!_autoScrolling && _dragInfo != null && _dragInfo!.scrollable != null) { + final ScrollPosition position = _dragInfo!.scrollable!.position; + double? newOffset; + const Duration duration = Duration(milliseconds: 14); + const double step = 1.0; + const double overDragMax = 20.0; + const double overDragCoef = 10; + + final RenderBox scrollRenderBox = _dragInfo!.scrollable!.context.findRenderObject()! as RenderBox; + final Offset scrollOrigin = scrollRenderBox.localToGlobal(Offset.zero); + final double scrollStart = _offsetExtent(scrollOrigin, _scrollDirection); + final double scrollEnd = scrollStart + _sizeExtent(scrollRenderBox.size, _scrollDirection); + + final double proxyStart = _offsetExtent(_dragInfo!.dragPosition - _dragInfo!.dragOffset, _scrollDirection); + final double proxyEnd = proxyStart + _dragInfo!.itemExtent; + + if (_reverse) { + if (proxyEnd > scrollEnd && position.pixels > position.minScrollExtent) { + final double overDrag = max(proxyEnd - scrollEnd, overDragMax); + newOffset = max(position.minScrollExtent, position.pixels - step * overDrag / overDragCoef); + } else if (proxyStart < scrollStart && position.pixels < position.maxScrollExtent) { + final double overDrag = max(scrollStart - proxyStart, overDragMax); + newOffset = min(position.maxScrollExtent, position.pixels + step * overDrag / overDragCoef); + } + } else { + if (proxyStart < scrollStart && position.pixels > position.minScrollExtent) { + final double overDrag = max(scrollStart - proxyStart, overDragMax); + newOffset = max(position.minScrollExtent, position.pixels - step * overDrag / overDragCoef); + } else if (proxyEnd > scrollEnd && position.pixels < position.maxScrollExtent) { + final double overDrag = max(proxyEnd - scrollEnd, overDragMax); + newOffset = min(position.maxScrollExtent, position.pixels + step * overDrag / overDragCoef); + } + } + + if (newOffset != null && (newOffset - position.pixels).abs() >= 1.0) { + _autoScrolling = true; + await position.animateTo( + newOffset, + duration: duration, + curve: Curves.linear, + ); + _autoScrolling = false; + if (_dragInfo != null) { + _dragUpdateItems(); + _autoScrollIfNecessary(); + } + } + } } Offset _itemOffsetAt(int index) { @@ -882,146 +904,6 @@ class SliverReorderableListState extends State with Ticke } } -/// An auto scroller that scrolls the [scrollable] if a drag gesture drag close -/// to its edge. -/// -/// The scroll velocity is controlled by the [velocityScalar]: -/// -/// velocity = * [_kDefaultAutoScrollVelocityScalar]. -class _EdgeDraggingAutoScroller { - /// Creates a auto scroller that scrolls the [scrollable]. - _EdgeDraggingAutoScroller(this.scrollable, {this.onScrollViewScrolled}); - - // An eyeball value - static const double _kDefaultAutoScrollVelocityScalar = 7; - - /// The [Scrollable] this auto scroller is scrolling. - final ScrollableState scrollable; - - /// Called when a scroll view is scrolled. - /// - /// The scroll view may be scrolled multiple times in a roll until the drag - /// target no longer triggers the auto scroll. This callback will be called - /// in between each scroll. - final VoidCallback? onScrollViewScrolled; - - late Rect _dragTargetRelatedToScrollOrigin; - - /// Whether the auto scroll is in progress. - bool get scrolling => _scrolling; - bool _scrolling = false; - - double _offsetExtent(Offset offset, Axis scrollDirection) { - switch (scrollDirection) { - case Axis.horizontal: - return offset.dx; - case Axis.vertical: - return offset.dy; - } - } - - double _sizeExtent(Size size, Axis scrollDirection) { - switch (scrollDirection) { - case Axis.horizontal: - return size.width; - case Axis.vertical: - return size.height; - } - } - - AxisDirection get _axisDirection => scrollable.axisDirection; - Axis get _scrollDirection => axisDirectionToAxis(_axisDirection); - - /// Starts the auto scroll if the [dragTarget] is close to the edge. - /// - /// The scroll starts to scroll the [scrollable] if the target rect is close - /// to the edge of the [scrollable]; otherwise, it remains stationary. - /// - /// If the scrollable is already scrolling, calling this method updates the - /// previous dragTarget to the new value and continue scrolling if necessary. - void startAutoScrollIfNecessary(Rect dragTarget) { - final Offset deltaToOrigin = _getDeltaToScrollOrigin(scrollable); - _dragTargetRelatedToScrollOrigin = dragTarget.translate(deltaToOrigin.dx, deltaToOrigin.dy); - if (_scrolling) { - // The change will be picked up in the next scroll. - return; - } - if (!_scrolling) - _scroll(); - } - - /// Stop any ongoing auto scrolling. - void stopAutoScroll() { - _scrolling = false; - } - - Future _scroll() async { - final RenderBox scrollRenderBox = scrollable.context.findRenderObject()! as RenderBox; - final Rect globalRect = MatrixUtils.transformRect( - scrollRenderBox.getTransformTo(null), - Rect.fromLTWH(0, 0, scrollRenderBox.size.width, scrollRenderBox.size.height) - ); - _scrolling = true; - double? newOffset; - const double overDragMax = 20.0; - - final Offset deltaToOrigin = _getDeltaToScrollOrigin(scrollable); - final Offset viewportOrigin = globalRect.topLeft.translate(deltaToOrigin.dx, deltaToOrigin.dy); - final double viewportStart = _offsetExtent(viewportOrigin, _scrollDirection); - final double viewportEnd = viewportStart + _sizeExtent(globalRect.size, _scrollDirection); - - final double proxyStart = _offsetExtent(_dragTargetRelatedToScrollOrigin.topLeft, _scrollDirection); - final double proxyEnd = _offsetExtent(_dragTargetRelatedToScrollOrigin.bottomRight, _scrollDirection); - late double overDrag; - if (_axisDirection == AxisDirection.up || _axisDirection == AxisDirection.left) { - if (proxyEnd > viewportEnd && scrollable.position.pixels > scrollable.position.minScrollExtent) { - overDrag = math.max(proxyEnd - viewportEnd, overDragMax); - newOffset = math.max(scrollable.position.minScrollExtent, scrollable.position.pixels - overDrag); - } else if (proxyStart < viewportStart && scrollable.position.pixels < scrollable.position.maxScrollExtent) { - overDrag = math.max(viewportStart - proxyStart, overDragMax); - newOffset = math.min(scrollable.position.maxScrollExtent, scrollable.position.pixels + overDrag); - } - } else { - if (proxyStart < viewportStart && scrollable.position.pixels > scrollable.position.minScrollExtent) { - overDrag = math.max(viewportStart - proxyStart, overDragMax); - newOffset = math.max(scrollable.position.minScrollExtent, scrollable.position.pixels - overDrag); - } else if (proxyEnd > viewportEnd && scrollable.position.pixels < scrollable.position.maxScrollExtent) { - overDrag = math.max(proxyEnd - viewportEnd, overDragMax); - newOffset = math.min(scrollable.position.maxScrollExtent, scrollable.position.pixels + overDrag); - } - } - - if (newOffset == null || (newOffset - scrollable.position.pixels).abs() < 1.0) { - // Drag should not trigger scroll. - _scrolling = false; - return; - } - final Duration duration = Duration(milliseconds: (1000 / _kDefaultAutoScrollVelocityScalar).round()); - await scrollable.position.animateTo( - newOffset, - duration: duration, - curve: Curves.linear, - ); - if (onScrollViewScrolled != null) - onScrollViewScrolled!(); - if (_scrolling) - await _scroll(); - } -} - -Offset _getDeltaToScrollOrigin(ScrollableState scrollableState) { - switch (scrollableState.axisDirection) { - case AxisDirection.down: - return Offset(0, scrollableState.position.pixels); - case AxisDirection.up: - return Offset(0, -scrollableState.position.pixels); - case AxisDirection.left: - return Offset(-scrollableState.position.pixels, 0); - case AxisDirection.right: - return Offset(scrollableState.position.pixels, 0); - } -} - class _ReorderableItem extends StatefulWidget { const _ReorderableItem({ required Key key, @@ -1227,9 +1109,9 @@ class ReorderableDragStartListener extends StatelessWidget { void _startDragging(BuildContext context, PointerDownEvent event) { final SliverReorderableListState? list = SliverReorderableList.maybeOf(context); list?.startItemDragReorder( - index: index, - event: event, - recognizer: createRecognizer(), + index: index, + event: event, + recognizer: createRecognizer(), ); } } diff --git a/packages/flutter/lib/src/widgets/restoration.dart b/packages/flutter/lib/src/widgets/restoration.dart index 55efff328f40d..3ff29c328f05e 100644 --- a/packages/flutter/lib/src/widgets/restoration.dart +++ b/packages/flutter/lib/src/widgets/restoration.dart @@ -621,7 +621,7 @@ mixin RestorationMixin on State { /// The restoration ID is used to claim a child [RestorationScope] from the /// surrounding [RestorationScope] (accessed via [RestorationScope.of]) and /// the ID must be unique in that scope (otherwise an exception is triggered - /// in debug mode). + /// in debug move). /// /// State restoration for this mixin is turned off when this getter returns /// null or when there is no surrounding [RestorationScope] available. When diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index bca9f5769ecd9..8faf464f577cd 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -809,13 +809,13 @@ class _CallbackHookProvider { stack: stack, library: 'widget library', context: ErrorDescription('while invoking the callback for $runtimeType'), - informationCollector: () => [ - DiagnosticsProperty<_CallbackHookProvider>( + informationCollector: () sync* { + yield DiagnosticsProperty<_CallbackHookProvider>( 'The $runtimeType that invoked the callback was', this, style: DiagnosticsTreeStyle.errorProperty, - ), - ], + ); + }, )); return defaultValue; } diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index 3f37bf25171cb..f019d29b17d7f 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -129,9 +129,7 @@ abstract class TransitionRoute extends OverlayRoute { // // This situation arises when dealing with the Cupertino dismiss gesture. @override - bool get finishedWhenPopped => _controller!.status == AnimationStatus.dismissed && !_popFinalized; - - bool _popFinalized = false; + bool get finishedWhenPopped => _controller!.status == AnimationStatus.dismissed; /// The animation that drives the route's transition and the previous route's /// forward transition. @@ -208,7 +206,6 @@ abstract class TransitionRoute extends OverlayRoute { // removing the route and disposing it. if (!isActive) { navigator!.finalizeRoute(this); - _popFinalized = true; } break; } @@ -1405,7 +1402,7 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute willPop() async { final _ModalScopeState? scope = _scopeKey.currentState; assert(scope != null); - for (final WillPopCallback callback in List.of(_willPopCallbacks)) { + for (final WillPopCallback callback in List.from(_willPopCallbacks)) { if (await callback() != true) return RoutePopDisposition.doNotPop; } @@ -1634,11 +1631,9 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute createOverlayEntries() { - return [ - _modalBarrier = OverlayEntry(builder: _buildModalBarrier), - _modalScope = OverlayEntry(builder: _buildModalScope, maintainState: maintainState), - ]; + Iterable createOverlayEntries() sync* { + yield _modalBarrier = OverlayEntry(builder: _buildModalBarrier); + yield _modalScope = OverlayEntry(builder: _buildModalScope, maintainState: maintainState); } @override diff --git a/packages/flutter/lib/src/widgets/scroll_controller.dart b/packages/flutter/lib/src/widgets/scroll_controller.dart index 92a3206cde465..a00ae680578bf 100644 --- a/packages/flutter/lib/src/widgets/scroll_controller.dart +++ b/packages/flutter/lib/src/widgets/scroll_controller.dart @@ -168,7 +168,7 @@ class ScrollController extends ChangeNotifier { /// value was out of range. void jumpTo(double value) { assert(_positions.isNotEmpty, 'ScrollController not attached to any scroll views.'); - for (final ScrollPosition position in List.of(_positions)) + for (final ScrollPosition position in List.from(_positions)) position.jumpTo(value); } diff --git a/packages/flutter/lib/src/widgets/scroll_notification_observer.dart b/packages/flutter/lib/src/widgets/scroll_notification_observer.dart index 7829cbd59e409..7742e435e2667 100644 --- a/packages/flutter/lib/src/widgets/scroll_notification_observer.dart +++ b/packages/flutter/lib/src/widgets/scroll_notification_observer.dart @@ -128,7 +128,7 @@ class ScrollNotificationObserverState extends State if (_listeners!.isEmpty) return; - final List<_ListenerEntry> localListeners = List<_ListenerEntry>.of(_listeners!); + final List<_ListenerEntry> localListeners = List<_ListenerEntry>.from(_listeners!); for (final _ListenerEntry entry in localListeners) { try { if (entry.list != null) @@ -139,13 +139,13 @@ class ScrollNotificationObserverState extends State stack: stack, library: 'widget library', context: ErrorDescription('while dispatching notifications for $runtimeType'), - informationCollector: () => [ - DiagnosticsProperty( + informationCollector: () sync* { + yield DiagnosticsProperty( 'The $runtimeType sending notification was', this, style: DiagnosticsTreeStyle.errorProperty, - ), - ], + ); + }, )); } } diff --git a/packages/flutter/lib/src/widgets/scroll_physics.dart b/packages/flutter/lib/src/widgets/scroll_physics.dart index dca3b7a28ca00..8e3e18809e00e 100644 --- a/packages/flutter/lib/src/widgets/scroll_physics.dart +++ b/packages/flutter/lib/src/widgets/scroll_physics.dart @@ -428,12 +428,8 @@ class ScrollPhysics { /// Scroll physics that attempt to keep the scroll position in range when the /// contents change dimensions suddenly. /// -/// This attempts to maintain the amount of overscroll or underscroll already present, -/// if the scroll position is already out of range _and_ the extents -/// have decreased, meaning that some content was removed. The reason for this -/// condition is that when new content is added, keeping the same overscroll -/// would mean that instead of showing it to the user, all of it is -/// being skipped by jumping right to the max extent. +/// If the scroll position is already out of range, this attempts to maintain +/// the amount of overscroll or underscroll already present. /// /// If the scroll activity is animating the scroll position, sudden changes to /// the scroll dimensions are allowed to happen (so as to prevent animations @@ -517,9 +513,9 @@ class RangeMaintainingScrollPhysics extends ScrollPhysics { maintainOverscroll = false; if (oldPosition.minScrollExtent.isFinite && oldPosition.maxScrollExtent.isFinite && newPosition.minScrollExtent.isFinite && newPosition.maxScrollExtent.isFinite) { - // In addition, if the position changed then we don't enforce the new - // boundary if both the new and previous boundaries are entirely finite. - // A common case where the position changes while one + // In addition, if the position changed then we only enforce + // the new boundary if the previous boundary was not entirely + // finite. A common case where the position changes while one // of the extents is infinite is a lazily-loaded list. (If the // boundaries were finite, and the position changed, then we // assume it was intentional.) @@ -533,19 +529,13 @@ class RangeMaintainingScrollPhysics extends ScrollPhysics { enforceBoundary = false; } if (maintainOverscroll) { - // Force the new position to be no more out of range than it was before, if: - // * it was overscrolled, and - // * the extents have decreased, meaning that some content was removed. The - // reason for this condition is that when new content is added, keeping - // the same overscroll would mean that instead of showing it to the user, - // all of it is being skipped by jumping right to the max extent. - if (oldPosition.pixels < oldPosition.minScrollExtent && - newPosition.minScrollExtent > oldPosition.minScrollExtent) { + // Force the new position to be no more out of range + // than it was before, if it was overscrolled. + if (oldPosition.pixels < oldPosition.minScrollExtent) { final double oldDelta = oldPosition.minScrollExtent - oldPosition.pixels; return newPosition.minScrollExtent - oldDelta; } - if (oldPosition.pixels > oldPosition.maxScrollExtent && - newPosition.maxScrollExtent < oldPosition.maxScrollExtent) { + if (oldPosition.pixels > oldPosition.maxScrollExtent) { final double oldDelta = oldPosition.pixels - oldPosition.maxScrollExtent; return newPosition.maxScrollExtent + oldDelta; } diff --git a/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart b/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart index ab25d87b5176b..09dea8ad5e965 100644 --- a/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart +++ b/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart @@ -205,9 +205,6 @@ class ScrollPositionWithSingleContext extends ScrollPosition implements ScrollAc @override void pointerScroll(double delta) { - // If an update is made to pointer scrolling here, consider if the same - // (or similar) change should be made in - // _NestedScrollCoordinator.pointerScroll. assert(delta != 0.0); final double targetPixels = diff --git a/packages/flutter/lib/src/widgets/scroll_view.dart b/packages/flutter/lib/src/widgets/scroll_view.dart index 923a207b88c30..ad78e2b9ae0e0 100644 --- a/packages/flutter/lib/src/widgets/scroll_view.dart +++ b/packages/flutter/lib/src/widgets/scroll_view.dart @@ -237,8 +237,6 @@ abstract class ScrollView extends StatelessWidget { /// scroll view needs to be recomputed whenever the scroll position changes. /// /// Defaults to false. - /// - /// {@youtube 560 315 https://www.youtube.com/watch?v=LUqDNnv_dh0} /// {@endtemplate} final bool shrinkWrap; diff --git a/packages/flutter/lib/src/widgets/scrollbar.dart b/packages/flutter/lib/src/widgets/scrollbar.dart index 488e36df0deda..0b1588663b688 100644 --- a/packages/flutter/lib/src/widgets/scrollbar.dart +++ b/packages/flutter/lib/src/widgets/scrollbar.dart @@ -90,7 +90,6 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { double minLength = _kMinThumbExtent, double? minOverscrollLength, ScrollbarOrientation? scrollbarOrientation, - bool ignorePointer = false, }) : assert(color != null), assert(radius == null || shape == null), assert(thickness != null), @@ -103,9 +102,6 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { assert(minOverscrollLength == null || minOverscrollLength >= 0), assert(padding != null), assert(padding.isNonNegative), - assert(trackColor != null), - assert(trackBorderColor != null), - assert(ignorePointer != null), _color = color, _textDirection = textDirection, _thickness = thickness, @@ -118,8 +114,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { _trackColor = trackColor, _trackBorderColor = trackBorderColor, _scrollbarOrientation = scrollbarOrientation, - _minOverscrollLength = minOverscrollLength ?? minLength, - _ignorePointer = ignorePointer { + _minOverscrollLength = minOverscrollLength ?? minLength { fadeoutOpacityAnimation.addListener(notifyListeners); } @@ -346,17 +341,6 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { notifyListeners(); } - /// Whether the painter will be ignored during hit testing. - bool get ignorePointer => _ignorePointer; - bool _ignorePointer; - set ignorePointer(bool value) { - if (ignorePointer == value) - return; - - _ignorePointer = value; - notifyListeners(); - } - void _debugAssertIsValidOrientation(ScrollbarOrientation orientation) { assert( (_isVertical && _isVerticalOrientation(orientation)) || (!_isVertical && !_isVerticalOrientation(orientation)), @@ -623,8 +607,6 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { return _paintScrollbar(canvas, size, thumbExtent, _lastAxisDirection!); } - bool get _lastMetricsAreScrollable => _lastMetrics!.minScrollExtent != _lastMetrics!.maxScrollExtent; - /// Same as hitTest, but includes some padding when the [PointerEvent] is /// caused by [PointerDeviceKind.touch] to make sure that the region /// isn't too small to be interacted with by the user. @@ -635,19 +617,12 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { /// based on proximity. When `forHover` is true, the larger hit test area will /// be used. bool hitTestInteractive(Offset position, PointerDeviceKind kind, { bool forHover = false }) { - if (_trackRect == null) { + if (_thumbRect == null) { // We have not computed the scrollbar position yet. return false; } - if (ignorePointer) { - return false; - } - if (!_lastMetricsAreScrollable) { - return false; - } - - final Rect interactiveRect = _trackRect!; + final Rect interactiveRect = _trackRect ?? _thumbRect!; final Rect paddedRect = interactiveRect.expandToInclude( Rect.fromCircle(center: _thumbRect!.center, radius: _kMinInteractiveSize / 2), ); @@ -678,18 +653,11 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { if (_thumbRect == null) { return false; } - if (ignorePointer) { - return false; - } // The thumb is not able to be hit when transparent. if (fadeoutOpacityAnimation.value == 0.0) { return false; } - if (!_lastMetricsAreScrollable) { - return false; - } - switch (kind) { case PointerDeviceKind.touch: final Rect touchThumbRect = _thumbRect!.expandToInclude( @@ -710,18 +678,10 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { if (_thumbRect == null) { return null; } - if (ignorePointer) { - return false; - } // The thumb is not able to be hit when transparent. if (fadeoutOpacityAnimation.value == 0.0) { return false; } - - if (!_lastMetricsAreScrollable) { - return false; - } - return _thumbRect!.contains(position!); } @@ -741,8 +701,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { || padding != oldDelegate.padding || minLength != oldDelegate.minLength || minOverscrollLength != oldDelegate.minOverscrollLength - || scrollbarOrientation != oldDelegate.scrollbarOrientation - || ignorePointer != oldDelegate.ignorePointer; + || scrollbarOrientation != oldDelegate.scrollbarOrientation; } @override @@ -750,9 +709,6 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { @override SemanticsBuilderCallback? get semanticsBuilder => null; - - @override - String toString() => describeIdentity(this); } /// An extendable base class for building scrollbars that fade in and out. @@ -760,8 +716,6 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { /// To add a scrollbar to a [ScrollView], like a [ListView] or a /// [CustomScrollView], wrap the scroll view widget in a [RawScrollbar] widget. /// -/// {@youtube 560 315 https://www.youtube.com/watch?v=DbkIQSvwnZc} -/// /// {@template flutter.widgets.Scrollbar} /// A scrollbar thumb indicates which portion of a [ScrollView] is actually /// visible. @@ -1135,8 +1089,7 @@ class RawScrollbar extends StatefulWidget { /// match native behavior. On Android, the scrollbar is not interactive by /// default. /// - /// When false, the scrollbar will not respond to gesture or hover events, - /// and will allow to click through it. + /// When false, the scrollbar will not respond to gesture or hover events. /// /// Defaults to true when null, unless on Android, which will default to false /// when null. @@ -1208,9 +1161,6 @@ class RawScrollbarState extends State with TickerProv /// Overridable getter to indicate is gestures should be enabled on the /// scrollbar. /// - /// When false, the scrollbar will not respond to gesture or hover events, - /// and will allow to click through it. - /// /// Subclasses can override this getter to make its value depend on an inherited /// theme. /// @@ -1235,15 +1185,14 @@ class RawScrollbarState extends State with TickerProv ); scrollbarPainter = ScrollbarPainter( color: widget.thumbColor ?? const Color(0x66BCBCBC), - fadeoutOpacityAnimation: _fadeoutOpacityAnimation, + minLength: widget.minThumbLength, + minOverscrollLength: widget.minOverscrollLength ?? widget.minThumbLength, thickness: widget.thickness ?? _kScrollbarThickness, - radius: widget.radius, + fadeoutOpacityAnimation: _fadeoutOpacityAnimation, scrollbarOrientation: widget.scrollbarOrientation, mainAxisMargin: widget.mainAxisMargin, shape: widget.shape, - crossAxisMargin: widget.crossAxisMargin, - minLength: widget.minThumbLength, - minOverscrollLength: widget.minOverscrollLength ?? widget.minThumbLength, + crossAxisMargin: widget.crossAxisMargin ); } @@ -1378,8 +1327,7 @@ class RawScrollbarState extends State with TickerProv ..shape = widget.shape ..crossAxisMargin = widget.crossAxisMargin ..minLength = widget.minThumbLength - ..minOverscrollLength = widget.minOverscrollLength ?? widget.minThumbLength - ..ignorePointer = !enableGestures; + ..minOverscrollLength = widget.minOverscrollLength ?? widget.minThumbLength; } @override @@ -1399,7 +1347,6 @@ class RawScrollbarState extends State with TickerProv void _updateScrollPosition(Offset updatedOffset) { assert(_currentController != null); assert(_dragScrollbarAxisOffset != null); - final ScrollPosition position = _currentController!.position; late double primaryDelta; switch (position.axisDirection) { @@ -1434,7 +1381,7 @@ class RawScrollbarState extends State with TickerProv case TargetPlatform.linux: case TargetPlatform.macOS: case TargetPlatform.windows: - newPosition = newPosition.clamp(position.minScrollExtent, position.maxScrollExtent); + newPosition = newPosition.clamp(0.0, position.maxScrollExtent); break; case TargetPlatform.iOS: case TargetPlatform.android: diff --git a/packages/flutter/lib/src/widgets/shared_app_data.dart b/packages/flutter/lib/src/widgets/shared_app_data.dart index 154cff2678e28..58666cbcbe08c 100644 --- a/packages/flutter/lib/src/widgets/shared_app_data.dart +++ b/packages/flutter/lib/src/widgets/shared_app_data.dart @@ -167,7 +167,7 @@ class _SharedAppDataState extends State { void setValue(K key, V value) { if (data[key] != value) { setState(() { - data = Map.of(data); + data = Map.from(data); data[key] = value; }); } diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index 9f1b5e916b8a5..7f1e637ec0d2c 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -74,7 +74,7 @@ class KeySet { : assert(keys != null), assert(keys.isNotEmpty), assert(!keys.contains(null)), - _keys = HashSet.of(keys); + _keys = HashSet.from(keys); /// Returns a copy of the [KeyboardKey]s in this [KeySet]. Set get keys => _keys.toSet(); @@ -388,7 +388,8 @@ class ShortcutMapProperty extends DiagnosticsProperty get triggers { - return [trigger]; + Iterable get triggers sync* { + yield trigger; } @override bool accepts(RawKeyEvent event, RawKeyboard state) { final Set pressed = state.keysPressed; return event is RawKeyDownEvent - && (includeRepeats || !event.repeat) && (control == (pressed.contains(LogicalKeyboardKey.controlLeft) || pressed.contains(LogicalKeyboardKey.controlRight))) && (shift == (pressed.contains(LogicalKeyboardKey.shiftLeft) || pressed.contains(LogicalKeyboardKey.shiftRight))) && (alt == (pressed.contains(LogicalKeyboardKey.altLeft) || pressed.contains(LogicalKeyboardKey.altRight))) @@ -532,7 +522,6 @@ class SingleActivator with Diagnosticable implements ShortcutActivator { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('keys', debugDescribeKeys())); - properties.add(FlagProperty('includeRepeats', value: includeRepeats, ifFalse: 'excluding repeats')); } } @@ -743,7 +732,7 @@ class ShortcutManager extends ChangeNotifier with Diagnosticable { } } -/// A widget that creates key bindings to specific actions for its +/// A widget to that creates key bindings to specific actions for its /// descendants. /// /// This widget establishes a [ShortcutManager] to be used by its descendants @@ -1016,11 +1005,9 @@ class CallbackShortcuts extends StatelessWidget { // throws, by providing the activator and event as arguments that will appear // in the stack trace. bool _applyKeyBinding(ShortcutActivator activator, RawKeyEvent event) { - if (activator.triggers?.contains(event.logicalKey) ?? true) { - if (activator.accepts(event, RawKeyboard.instance)) { - bindings[activator]!.call(); - return true; - } + if (activator.accepts(event, RawKeyboard.instance)) { + bindings[activator]!.call(); + return true; } return false; } diff --git a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart index c4e54d17a7542..2b2e40ea74de5 100644 --- a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart @@ -34,7 +34,7 @@ import 'scrollable.dart'; /// When you have a list of children and do not require cross-axis /// shrink-wrapping behavior, for example a scrolling list that is always the /// width of the screen, consider [ListView], which is vastly more efficient -/// than a [SingleChildScrollView] containing a [ListBody] or [Column] with +/// that a [SingleChildScrollView] containing a [ListBody] or [Column] with /// many children. /// /// ## Sample code: Using [SingleChildScrollView] with a [Column] diff --git a/packages/flutter/lib/src/widgets/sliver.dart b/packages/flutter/lib/src/widgets/sliver.dart index 14027205053db..132991b013779 100644 --- a/packages/flutter/lib/src/widgets/sliver.dart +++ b/packages/flutter/lib/src/widgets/sliver.dart @@ -662,7 +662,7 @@ class SliverChildListDelegate extends SliverChildDelegate { /// /// Widget build(BuildContext context) { /// // Always create a new list of children as a Widget is immutable. - /// return PageView(children: List.of(_children)); + /// return PageView(children: List.from(_children)); /// } /// } /// ``` diff --git a/packages/flutter/lib/src/widgets/sliver_fill.dart b/packages/flutter/lib/src/widgets/sliver_fill.dart index cadc22b8dada8..66334100c5b1b 100644 --- a/packages/flutter/lib/src/widgets/sliver_fill.dart +++ b/packages/flutter/lib/src/widgets/sliver_fill.dart @@ -239,7 +239,7 @@ class _RenderSliverFractionalPadding extends RenderSliverEdgeInsetsPadding { /// /// {@animation 250 500 https://flutter.github.io/assets-for-api-docs/assets/widgets/sliver_fill_remaining_fill_overscroll.mp4} /// -/// {@tool dartpad} +/// {@tool sample} /// In this sample the [SliverFillRemaining]'s child stretches to fill the /// overscroll area when [fillOverscroll] is true. This sample also features a /// button that is pinned to the bottom of the sliver, regardless of size or diff --git a/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart b/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart deleted file mode 100644 index 25ae7b4d3b722..0000000000000 --- a/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart +++ /dev/null @@ -1,271 +0,0 @@ -// 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 'package:flutter/foundation.dart'; -import 'package:flutter/rendering.dart'; - -import 'framework.dart'; - -/// A mixin for a [RenderObjectWidget] that configures a [RenderObject] -/// subclass, which organizes its children in different slots. -/// -/// Implementers of this mixin have to provide the list of available slots by -/// overriding [slots]. The list of slots must never change for a given class -/// implementing this mixin. In the common case, [Enum] values are used as slots -/// and [slots] is typically implemented to return the value of the enum's -/// `values` getter. -/// -/// Furthermore, [childForSlot] must be implemented to return the current -/// widget configuration for a given slot. -/// -/// The [RenderObject] returned by [createRenderObject] and updated by -/// [updateRenderObject] must implement the [SlottedContainerRenderObjectMixin]. -/// -/// The type parameter `S` is the type for the slots to be used by this -/// [RenderObjectWidget] and the [RenderObject] it configures. In the typical -/// case, `S` is an [Enum] type. -/// -/// {@tool dartpad} -/// This example uses the [SlottedMultiChildRenderObjectWidgetMixin] in -/// combination with the [SlottedContainerRenderObjectMixin] to implement a -/// widget that provides two slots: topLeft and bottomRight. The widget arranges -/// the children in those slots diagonally. -/// -/// ** See code in examples/api/lib/widgets/slotted_render_object_widget/slotted_multi_child_render_object_widget_mixin.0.dart ** -/// {@end-tool} -/// -/// See also: -/// -/// * [MultiChildRenderObjectWidget], which configures a [RenderObject] -/// with a single list of children. -/// * [ListTile], which uses [SlottedMultiChildRenderObjectWidgetMixin] in its -/// internal (private) implementation. -mixin SlottedMultiChildRenderObjectWidgetMixin on RenderObjectWidget { - /// Returns a list of all available slots. - /// - /// The list of slots must be static and must never change for a given class - /// implementing this mixin. - /// - /// Typically, an [Enum] is used to identify the different slots. In that case - /// this getter can be implemented by returning what the `values` getter - /// of the enum used returns. - @protected - Iterable get slots; - - /// Returns the widget that is currently occupying the provided `slot`. - /// - /// The [RenderObject] configured by this class will be configured to have - /// the [RenderObject] produced by the returned [Widget] in the provided - /// `slot`. - @protected - Widget? childForSlot(S slot); - - @override - SlottedContainerRenderObjectMixin createRenderObject(BuildContext context); - - @override - void updateRenderObject(BuildContext context, SlottedContainerRenderObjectMixin renderObject); - - @override - SlottedRenderObjectElement createElement() => SlottedRenderObjectElement(this); -} - -/// Mixin for a [RenderBox] configured by a [SlottedMultiChildRenderObjectWidgetMixin]. -/// -/// The [RenderBox] child currently occupying a given slot can be obtained by -/// calling [childForSlot]. -/// -/// Implementers may consider overriding [children] to return the children -/// of this render object in a consistent order (e.g. hit test order). -/// -/// The type parameter `S` is the type for the slots to be used by this -/// [RenderObject] and the [SlottedMultiChildRenderObjectWidgetMixin] it was -/// configured by. In the typical case, `S` is an [Enum] type. -/// -/// See [SlottedMultiChildRenderObjectWidgetMixin] for example code showcasing -/// how this mixin is used in combination with the -/// [SlottedMultiChildRenderObjectWidgetMixin]. -/// -/// See also: -/// -/// * [ContainerRenderObjectMixin], which organizes its children in a single -/// list. -mixin SlottedContainerRenderObjectMixin on RenderBox { - /// Returns the [RenderBox] child that is currently occupying the provided - /// `slot`. - /// - /// Returns null if no [RenderBox] is configured for the given slot. - @protected - RenderBox? childForSlot(S slot) => _slotToChild[slot]; - - /// Returns an [Iterable] of all non-null children. - /// - /// This getter is used by the default implementation of [attach], [detach], - /// [redepthChildren], [visitChildren], and [debugDescribeChildren] to iterate - /// over the children of this [RenderBox]. The base implementation makes no - /// guarantee about the order in which the children are returned. Subclasses, - /// for which the child order is important should override this getter and - /// return the children in the desired order. - @protected - Iterable get children => _slotToChild.values; - - /// Returns the debug name for a given `slot`. - /// - /// This method is called by [debugDescribeChildren] for each slot that is - /// currently occupied by a child to obtain a name for that slot for debug - /// outputs. - /// - /// The default implementation calls [EnumName.name] on `slot` it it is an - /// [Enum] value and `toString` if it is not. - @protected - String debugNameForSlot(S slot) { - if (slot is Enum) { - return slot.name; - } - return slot.toString(); - } - - @override - void attach(PipelineOwner owner) { - super.attach(owner); - for (final RenderBox child in children) { - child.attach(owner); - } - } - - @override - void detach() { - super.detach(); - for (final RenderBox child in children) { - child.detach(); - } - } - - @override - void redepthChildren() { - children.forEach(redepthChild); - } - - @override - void visitChildren(RenderObjectVisitor visitor) { - children.forEach(visitor); - } - - @override - List debugDescribeChildren() { - final List value = []; - final Map childToSlot = Map.fromIterables( - _slotToChild.values, - _slotToChild.keys, - ); - for (final RenderBox child in children) { - _addDiagnostics(child, value, debugNameForSlot(childToSlot[child] as S)); - } - return value; - } - - void _addDiagnostics(RenderBox child, List value, String name) { - value.add(child.toDiagnosticsNode(name: name)); - } - - final Map _slotToChild = {}; - - void _setChild(RenderBox? child, S slot) { - final RenderBox? oldChild = _slotToChild[slot]; - if (oldChild != null) { - dropChild(oldChild); - _slotToChild.remove(slot); - } - if (child != null) { - _slotToChild[slot] = child; - adoptChild(child); - } - } -} - -/// Element used by the [SlottedMultiChildRenderObjectWidgetMixin]. -class SlottedRenderObjectElement extends RenderObjectElement { - /// Creates an element that uses the given widget as its configuration. - SlottedRenderObjectElement(SlottedMultiChildRenderObjectWidgetMixin widget) : super(widget); - - final Map _slotToChild = {}; - - @override - SlottedMultiChildRenderObjectWidgetMixin get widget => super.widget as SlottedMultiChildRenderObjectWidgetMixin; - - @override - SlottedContainerRenderObjectMixin get renderObject => super.renderObject as SlottedContainerRenderObjectMixin; - - @override - void visitChildren(ElementVisitor visitor) { - _slotToChild.values.forEach(visitor); - } - - @override - void forgetChild(Element child) { - assert(_slotToChild.containsValue(child)); - assert(child.slot is S); - assert(_slotToChild.containsKey(child.slot)); - _slotToChild.remove(child.slot); - super.forgetChild(child); - } - - @override - void mount(Element? parent, Object? newSlot) { - super.mount(parent, newSlot); - _updateChildren(); - } - - @override - void update(SlottedMultiChildRenderObjectWidgetMixin newWidget) { - super.update(newWidget); - assert(widget == newWidget); - _updateChildren(); - } - - List? _debugPreviousSlots; - - void _updateChildren() { - assert(() { - _debugPreviousSlots ??= widget.slots.toList(); - return listEquals(_debugPreviousSlots, widget.slots.toList()); - }(), '${widget.runtimeType}.slots must not change.'); - assert(widget.slots.toSet().length == widget.slots.length, 'slots must be unique'); - - for (final S slot in widget.slots) { - _updateChild(widget.childForSlot(slot), slot); - } - } - - void _updateChild(Widget? widget, S slot) { - final Element? oldChild = _slotToChild[slot]; - assert(oldChild == null || oldChild.slot == slot); // Reason why [moveRenderObjectChild] is not reachable. - final Element? newChild = updateChild(oldChild, widget, slot); - if (oldChild != null) { - _slotToChild.remove(slot); - } - if (newChild != null) { - _slotToChild[slot] = newChild; - } - } - - @override - void insertRenderObjectChild(RenderBox child, S slot) { - renderObject._setChild(child, slot); - assert(renderObject._slotToChild[slot] == child); - } - - @override - void removeRenderObjectChild(RenderBox child, S slot) { - assert(renderObject._slotToChild[slot] == child); - renderObject._setChild(null, slot); - assert(renderObject._slotToChild[slot] == null); - } - - @override - void moveRenderObjectChild(RenderBox child, Object? oldSlot, Object? newSlot) { - // Existing elements are never moved to a new slot, see assert in [_updateChild]. - assert(false, 'not reachable'); - } -} diff --git a/packages/flutter/lib/src/widgets/text.dart b/packages/flutter/lib/src/widgets/text.dart index a22f4a178c524..6b3f20d22db6a 100644 --- a/packages/flutter/lib/src/widgets/text.dart +++ b/packages/flutter/lib/src/widgets/text.dart @@ -150,7 +150,7 @@ class DefaultTextStyle extends InheritedTheme { /// See [TextWidthBasis] for possible values and their implications. final TextWidthBasis textWidthBasis; - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} final ui.TextHeightBehavior? textHeightBehavior; /// The closest instance of this class that encloses the given context. @@ -241,7 +241,7 @@ class DefaultTextHeightBehavior extends InheritedTheme { assert(child != null), super(key: key, child: child); - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} final TextHeightBehavior textHeightBehavior; /// The closest instance of this class that encloses the given context. @@ -513,7 +513,7 @@ class Text extends StatelessWidget { /// {@macro flutter.painting.textPainter.textWidthBasis} final TextWidthBasis? textWidthBasis; - /// {@macro dart.ui.textHeightBehavior} + /// {@macro flutter.dart:ui.textHeightBehavior} final ui.TextHeightBehavior? textHeightBehavior; @override diff --git a/packages/flutter/lib/src/widgets/text_editing_action.dart b/packages/flutter/lib/src/widgets/text_editing_action.dart new file mode 100644 index 0000000000000..b0340e43d3615 --- /dev/null +++ b/packages/flutter/lib/src/widgets/text_editing_action.dart @@ -0,0 +1,48 @@ +// 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 'actions.dart'; +import 'focus_manager.dart'; +import 'framework.dart'; +import 'text_editing_action_target.dart'; + +/// An [Action] related to editing text. +/// +/// Enables itself only when a [TextEditingActionTarget], e.g. [EditableText], +/// is currently focused. The result of this is that when a +/// TextEditingActionTarget is not focused, it will fall through to any +/// non-TextEditingAction that handles the same shortcut. For example, +/// overriding the tab key in [Shortcuts] with a TextEditingAction will only +/// invoke your TextEditingAction when a TextEditingActionTarget is focused, +/// otherwise the default tab behavior will apply. +/// +/// The currently focused TextEditingActionTarget is available in the [invoke] +/// method via [textEditingActionTarget]. +/// +/// See also: +/// +/// * [CallbackAction], which is a similar Action type but unrelated to text +/// editing. +abstract class TextEditingAction extends ContextAction { + /// Returns the currently focused [TextEditingAction], or null if none is + /// focused. + @protected + TextEditingActionTarget? get textEditingActionTarget { + // If a TextEditingActionTarget is not focused, then ignore this action. + if (primaryFocus?.context == null || + primaryFocus!.context! is! StatefulElement || + ((primaryFocus!.context! as StatefulElement).state + is! TextEditingActionTarget)) { + return null; + } + return (primaryFocus!.context! as StatefulElement).state + as TextEditingActionTarget; + } + + @override + bool isEnabled(T intent) { + // The Action is disabled if there is no focused TextEditingActionTarget. + return textEditingActionTarget != null; + } +} diff --git a/packages/flutter/lib/src/widgets/text_editing_action_target.dart b/packages/flutter/lib/src/widgets/text_editing_action_target.dart new file mode 100644 index 0000000000000..e08f959b86e4e --- /dev/null +++ b/packages/flutter/lib/src/widgets/text_editing_action_target.dart @@ -0,0 +1,1572 @@ +// 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:math' as math; +import 'dart:ui' show TextAffinity, TextPosition; + +import 'package:characters/characters.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart' + show Clipboard, ClipboardData, TextLayoutMetrics, TextRange; + +import 'editable_text.dart'; + +/// The recipient of a [TextEditingAction]. +/// +/// TextEditingActions will only be enabled when an implementer of this class is +/// focused. +/// +/// See also: +/// +/// * [EditableTextState], which implements this and is the most typical +/// target of a TextEditingAction. +abstract class TextEditingActionTarget { + /// Whether the characters in the field are obscured from the user. + /// + /// When true, the entire contents of the field are treated as one word. + bool get obscureText; + + /// Whether the field currently in a read-only state. + /// + /// When true, [textEditingValue]'s text may not be modified, but its selection can be. + bool get readOnly; + + /// Whether the [textEditingValue]'s selection can be modified. + bool get selectionEnabled; + + /// Provides information about the text that is the target of this action. + /// + /// See also: + /// + /// * [EditableTextState.renderEditable], which overrides this. + TextLayoutMetrics get textLayoutMetrics; + + /// The [TextEditingValue] expressed in this field. + TextEditingValue get textEditingValue; + + // Holds the last cursor location the user selected in the case the user tries + // to select vertically past the end or beginning of the field. If they do, + // then we need to keep the old cursor location so that we can go back to it + // if they change their minds. Only used for moving selection up and down in a + // multiline text field when selecting using the keyboard. + int _cursorResetLocation = -1; + + // Whether we should reset the location of the cursor in the case the user + // tries to select vertically past the end or beginning of the field. If they + // do, then we need to keep the old cursor location so that we can go back to + // it if they change their minds. Only used for resetting selection up and + // down in a multiline text field when selecting using the keyboard. + bool _wasSelectingVerticallyWithKeyboard = false; + + /// Called when assuming that the text layout is in sync with + /// [textEditingValue]. + /// + /// Can be overridden to assert that this is a valid assumption. + void debugAssertLayoutUpToDate(); + + /// Returns the index into the string of the next character boundary after the + /// given index. + /// + /// The character boundary is determined by the characters package, so + /// surrogate pairs and extended grapheme clusters are considered. + /// + /// The index must be between 0 and string.length, inclusive. If given + /// string.length, string.length is returned. + /// + /// Setting includeWhitespace to false will only return the index of non-space + /// characters. + @visibleForTesting + static int nextCharacter(int index, String string, [bool includeWhitespace = true]) { + assert(index >= 0 && index <= string.length); + if (index == string.length) { + return string.length; + } + + final CharacterRange range = CharacterRange.at(string, 0, index); + // If index is not on a character boundary, return the next character + // boundary. + if (range.current.length != index) { + return range.current.length; + } + + range.expandNext(); + if (!includeWhitespace) { + range.expandWhile((String character) { + return TextLayoutMetrics.isWhitespace(character.codeUnitAt(0)); + }); + } + return range.current.length; + } + + /// Returns the index into the string of the previous character boundary + /// before the given index. + /// + /// The character boundary is determined by the characters package, so + /// surrogate pairs and extended grapheme clusters are considered. + /// + /// The index must be between 0 and string.length, inclusive. If index is 0, + /// 0 will be returned. + /// + /// Setting includeWhitespace to false will only return the index of non-space + /// characters. + @visibleForTesting + static int previousCharacter(int index, String string, [bool includeWhitespace = true]) { + assert(index >= 0 && index <= string.length); + if (index == 0) { + return 0; + } + + final CharacterRange range = CharacterRange.at(string, 0, index); + // If index is not on a character boundary, return the previous character + // boundary. + if (range.current.length != index) { + range.dropLast(); + return range.current.length; + } + + range.dropLast(); + if (!includeWhitespace) { + while (range.currentCharacters.isNotEmpty + && TextLayoutMetrics.isWhitespace(range.charactersAfter.first.codeUnitAt(0))) { + range.dropLast(); + } + } + return range.current.length; + } + + /// {@template flutter.widgets.TextEditingActionTarget.setSelection} + /// Called to update the [TextSelection] in the current [TextEditingValue]. + /// {@endtemplate} + void setSelection(TextSelection nextSelection, SelectionChangedCause cause) { + if (nextSelection == textEditingValue.selection) { + return; + } + setTextEditingValue( + textEditingValue.copyWith(selection: nextSelection), + cause, + ); + } + + /// {@template flutter.widgets.TextEditingActionTarget.setTextEditingValue} + /// Called to update the current [TextEditingValue]. + /// {@endtemplate} + void setTextEditingValue(TextEditingValue newValue, SelectionChangedCause cause); + + // Extend the current selection to the end of the field. + // + // If selectionEnabled is false, keeps the selection collapsed and moves it to + // the end. + // + // See also: + // + // * _extendSelectionToStart + void _extendSelectionToEnd(SelectionChangedCause cause) { + if (textEditingValue.selection.extentOffset == textEditingValue.text.length) { + return; + } + + final TextSelection nextSelection = textEditingValue.selection.copyWith( + extentOffset: textEditingValue.text.length, + ); + return setSelection(nextSelection, cause); + } + + // Extend the current selection to the start of the field. + // + // If selectionEnabled is false, keeps the selection collapsed and moves it to + // the start. + // + // The given [SelectionChangedCause] indicates the cause of this change and + // will be passed to [setSelection]. + // + // See also: + // + // * _extendSelectionToEnd + void _extendSelectionToStart(SelectionChangedCause cause) { + if (!selectionEnabled) { + return moveSelectionToStart(cause); + } + + setSelection(textEditingValue.selection.extendTo(const TextPosition( + offset: 0, + affinity: TextAffinity.upstream, + )), cause); + } + + // Return the offset at the start of the nearest word to the left of the + // given offset. + int _getLeftByWord(int offset, [bool includeWhitespace = true]) { + // If the offset is already all the way left, there is nothing to do. + if (offset <= 0) { + return offset; + } + + // If we can just return the start of the text without checking for a word. + if (offset == 1) { + return 0; + } + + final int startPoint = previousCharacter( + offset, textEditingValue.text, includeWhitespace); + final TextRange word = + textLayoutMetrics.getWordBoundary(TextPosition(offset: startPoint, affinity: textEditingValue.selection.affinity)); + return word.start; + } + + /// Return the offset at the end of the nearest word to the right of the given + /// offset. + int _getRightByWord(int offset, [bool includeWhitespace = true]) { + // If the selection is already all the way right, there is nothing to do. + if (offset == textEditingValue.text.length) { + return offset; + } + + // If we can just return the end of the text without checking for a word. + if (offset == textEditingValue.text.length - 1 || offset == textEditingValue.text.length) { + return textEditingValue.text.length; + } + + final int startPoint = includeWhitespace || + !TextLayoutMetrics.isWhitespace(textEditingValue.text.codeUnitAt(offset)) + ? offset + : nextCharacter(offset, textEditingValue.text, includeWhitespace); + final TextRange nextWord = + textLayoutMetrics.getWordBoundary(TextPosition(offset: startPoint, affinity: textEditingValue.selection.affinity)); + return nextWord.end; + } + + // Deletes the current non-empty selection. + // + // If the selection is currently non-empty, this method deletes the selected + // text. Otherwise this method does nothing. + TextEditingValue _deleteNonEmptySelection() { + assert(textEditingValue.selection.isValid); + assert(!textEditingValue.selection.isCollapsed); + + final String textBefore = textEditingValue.selection.textBefore(textEditingValue.text); + final String textAfter = textEditingValue.selection.textAfter(textEditingValue.text); + final TextSelection newSelection = TextSelection.collapsed( + offset: textEditingValue.selection.start, + affinity: textEditingValue.selection.affinity, + ); + final TextRange newComposingRange = !textEditingValue.composing.isValid || textEditingValue.composing.isCollapsed + ? TextRange.empty + : TextRange( + start: textEditingValue.composing.start - (textEditingValue.composing.start - textEditingValue.selection.start).clamp(0, textEditingValue.selection.end - textEditingValue.selection.start), + end: textEditingValue.composing.end - (textEditingValue.composing.end - textEditingValue.selection.start).clamp(0, textEditingValue.selection.end - textEditingValue.selection.start), + ); + + return TextEditingValue( + text: textBefore + textAfter, + selection: newSelection, + composing: newComposingRange, + ); + } + + /// Returns a new TextEditingValue representing a deletion from the current + /// [selection] to the given index, inclusively. + /// + /// If the selection is not collapsed, deletes the selection regardless of the + /// given index. + /// + /// The composing region, if any, will also be adjusted to remove the deleted + /// characters. + TextEditingValue _deleteTo(TextPosition position) { + assert(textEditingValue.selection != null); + + if (!textEditingValue.selection.isValid) { + return textEditingValue; + } + if (!textEditingValue.selection.isCollapsed) { + return _deleteNonEmptySelection(); + } + if (position.offset == textEditingValue.selection.extentOffset) { + return textEditingValue; + } + + final TextRange deletion = TextRange( + start: math.min(position.offset, textEditingValue.selection.extentOffset), + end: math.max(position.offset, textEditingValue.selection.extentOffset), + ); + final String deleted = deletion.textInside(textEditingValue.text); + if (deletion.textInside(textEditingValue.text).isEmpty) { + return textEditingValue; + } + + final int charactersDeletedBeforeComposingStart = + (textEditingValue.composing.start - deletion.start).clamp(0, deleted.length); + final int charactersDeletedBeforeComposingEnd = + (textEditingValue.composing.end - deletion.start).clamp(0, deleted.length); + final TextRange nextComposingRange = !textEditingValue.composing.isValid || textEditingValue.composing.isCollapsed + ? TextRange.empty + : TextRange( + start: textEditingValue.composing.start - charactersDeletedBeforeComposingStart, + end: textEditingValue.composing.end - charactersDeletedBeforeComposingEnd, + ); + + return TextEditingValue( + text: deletion.textBefore(textEditingValue.text) + deletion.textAfter(textEditingValue.text), + selection: TextSelection.collapsed( + offset: deletion.start, + affinity: position.affinity, + ), + composing: nextComposingRange, + ); + } + + /// Deletes backwards from the current selection. + /// + /// If the selection is collapsed, deletes a single character before the + /// cursor. + /// + /// If the selection is not collapsed, deletes the selection. + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// {@template flutter.widgets.TextEditingActionTarget.cause} + /// The given [SelectionChangedCause] indicates the cause of this change and + /// will be passed to [setSelection]. + /// {@endtemplate} + /// + /// See also: + /// + /// * [deleteForward], which is same but in the opposite direction. + void delete(SelectionChangedCause cause) { + if (readOnly) { + return; + } + if (!textEditingValue.selection.isValid) { + return; + } + + // `delete` does not depend on the text layout, and the boundary analysis is + // done using the `previousCharacter` method instead of ICU, we can keep + // deleting without having to layout the text. For this reason, we can + // directly delete the character before the caret in the controller. + final String textBefore = textEditingValue.selection.textBefore(textEditingValue.text); + final int characterBoundary = previousCharacter( + textBefore.length, + textBefore, + ); + final TextPosition position = TextPosition(offset: characterBoundary); + setTextEditingValue(_deleteTo(position), cause); + } + + /// Deletes a word backwards from the current selection. + /// + /// If the selection is collapsed, deletes a word before the cursor. + /// + /// If the selection is not collapsed, deletes the selection. + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// If [obscureText] is true, it treats the whole text content as a single + /// word. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// {@template flutter.widgets.TextEditingActionTarget.whiteSpace} + /// By default, includeWhitespace is set to true, meaning that whitespace can + /// be considered a word in itself. If set to false, the selection will be + /// extended past any whitespace and the first word following the whitespace. + /// {@endtemplate} + /// + /// See also: + /// + /// * [deleteForwardByWord], which is same but in the opposite direction. + void deleteByWord(SelectionChangedCause cause, + [bool includeWhitespace = true]) { + if (readOnly) { + return; + } + if (!textEditingValue.selection.isValid) { + return; + } + + if (obscureText) { + // When the text is obscured, the whole thing is treated as one big line. + return deleteToStart(cause); + } + + final String textBefore = textEditingValue.selection.textBefore(textEditingValue.text); + final int characterBoundary = + _getLeftByWord(textBefore.length, includeWhitespace); + final TextEditingValue nextValue = _deleteTo(TextPosition(offset: characterBoundary)); + + setTextEditingValue(nextValue, cause); + } + + /// Deletes a line backwards from the current selection. + /// + /// If the selection is collapsed, deletes a line before the cursor. + /// + /// If the selection is not collapsed, deletes the selection. + /// + /// If [obscureText] is true, it treats the whole text content as + /// a single word. + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [deleteForwardByLine], which is same but in the opposite direction. + void deleteByLine(SelectionChangedCause cause) { + if (readOnly) { + return; + } + if (!textEditingValue.selection.isValid) { + return; + } + + // When there is a line break, line delete shouldn't do anything + final String textBefore = textEditingValue.selection.textBefore(textEditingValue.text); + final bool isPreviousCharacterBreakLine = + textBefore.codeUnitAt(textBefore.length - 1) == 0x0A; + if (isPreviousCharacterBreakLine) { + return; + } + + // When the text is obscured, the whole thing is treated as one big line. + if (obscureText) { + return deleteToStart(cause); + } + + final TextSelection line = textLayoutMetrics.getLineAtOffset( + TextPosition(offset: textBefore.length - 1), + ); + + setTextEditingValue(_deleteTo(TextPosition(offset: line.start)), cause); + } + + /// Deletes in the forward direction. + /// + /// If the selection is collapsed, deletes a single character after the + /// cursor. + /// + /// If the selection is not collapsed, deletes the selection. + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [delete], which is the same but in the opposite direction. + void deleteForward(SelectionChangedCause cause) { + if (readOnly) { + return; + } + if (!textEditingValue.selection.isValid) { + return; + } + + final String textAfter = textEditingValue.selection.textAfter(textEditingValue.text); + final int characterBoundary = nextCharacter(0, textAfter); + setTextEditingValue(_deleteTo(TextPosition(offset: textEditingValue.selection.end + characterBoundary)), cause); + } + + /// Deletes a word in the forward direction from the current selection. + /// + /// If the selection is collapsed, deletes a word after the cursor. + /// + /// If the selection is not collapsed, deletes the selection. + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// If [obscureText] is true, it treats the whole text content as + /// a single word. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// {@macro flutter.widgets.TextEditingActionTarget.whiteSpace} + /// + /// See also: + /// + /// * [deleteByWord], which is same but in the opposite direction. + void deleteForwardByWord(SelectionChangedCause cause, + [bool includeWhitespace = true]) { + if (readOnly) { + return; + } + if (!textEditingValue.selection.isValid) { + return; + } + + if (obscureText) { + // When the text is obscured, the whole thing is treated as one big word. + return deleteToEnd(cause); + } + + final String textBefore = textEditingValue.selection.textBefore(textEditingValue.text); + final int characterBoundary = _getRightByWord(textBefore.length, includeWhitespace); + final TextEditingValue nextValue = _deleteTo(TextPosition(offset: characterBoundary)); + + setTextEditingValue(nextValue, cause); + } + + /// Deletes a line in the forward direction from the current selection. + /// + /// If the selection is collapsed, deletes a line after the cursor. + /// + /// If the selection is not collapsed, deletes the selection. + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// If [obscureText] is true, it treats the whole text content as + /// a single word. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [deleteByLine], which is same but in the opposite direction. + void deleteForwardByLine(SelectionChangedCause cause) { + if (readOnly) { + return; + } + if (!textEditingValue.selection.isValid) { + return; + } + + if (obscureText) { + // When the text is obscured, the whole thing is treated as one big line. + return deleteToEnd(cause); + } + + + // When there is a line break, it shouldn't do anything. + final String textAfter = textEditingValue.selection.textAfter(textEditingValue.text); + final bool isNextCharacterBreakLine = textAfter.codeUnitAt(0) == 0x0A; + if (isNextCharacterBreakLine) { + return; + } + + final String textBefore = textEditingValue.selection.textBefore(textEditingValue.text); + final TextSelection line = textLayoutMetrics.getLineAtOffset( + TextPosition(offset: textBefore.length), + ); + + setTextEditingValue(_deleteTo(TextPosition(offset: line.end)), cause); + } + + /// Deletes the from the current collapsed selection to the end of the field. + /// + /// The given SelectionChangedCause indicates the cause of this change and + /// will be passed to setSelection. + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// See also: + /// * [deleteToStart] + void deleteToEnd(SelectionChangedCause cause) { + assert(textEditingValue.selection.isCollapsed); + if (readOnly) { + return; + } + if (!textEditingValue.selection.isValid) { + return; + } + + setTextEditingValue(_deleteTo(TextPosition(offset: textEditingValue.text.length)), cause); + } + + /// Deletes the from the current collapsed selection to the start of the field. + /// + /// The given SelectionChangedCause indicates the cause of this change and + /// will be passed to setSelection. + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// See also: + /// * [deleteToEnd] + void deleteToStart(SelectionChangedCause cause) { + assert(textEditingValue.selection.isCollapsed); + if (readOnly) { + return; + } + if (!textEditingValue.selection.isValid) { + return; + } + + setTextEditingValue(_deleteTo(const TextPosition(offset: 0)), cause); + } + + /// Expand the current selection to the end of the field. + /// + /// The selection will never shrink. The [TextSelection.extentOffset] will + // always be at the end of the field, regardless of the original order of + /// [TextSelection.baseOffset] and [TextSelection.extentOffset]. + /// + /// If [selectionEnabled] is false, keeps the selection collapsed and moves it + /// to the end. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [expandSelectionToStart], which is same but in the opposite direction. + void expandSelectionToEnd(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionToEnd(cause); + } + + final TextPosition nextPosition = TextPosition( + offset: textEditingValue.text.length, + ); + setSelection(textEditingValue.selection.expandTo(nextPosition, true), cause); + } + + /// Expand the current selection to the start of the field. + /// + /// The selection will never shrink. The [TextSelection.extentOffset] will + /// always be at the start of the field, regardless of the original order of + /// [TextSelection.baseOffset] and [TextSelection.extentOffset]. + /// + /// If [selectionEnabled] is false, keeps the selection collapsed and moves it + /// to the start. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [expandSelectionToEnd], which is the same but in the opposite + /// direction. + void expandSelectionToStart(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionToStart(cause); + } + + const TextPosition nextPosition = TextPosition( + offset: 0, + affinity: TextAffinity.upstream, + ); + setSelection(textEditingValue.selection.expandTo(nextPosition, true), cause); + } + + /// Expand the current selection to the smallest selection that includes the + /// start of the line. + /// + /// The selection will never shrink. The upper offset will be expanded to the + /// beginning of its line, and the original order of baseOffset and + /// [TextSelection.extentOffset] will be preserved. + /// + /// If [selectionEnabled] is false, keeps the selection collapsed and moves it + /// left by line. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [expandSelectionRightByLine], which is the same but in the opposite + /// direction. + void expandSelectionLeftByLine(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionLeftByLine(cause); + } + + // If the lowest edge of the selection is at the start of a line, don't do + // anything. + // TODO(justinmc): Support selection with multiple TextAffinities. + // https://github.com/flutter/flutter/issues/88135 + final TextSelection currentLine = textLayoutMetrics.getLineAtOffset( + TextPosition( + offset: textEditingValue.selection.start, + affinity: textEditingValue.selection.isCollapsed + ? textEditingValue.selection.affinity + : TextAffinity.downstream, + ), + ); + if (currentLine.baseOffset == textEditingValue.selection.start) { + return; + } + + setSelection(textEditingValue.selection.expandTo(TextPosition( + offset: currentLine.baseOffset, + affinity: textEditingValue.selection.affinity, + )), cause); + } + + /// Expand the current selection to the smallest selection that includes the + /// end of the line. + /// + /// The selection will never shrink. The lower offset will be expanded to the + /// end of its line and the original order of [TextSelection.baseOffset] and + /// [TextSelection.extentOffset] will be preserved. + /// + /// If [selectionEnabled] is false, keeps the selection collapsed and moves it + /// right by line. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [expandSelectionLeftByLine], which is the same but in the opposite + /// direction. + void expandSelectionRightByLine(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionRightByLine(cause); + } + + // If greatest edge is already at the end of a line, don't do anything. + // TODO(justinmc): Support selection with multiple TextAffinities. + // https://github.com/flutter/flutter/issues/88135 + final TextSelection currentLine = textLayoutMetrics.getLineAtOffset( + TextPosition( + offset: textEditingValue.selection.end, + affinity: textEditingValue.selection.isCollapsed + ? textEditingValue.selection.affinity + : TextAffinity.upstream, + ), + ); + if (currentLine.extentOffset == textEditingValue.selection.end) { + return; + } + + final TextSelection nextSelection = textEditingValue.selection.expandTo( + TextPosition( + offset: currentLine.extentOffset, + affinity: TextAffinity.upstream, + ), + ); + setSelection(nextSelection, cause); + } + + /// Keeping selection's [TextSelection.baseOffset] fixed, move the + /// [TextSelection.extentOffset] down by one line. + /// + /// If selectionEnabled is false, keeps the selection collapsed and just + /// moves it down. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [extendSelectionUp], which is same but in the opposite direction. + void extendSelectionDown(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionDown(cause); + } + + // If the selection is collapsed at the end of the field already, then + // nothing happens. + if (textEditingValue.selection.isCollapsed && + textEditingValue.selection.extentOffset >= textEditingValue.text.length) { + return; + } + + int index = + textLayoutMetrics.getTextPositionBelow(textEditingValue.selection.extent).offset; + + if (index == textEditingValue.selection.extentOffset) { + index = textEditingValue.text.length; + _wasSelectingVerticallyWithKeyboard = true; + } else if (_wasSelectingVerticallyWithKeyboard) { + index = _cursorResetLocation; + _wasSelectingVerticallyWithKeyboard = false; + } else { + _cursorResetLocation = index; + } + + final TextPosition nextPosition = TextPosition( + offset: index, + affinity: textEditingValue.selection.affinity, + ); + setSelection(textEditingValue.selection.extendTo(nextPosition), cause); + } + + /// If [selectionEnabled] is false, keeps the selection collapsed and moves it + /// left. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [extendSelectionRight], which is same but in the opposite direction. + void extendSelectionLeft(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionLeft(cause); + } + + // If the selection is already all the way left, there is nothing to do. + if (textEditingValue.selection.extentOffset <= 0) { + return; + } + + final int previousExtent = previousCharacter( + textEditingValue.selection.extentOffset, + textEditingValue.text, + ); + + final int distance = textEditingValue.selection.extentOffset - previousExtent; + _cursorResetLocation -= distance; + setSelection(textEditingValue.selection.extendTo(TextPosition(offset: previousExtent, affinity: textEditingValue.selection.affinity)), cause); + } + + /// Extend the current selection to the start of + /// [TextSelection.extentOffset]'s line. + /// + /// Uses [TextSelection.baseOffset] as a pivot point and doesn't change it. + /// If [TextSelection.extentOffset] is right of [TextSelection.baseOffset], + /// then the selection will be collapsed. + /// + /// If [selectionEnabled] is false, keeps the selection collapsed and moves it + /// left by line. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [extendSelectionRightByLine], which is same but in the opposite + /// direction. + /// * [expandSelectionRightByLine], which strictly grows the selection + /// regardless of the order. + void extendSelectionLeftByLine(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionLeftByLine(cause); + } + + // When going left, we want to skip over any whitespace before the line, + // so we go back to the first non-whitespace before asking for the line + // bounds, since getLineAtOffset finds the line boundaries without + // including whitespace (like the newline). + final int startPoint = previousCharacter( + textEditingValue.selection.extentOffset, textEditingValue.text, false); + final TextSelection selectedLine = textLayoutMetrics.getLineAtOffset( + TextPosition(offset: startPoint), + ); + + late final TextSelection nextSelection; + // If the extent and base offsets would reverse order, then instead the + // selection collapses. + if (textEditingValue.selection.extentOffset > textEditingValue.selection.baseOffset) { + nextSelection = textEditingValue.selection.copyWith( + extentOffset: textEditingValue.selection.baseOffset, + ); + } else { + nextSelection = textEditingValue.selection.extendTo(TextPosition( + offset: selectedLine.baseOffset, + )); + } + + setSelection(nextSelection, cause); + } + + /// Keeping selection's [TextSelection.baseOffset] fixed, move the + /// [TextSelection.extentOffset] right. + /// + /// If [selectionEnabled] is false, keeps the selection collapsed and moves it + /// right. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [extendSelectionLeft], which is same but in the opposite direction. + void extendSelectionRight(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionRight(cause); + } + + // If the selection is already all the way right, there is nothing to do. + if (textEditingValue.selection.extentOffset >= textEditingValue.text.length) { + return; + } + final int nextExtent = nextCharacter( + textEditingValue.selection.extentOffset, textEditingValue.text); + + final int distance = nextExtent - textEditingValue.selection.extentOffset; + _cursorResetLocation += distance; + setSelection(textEditingValue.selection.extendTo(TextPosition(offset: nextExtent, affinity: textEditingValue.selection.affinity)), cause); + } + + /// Extend the current selection to the end of [TextSelection.extentOffset]'s + /// line. + /// + /// Uses [TextSelection.baseOffset] as a pivot point and doesn't change it. If + /// [TextSelection.extentOffset] is left of [TextSelection.baseOffset], then + /// collapses the selection. + /// + /// If [selectionEnabled] is false, keeps the selection collapsed and moves it + /// right by line. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [extendSelectionLeftByLine], which is same but in the opposite + /// direction. + /// * [expandSelectionRightByLine], which strictly grows the selection + /// regardless of the order. + void extendSelectionRightByLine(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionRightByLine(cause); + } + + final int startPoint = nextCharacter( + textEditingValue.selection.extentOffset, textEditingValue.text, false); + final TextSelection selectedLine = textLayoutMetrics.getLineAtOffset( + TextPosition(offset: startPoint), + ); + + // If the extent and base offsets would reverse order, then instead the + // selection collapses. + late final TextSelection nextSelection; + if (textEditingValue.selection.extentOffset < textEditingValue.selection.baseOffset) { + nextSelection = textEditingValue.selection.copyWith( + extentOffset: textEditingValue.selection.baseOffset, + ); + } else { + nextSelection = textEditingValue.selection.extendTo(TextPosition( + offset: selectedLine.extentOffset, + affinity: TextAffinity.upstream, + )); + } + + setSelection(nextSelection, cause); + } + + /// Extend the current selection to the previous start of a word. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// {@macro flutter.widgets.TextEditingActionTarget.whiteSpace} + /// + /// {@template flutter.widgets.TextEditingActionTarget.stopAtReversal} + /// The `stopAtReversal` parameter is false by default, meaning that it's + /// ok for the base and extent to flip their order here. If set to true, then + /// the selection will collapse when it would otherwise reverse its order. A + /// selection that is already collapsed is not affected by this parameter. + /// {@endtemplate} + /// + /// See also: + /// + /// * [extendSelectionRightByWord], which is the same but in the opposite + /// direction. + void extendSelectionLeftByWord(SelectionChangedCause cause, + [bool includeWhitespace = true, bool stopAtReversal = false]) { + if (!textEditingValue.selection.isValid) { + return; + } + // When the text is obscured, the whole thing is treated as one big word. + if (obscureText) { + return _extendSelectionToStart(cause); + } + + debugAssertLayoutUpToDate(); + // If the selection is already all the way left, there is nothing to do. + if (textEditingValue.selection.isCollapsed && textEditingValue.selection.extentOffset <= 0) { + return; + } + + final int leftOffset = + _getLeftByWord(textEditingValue.selection.extentOffset, includeWhitespace); + + late final TextSelection nextSelection; + if (stopAtReversal && + textEditingValue.selection.extentOffset > textEditingValue.selection.baseOffset && + leftOffset < textEditingValue.selection.baseOffset) { + nextSelection = textEditingValue.selection.extendTo(TextPosition(offset: textEditingValue.selection.baseOffset)); + } else { + nextSelection = textEditingValue.selection.extendTo(TextPosition(offset: leftOffset, affinity: textEditingValue.selection.affinity)); + } + + if (nextSelection == textEditingValue.selection) { + return; + } + setSelection(nextSelection, cause); + } + + /// Extend the current selection to the next end of a word. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// {@macro flutter.widgets.TextEditingActionTarget.whiteSpace} + /// + /// {@macro flutter.widgets.TextEditingActionTarget.stopAtReversal} + /// + /// See also: + /// + /// * [extendSelectionLeftByWord], which is the same but in the opposite + /// direction. + void extendSelectionRightByWord(SelectionChangedCause cause, + [bool includeWhitespace = true, bool stopAtReversal = false]) { + if (!textEditingValue.selection.isValid) { + return; + } + debugAssertLayoutUpToDate(); + // When the text is obscured, the whole thing is treated as one big word. + if (obscureText) { + return _extendSelectionToEnd(cause); + } + + // If the selection is already all the way right, there is nothing to do. + if (textEditingValue.selection.isCollapsed && + textEditingValue.selection.extentOffset == textEditingValue.text.length) { + return; + } + + final int rightOffset = + _getRightByWord(textEditingValue.selection.extentOffset, includeWhitespace); + + late final TextSelection nextSelection; + if (stopAtReversal && + textEditingValue.selection.baseOffset > textEditingValue.selection.extentOffset && + rightOffset > textEditingValue.selection.baseOffset) { + nextSelection = TextSelection.fromPosition( + TextPosition(offset: textEditingValue.selection.baseOffset), + ); + } else { + nextSelection = textEditingValue.selection.extendTo(TextPosition(offset: rightOffset, affinity: textEditingValue.selection.affinity)); + } + + if (nextSelection == textEditingValue.selection) { + return; + } + setSelection(nextSelection, cause); + } + + /// Keeping selection's [TextSelection.baseOffset] fixed, move the + /// [TextSelection.extentOffset] up by one + /// line. + /// + /// If [selectionEnabled] is false, keeps the selection collapsed and moves it + /// up. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [extendSelectionDown], which is the same but in the opposite + /// direction. + void extendSelectionUp(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + if (!selectionEnabled) { + return moveSelectionUp(cause); + } + + // If the selection is collapsed at the beginning of the field already, then + // nothing happens. + if (textEditingValue.selection.isCollapsed && textEditingValue.selection.extentOffset <= 0.0) { + return; + } + + final TextPosition positionAbove = + textLayoutMetrics.getTextPositionAbove(textEditingValue.selection.extent); + late final TextSelection nextSelection; + if (positionAbove.offset == textEditingValue.selection.extentOffset) { + nextSelection = textEditingValue.selection.copyWith( + extentOffset: 0, + affinity: TextAffinity.upstream, + ); + _wasSelectingVerticallyWithKeyboard = true; + } else if (_wasSelectingVerticallyWithKeyboard) { + nextSelection = textEditingValue.selection.copyWith( + baseOffset: textEditingValue.selection.baseOffset, + extentOffset: _cursorResetLocation, + ); + _wasSelectingVerticallyWithKeyboard = false; + } else { + nextSelection = textEditingValue.selection.copyWith( + baseOffset: textEditingValue.selection.baseOffset, + extentOffset: positionAbove.offset, + affinity: positionAbove.affinity, + ); + _cursorResetLocation = nextSelection.extentOffset; + } + + setSelection(nextSelection, cause); + } + + /// Move the current selection to the leftmost point of the current line. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [moveSelectionRightByLine], which is the same but in the opposite + /// direction. + void moveSelectionLeftByLine(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + // If already at the left edge of the line, do nothing. + final TextSelection currentLine = textLayoutMetrics.getLineAtOffset( + textEditingValue.selection.extent, + ); + if (currentLine.baseOffset == textEditingValue.selection.extentOffset) { + return; + } + + // When going left, we want to skip over any whitespace before the line, + // so we go back to the first non-whitespace before asking for the line + // bounds, since getLineAtOffset finds the line boundaries without + // including whitespace (like the newline). + final int startPoint = previousCharacter( + textEditingValue.selection.extentOffset, textEditingValue.text, false); + final TextSelection selectedLine = textLayoutMetrics.getLineAtOffset( + TextPosition(offset: startPoint), + ); + final TextSelection nextSelection = TextSelection.fromPosition(TextPosition( + offset: selectedLine.baseOffset, + )); + + setSelection(nextSelection, cause); + } + + /// Move the current selection to the next line. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [moveSelectionUp], which is the same but in the opposite direction. + void moveSelectionDown(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + // If the selection is collapsed at the end of the field already, then + // nothing happens. + if (textEditingValue.selection.isCollapsed && + textEditingValue.selection.extentOffset >= textEditingValue.text.length) { + return; + } + + final TextPosition positionBelow = + textLayoutMetrics.getTextPositionBelow(textEditingValue.selection.extent); + + late final TextSelection nextSelection; + if (positionBelow.offset == textEditingValue.selection.extentOffset) { + nextSelection = textEditingValue.selection.copyWith( + baseOffset: textEditingValue.text.length, + extentOffset: textEditingValue.text.length, + ); + } else { + nextSelection = TextSelection.fromPosition(positionBelow); + } + + if (textEditingValue.selection.extentOffset == textEditingValue.text.length) { + _wasSelectingVerticallyWithKeyboard = false; + } else { + _cursorResetLocation = nextSelection.extentOffset; + } + + setSelection(nextSelection, cause); + } + + /// Move the current selection left by one character. + /// + /// If it can't be moved left, do nothing. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [moveSelectionRight], which is the same but in the opposite direction. + void moveSelectionLeft(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + // If the selection is already all the way left, there is nothing to do. + if (textEditingValue.selection.isCollapsed && textEditingValue.selection.extentOffset <= 0) { + return; + } + + int previousExtent; + if (textEditingValue.selection.start != textEditingValue.selection.end) { + previousExtent = textEditingValue.selection.start; + } else { + previousExtent = previousCharacter( + textEditingValue.selection.extentOffset, textEditingValue.text); + } + final TextSelection nextSelection = TextSelection.fromPosition( + TextPosition( + offset: previousExtent, + affinity: textEditingValue.selection.affinity, + ), + ); + + if (nextSelection == textEditingValue.selection) { + return; + } + _cursorResetLocation -= + textEditingValue.selection.extentOffset - nextSelection.extentOffset; + setSelection(nextSelection, cause); + } + + /// Move the current selection to the previous start of a word. + /// + /// A TextSelection that isn't collapsed will be collapsed and moved from the + /// extentOffset. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// {@macro flutter.widgets.TextEditingActionTarget.whiteSpace} + /// + /// See also: + /// + /// * [moveSelectionRightByWord], which is the same but in the opposite + /// direction. + void moveSelectionLeftByWord(SelectionChangedCause cause, + [bool includeWhitespace = true]) { + if (!textEditingValue.selection.isValid) { + return; + } + // When the text is obscured, the whole thing is treated as one big word. + if (obscureText) { + return moveSelectionToStart(cause); + } + + debugAssertLayoutUpToDate(); + // If the selection is already all the way left, there is nothing to do. + if (textEditingValue.selection.isCollapsed && textEditingValue.selection.extentOffset <= 0) { + return; + } + + final int leftOffset = + _getLeftByWord(textEditingValue.selection.extentOffset, includeWhitespace); + final TextSelection nextSelection = TextSelection.fromPosition(TextPosition(offset: leftOffset, affinity: textEditingValue.selection.affinity)); + + if (nextSelection == textEditingValue.selection) { + return; + } + setSelection(nextSelection, cause); + } + + /// Move the current selection to the right by one character. + /// + /// If the selection is invalid or it can't be moved right, do nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [moveSelectionLeft], which is the same but in the opposite direction. + void moveSelectionRight(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + // If the selection is already all the way right, there is nothing to do. + if (textEditingValue.selection.isCollapsed && + textEditingValue.selection.extentOffset >= textEditingValue.text.length) { + return; + } + + int nextExtent; + if (textEditingValue.selection.start != textEditingValue.selection.end) { + nextExtent = textEditingValue.selection.end; + } else { + nextExtent = nextCharacter( + textEditingValue.selection.extentOffset, textEditingValue.text); + } + final TextSelection nextSelection = TextSelection.fromPosition(TextPosition( + offset: nextExtent, + )); + + if (nextSelection == textEditingValue.selection) { + return; + } + setSelection(nextSelection, cause); + } + + /// Move the current selection to the rightmost point of the current line. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [moveSelectionLeftByLine], which is the same but in the opposite + /// direction. + void moveSelectionRightByLine(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + // If already at the right edge of the line, do nothing. + final TextSelection currentLine = textLayoutMetrics.getLineAtOffset( + textEditingValue.selection.extent, + ); + if (currentLine.extentOffset == textEditingValue.selection.extentOffset) { + return; + } + + // When going right, we want to skip over any whitespace after the line, + // so we go forward to the first non-whitespace character before asking + // for the line bounds, since getLineAtOffset finds the line + // boundaries without including whitespace (like the newline). + final int startPoint = nextCharacter( + textEditingValue.selection.extentOffset, textEditingValue.text, false); + final TextSelection selectedLine = textLayoutMetrics.getLineAtOffset( + TextPosition( + offset: startPoint, + affinity: TextAffinity.upstream, + ), + ); + final TextSelection nextSelection = TextSelection.fromPosition(TextPosition( + offset: selectedLine.extentOffset, + affinity: TextAffinity.upstream, + )); + setSelection(nextSelection, cause); + } + + /// Move the current selection to the next end of a word. + /// + /// A TextSelection that isn't collapsed will be collapsed and moved from the + /// extentOffset. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// {@macro flutter.widgets.TextEditingActionTarget.whiteSpace} + /// + /// See also: + /// + /// * [moveSelectionLeftByWord], which is the same but in the opposite + /// direction. + void moveSelectionRightByWord(SelectionChangedCause cause, + [bool includeWhitespace = true]) { + if (!textEditingValue.selection.isValid) { + return; + } + // When the text is obscured, the whole thing is treated as one big word. + if (obscureText) { + return moveSelectionToEnd(cause); + } + + debugAssertLayoutUpToDate(); + // If the selection is already all the way right, there is nothing to do. + if (textEditingValue.selection.isCollapsed && + textEditingValue.selection.extentOffset == textEditingValue.text.length) { + return; + } + + final int rightOffset = + _getRightByWord(textEditingValue.selection.extentOffset, includeWhitespace); + final TextSelection nextSelection = TextSelection.fromPosition(TextPosition(offset: rightOffset, affinity: textEditingValue.selection.affinity)); + + if (nextSelection == textEditingValue.selection) { + return; + } + setSelection(nextSelection, cause); + } + + /// Move the current selection to the end of the field. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [moveSelectionToStart], which is the same but in the opposite + /// direction. + void moveSelectionToEnd(SelectionChangedCause cause) { + final TextPosition nextPosition = TextPosition( + offset: textEditingValue.text.length, + ); + setSelection(TextSelection.fromPosition(nextPosition), cause); + } + + /// Move the current selection to the start of the field. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [moveSelectionToEnd], which is the same but in the opposite direction. + void moveSelectionToStart(SelectionChangedCause cause) { + const TextPosition nextPosition = TextPosition( + offset: 0, + affinity: TextAffinity.upstream, + ); + setSelection(TextSelection.fromPosition(nextPosition), cause); + } + + /// Move the current selection up by one line. + /// + /// If the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + /// + /// See also: + /// + /// * [moveSelectionDown], which is the same but in the opposite direction. + void moveSelectionUp(SelectionChangedCause cause) { + if (!textEditingValue.selection.isValid) { + return; + } + final int nextIndex = + textLayoutMetrics.getTextPositionAbove(textEditingValue.selection.extent).offset; + + if (nextIndex == textEditingValue.selection.extentOffset) { + _wasSelectingVerticallyWithKeyboard = false; + return moveSelectionToStart(cause); + } + _cursorResetLocation = nextIndex; + + setSelection(TextSelection.fromPosition(TextPosition(offset: nextIndex, affinity: textEditingValue.selection.affinity)), cause); + } + + /// Select the entire text value. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + void selectAll(SelectionChangedCause cause) { + setSelection( + textEditingValue.selection.copyWith( + baseOffset: 0, + extentOffset: textEditingValue.text.length, + ), + cause, + ); + } + + /// {@template flutter.widgets.TextEditingActionTarget.copySelection} + /// Copy current selection to [Clipboard]. + /// {@endtemplate} + /// + /// If the selection is collapsed or invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + void copySelection(SelectionChangedCause cause) { + final TextSelection selection = textEditingValue.selection; + final String text = textEditingValue.text; + assert(selection != null); + if (selection.isCollapsed || !selection.isValid) { + return; + } + Clipboard.setData(ClipboardData(text: selection.textInside(text))); + } + + /// {@template flutter.widgets.TextEditingActionTarget.cutSelection} + /// Cut current selection to Clipboard. + /// {@endtemplate} + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + void cutSelection(SelectionChangedCause cause) { + final TextSelection selection = textEditingValue.selection; + if (readOnly || !selection.isValid) { + return; + } + final String text = textEditingValue.text; + assert(selection != null); + if (selection.isCollapsed) { + return; + } + Clipboard.setData(ClipboardData(text: selection.textInside(text))); + setTextEditingValue( + TextEditingValue( + text: selection.textBefore(text) + selection.textAfter(text), + selection: TextSelection.collapsed( + offset: math.min(selection.start, selection.end), + affinity: selection.affinity, + ), + ), + cause, + ); + } + + /// {@template flutter.widgets.TextEditingActionTarget.pasteText} + /// Paste text from [Clipboard]. + /// {@endtemplate} + /// + /// If there is currently a selection, it will be replaced. + /// + /// If [readOnly] is true or the selection is invalid, does nothing. + /// + /// {@macro flutter.widgets.TextEditingActionTarget.cause} + Future pasteText(SelectionChangedCause cause) async { + final TextSelection selection = textEditingValue.selection; + if (readOnly || !selection.isValid) { + return; + } + final String text = textEditingValue.text; + assert(selection != null); + if (!selection.isValid) { + return; + } + // Snapshot the input before using `await`. + // See https://github.com/flutter/flutter/issues/11427 + final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); + if (data == null) { + return; + } + setTextEditingValue( + TextEditingValue( + text: selection.textBefore(text) + + data.text! + + selection.textAfter(text), + selection: TextSelection.collapsed( + offset: + math.min(selection.start, selection.end) + data.text!.length, + affinity: selection.affinity, + ), + ), + cause, + ); + } +} diff --git a/packages/flutter/lib/src/widgets/text_editing_intents.dart b/packages/flutter/lib/src/widgets/text_editing_intents.dart index b4554f5624339..86aff6821323d 100644 --- a/packages/flutter/lib/src/widgets/text_editing_intents.dart +++ b/packages/flutter/lib/src/widgets/text_editing_intents.dart @@ -2,266 +2,299 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/services.dart'; - import 'actions.dart'; -/// An [Intent] to send the event straight to the engine. +/// An [Intent] to delete a character in the backwards direction. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class DeleteTextIntent extends Intent { + /// Creates an instance of DeleteTextIntent. + const DeleteTextIntent(); +} + +/// An [Intent] to delete a word in the backwards direction. /// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class DeleteByWordTextIntent extends Intent { + /// Creates an instance of DeleteByWordTextIntent. + const DeleteByWordTextIntent(); +} + +/// An [Intent] to delete a line in the backwards direction. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class DeleteByLineTextIntent extends Intent { + /// Creates an instance of DeleteByLineTextIntent. + const DeleteByLineTextIntent(); +} + +/// An [Intent] to delete in the forward direction. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class DeleteForwardTextIntent extends Intent { + /// Creates an instance of DeleteForwardTextIntent. + const DeleteForwardTextIntent(); +} + +/// An [Intent] to delete a word in the forward direction. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class DeleteForwardByWordTextIntent extends Intent { + /// Creates an instance of DeleteByWordTextIntent. + const DeleteForwardByWordTextIntent(); +} + +/// An [Intent] to delete a line in the forward direction. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class DeleteForwardByLineTextIntent extends Intent { + /// Creates an instance of DeleteByLineTextIntent. + const DeleteForwardByLineTextIntent(); +} + +/// An [Intent] to send the event straight to the engine, but only if a +/// TextEditingTarget is focused. +/// +/// {@template flutter.widgets.TextEditingIntents.seeAlso} /// See also: /// +/// * [DefaultTextEditingActions], which responds to this [Intent]. /// * [DefaultTextEditingShortcuts], which triggers this [Intent]. +/// {@endtemplate} class DoNothingAndStopPropagationTextIntent extends Intent { - /// Creates an instance of [DoNothingAndStopPropagationTextIntent]. + /// Creates an instance of DoNothingAndStopPropagationTextIntent. const DoNothingAndStopPropagationTextIntent(); } -/// A text editing related [Intent] that performs an operation towards a given -/// direction of the current caret location. -abstract class DirectionalTextEditingIntent extends Intent { - /// Creates a [DirectionalTextEditingIntent]. - const DirectionalTextEditingIntent(this.forward); +/// An [Intent] to expand the selection left to the start/end of the current +/// line. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExpandSelectionLeftByLineTextIntent extends Intent { + /// Creates an instance of ExpandSelectionLeftByLineTextIntent. + const ExpandSelectionLeftByLineTextIntent(); +} - /// Whether the input field, if applicable, should perform the text editing - /// operation from the current caret location towards the end of the document. - /// - /// Unless otherwise specified by the recipient of this intent, this parameter - /// uses the logical order of characters in the string to determind the - /// direction, and is not affected by the writing direction of the text. - final bool forward; +/// An [Intent] to expand the selection right to the start/end of the current +/// field. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExpandSelectionRightByLineTextIntent extends Intent { + /// Creates an instance of ExpandSelectionRightByLineTextIntent. + const ExpandSelectionRightByLineTextIntent(); } -/// Deletes the character before or after the caret location, based on whether -/// `forward` is true. +/// An [Intent] to expand the selection to the end of the field. /// -/// {@template flutter.widgets.TextEditingIntents.logicalOrder} -/// {@endtemplate} +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExpandSelectionToEndTextIntent extends Intent { + /// Creates an instance of ExpandSelectionToEndTextIntent. + const ExpandSelectionToEndTextIntent(); +} + +/// An [Intent] to expand the selection to the start of the field. /// -/// Typically a text field will not respond to this intent if it has no active -/// caret ([TextSelection.isValid] is false for the current selection). -class DeleteCharacterIntent extends DirectionalTextEditingIntent { - /// Creates a [DeleteCharacterIntent]. - const DeleteCharacterIntent({ required bool forward }) : super(forward); -} - -/// Deletes from the current caret location to the previous or next word -/// boundary, based on whether `forward` is true. -class DeleteToNextWordBoundaryIntent extends DirectionalTextEditingIntent { - /// Creates a [DeleteToNextWordBoundaryIntent]. - const DeleteToNextWordBoundaryIntent({ required bool forward }) : super(forward); -} - -/// Deletes from the current caret location to the previous or next soft or hard -/// line break, based on whether `forward` is true. -class DeleteToLineBreakIntent extends DirectionalTextEditingIntent { - /// Creates a [DeleteToLineBreakIntent]. - const DeleteToLineBreakIntent({ required bool forward }) : super(forward); -} - -/// A [DirectionalTextEditingIntent] that moves the caret or the selection to a -/// new location. -abstract class DirectionalCaretMovementIntent extends DirectionalTextEditingIntent { - /// Creates a [DirectionalCaretMovementIntent]. - const DirectionalCaretMovementIntent( - bool forward, - this.collapseSelection, - [this.collapseAtReversal = false] - ) : assert(!collapseSelection || !collapseAtReversal), - super(forward); - - /// Whether this [Intent] should make the selection collapsed (so it becomes a - /// caret), after the movement. - /// - /// When [collapseSelection] is false, the input field typically only moves - /// the current [TextSelection.extent] to the new location, while maintains - /// the current [TextSelection.base] location. - /// - /// When [collapseSelection] is true, the input field typically should move - /// both the [TextSelection.base] and the [TextSelection.extent] to the new - /// location. - final bool collapseSelection; - - /// Whether to collapse the selection when it would otherwise reverse order. - /// - /// For example, consider when forward is true and the extent is before the - /// base. If collapseAtReversal is true, then this will cause the selection to - /// collapse at the base. If it's false, then the extent will be placed at the - /// linebreak, reversing the order of base and offset. - /// - /// Cannot be true when collapseSelection is true. - final bool collapseAtReversal; -} - -/// Extends, or moves the current selection from the current -/// [TextSelection.extent] position to the previous or the next character -/// boundary. -class ExtendSelectionByCharacterIntent extends DirectionalCaretMovementIntent { - /// Creates an [ExtendSelectionByCharacterIntent]. - const ExtendSelectionByCharacterIntent({ - required bool forward, - required bool collapseSelection, - }) : super(forward, collapseSelection); -} - -/// Extends, or moves the current selection from the current -/// [TextSelection.extent] position to the previous or the next word -/// boundary. -class ExtendSelectionToNextWordBoundaryIntent extends DirectionalCaretMovementIntent { - /// Creates an [ExtendSelectionToNextWordBoundaryIntent]. - const ExtendSelectionToNextWordBoundaryIntent({ - required bool forward, - required bool collapseSelection, - }) : super(forward, collapseSelection); -} - -/// Extends, or moves the current selection from the current -/// [TextSelection.extent] position to the previous or the next word -/// boundary, or the [TextSelection.base] position if it's closer in the move -/// direction. -/// -/// This [Intent] typically has the same effect as an -/// [ExtendSelectionToNextWordBoundaryIntent], except it collapses the selection -/// when the order of [TextSelection.base] and [TextSelection.extent] would -/// reverse. -/// -/// This is typically only used on MacOS. -class ExtendSelectionToNextWordBoundaryOrCaretLocationIntent extends DirectionalTextEditingIntent { - /// Creates an [ExtendSelectionToNextWordBoundaryOrCaretLocationIntent]. - const ExtendSelectionToNextWordBoundaryOrCaretLocationIntent({ - required bool forward, - }) : super(forward); -} - -/// Expands the current selection to the closest line break in the direction -/// given by [forward]. -/// -/// Either the base or extent can move, whichever is closer to the line break. -/// The selection will never shrink. -/// -/// This behavior is common on MacOS. +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExpandSelectionToStartTextIntent extends Intent { + /// Creates an instance of ExpandSelectionToStartTextIntent. + const ExpandSelectionToStartTextIntent(); +} + +/// An [Intent] to extend the selection down by one line. /// -/// See also: +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionDownTextIntent extends Intent { + /// Creates an instance of ExtendSelectionDownTextIntent. + const ExtendSelectionDownTextIntent(); +} + +/// An [Intent] to extend the selection left to the start/end of the current +/// line. /// -/// [ExtendSelectionToLineBreakIntent], which is similar but always moves the -/// extent. -class ExpandSelectionToLineBreakIntent extends DirectionalTextEditingIntent { - /// Creates an [ExpandSelectionToLineBreakIntent]. - const ExpandSelectionToLineBreakIntent({ - required bool forward, - }) : super(forward); +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionLeftByLineTextIntent extends Intent { + /// Creates an instance of ExtendSelectionLeftByLineTextIntent. + const ExtendSelectionLeftByLineTextIntent(); } -/// Extends, or moves the current selection from the current -/// [TextSelection.extent] position to the closest line break in the direction -/// given by [forward]. +/// An [Intent] to extend the selection left past the nearest word, collapsing +/// the selection if the order of [TextSelection.extentOffset] and +/// [TextSelection.baseOffset] would reverse. /// -/// See also: +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionLeftByWordAndStopAtReversalTextIntent extends Intent { + /// Creates an instance of ExtendSelectionLeftByWordAndStopAtReversalTextIntent. + const ExtendSelectionLeftByWordAndStopAtReversalTextIntent(); +} + +/// An [Intent] to extend the selection left past the nearest word. /// -/// [ExpandSelectionToLineBreakIntent], which is similar but always increases -/// the size of the selection. -class ExtendSelectionToLineBreakIntent extends DirectionalCaretMovementIntent { - /// Creates an [ExtendSelectionToLineBreakIntent]. - const ExtendSelectionToLineBreakIntent({ - required bool forward, - required bool collapseSelection, - bool collapseAtReversal = false, - }) : assert(!collapseSelection || !collapseAtReversal), - super(forward, collapseSelection, collapseAtReversal); +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionLeftByWordTextIntent extends Intent { + /// Creates an instance of ExtendSelectionLeftByWordTextIntent. + const ExtendSelectionLeftByWordTextIntent(); } -/// Extends, or moves the current selection from the current -/// [TextSelection.extent] position to the closest position on the adjacent -/// line. -class ExtendSelectionVerticallyToAdjacentLineIntent extends DirectionalCaretMovementIntent { - /// Creates an [ExtendSelectionVerticallyToAdjacentLineIntent]. - const ExtendSelectionVerticallyToAdjacentLineIntent({ - required bool forward, - required bool collapseSelection, - }) : super(forward, collapseSelection); +/// An [Intent] to extend the selection left by one character. +/// platform for the shift + arrow-left key event. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionLeftTextIntent extends Intent { + /// Creates an instance of ExtendSelectionLeftTextIntent. + const ExtendSelectionLeftTextIntent(); } -/// Extends, or moves the current selection from the current -/// [TextSelection.extent] position to the start or the end of the document. -class ExtendSelectionToDocumentBoundaryIntent extends DirectionalCaretMovementIntent { - /// Creates an [ExtendSelectionToDocumentBoundaryIntent]. - const ExtendSelectionToDocumentBoundaryIntent({ - required bool forward, - required bool collapseSelection, - }) : super(forward, collapseSelection); +/// An [Intent] to extend the selection right to the start/end of the current +/// line. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionRightByLineTextIntent extends Intent { + /// Creates an instance of ExtendSelectionRightByLineTextIntent. + const ExtendSelectionRightByLineTextIntent(); } -/// An [Intent] to select everything in the field. -class SelectAllTextIntent extends Intent { - /// Creates an instance of [SelectAllTextIntent]. - const SelectAllTextIntent(this.cause); +/// An [Intent] to extend the selection right past the nearest word, collapsing +/// the selection if the order of [TextSelection.extentOffset] and +/// [TextSelection.baseOffset] would reverse. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionRightByWordAndStopAtReversalTextIntent extends Intent { + /// Creates an instance of ExtendSelectionRightByWordAndStopAtReversalTextIntent. + const ExtendSelectionRightByWordAndStopAtReversalTextIntent(); +} - /// {@template flutter.widgets.TextEditingIntents.cause} - /// The [SelectionChangedCause] that triggered the intent. - /// {@endtemplate} - final SelectionChangedCause cause; +/// An [Intent] to extend the selection right past the nearest word. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionRightByWordTextIntent extends Intent { + /// Creates an instance of ExtendSelectionRightByWordTextIntent. + const ExtendSelectionRightByWordTextIntent(); } -/// An [Intent] that represents a user interaction that attempts to copy or cut -/// the current selection in the field. -class CopySelectionTextIntent extends Intent { - const CopySelectionTextIntent._(this.cause, this.collapseSelection); +/// An [Intent] to extend the selection right by one character. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionRightTextIntent extends Intent { + /// Creates an instance of ExtendSelectionRightTextIntent. + const ExtendSelectionRightTextIntent(); +} - /// Creates an [Intent] that represents a user interaction that attempts to - /// cut the current selection in the field. - const CopySelectionTextIntent.cut(SelectionChangedCause cause) : this._(cause, true); +/// An [Intent] to extend the selection up by one line. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class ExtendSelectionUpTextIntent extends Intent { + /// Creates an instance of ExtendSelectionUpTextIntent. + const ExtendSelectionUpTextIntent(); +} - /// An [Intent] that represents a user interaction that attempts to copy the - /// current selection in the field. - static const CopySelectionTextIntent copy = CopySelectionTextIntent._(SelectionChangedCause.keyboard, false); +/// An [Intent] to move the selection down by one line. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionDownTextIntent extends Intent { + /// Creates an instance of MoveSelectionDownTextIntent. + const MoveSelectionDownTextIntent(); +} - /// {@macro flutter.widgets.TextEditingIntents.cause} - final SelectionChangedCause cause; +/// An [Intent] to move the selection left by one line. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionLeftByLineTextIntent extends Intent { + /// Creates an instance of MoveSelectionLeftByLineTextIntent. + const MoveSelectionLeftByLineTextIntent(); +} - /// Whether the original text needs to be removed from the input field if the - /// copy action was successful. - final bool collapseSelection; +/// An [Intent] to move the selection left past the nearest word. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionLeftByWordTextIntent extends Intent { + /// Creates an instance of MoveSelectionLeftByWordTextIntent. + const MoveSelectionLeftByWordTextIntent(); } -/// An [Intent] to paste text from [Clipboard] to the field. -class PasteTextIntent extends Intent { - /// Creates an instance of [PasteTextIntent]. - const PasteTextIntent(this.cause); +/// An [Intent] to move the selection left by one character. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionLeftTextIntent extends Intent { + /// Creates an instance of MoveSelectionLeftTextIntent. + const MoveSelectionLeftTextIntent(); +} - /// {@macro flutter.widgets.TextEditingIntents.cause} - final SelectionChangedCause cause; +/// An [Intent] to move the selection to the start of the field. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionToStartTextIntent extends Intent { + /// Creates an instance of MoveSelectionToStartTextIntent. + const MoveSelectionToStartTextIntent(); } -/// An [Intent] that represents a user interaction that attempts to modify the -/// current [TextEditingValue] in an input field. -class ReplaceTextIntent extends Intent { - /// Creates a [ReplaceTextIntent]. - const ReplaceTextIntent(this.currentTextEditingValue, this.replacementText, this.replacementRange, this.cause); +/// An [Intent] to move the selection right by one line. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionRightByLineTextIntent extends Intent { + /// Creates an instance of MoveSelectionRightByLineTextIntent. + const MoveSelectionRightByLineTextIntent(); +} - /// The [TextEditingValue] that this [Intent]'s action should perform on. - final TextEditingValue currentTextEditingValue; +/// An [Intent] to move the selection right past the nearest word. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionRightByWordTextIntent extends Intent { + /// Creates an instance of MoveSelectionRightByWordTextIntent. + const MoveSelectionRightByWordTextIntent(); +} - /// The text to replace the original text within the [replacementRange] with. - final String replacementText; +/// An [Intent] to move the selection right by one character. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionRightTextIntent extends Intent { + /// Creates an instance of MoveSelectionRightTextIntent. + const MoveSelectionRightTextIntent(); +} - /// The range of text in [currentTextEditingValue] that needs to be replaced. - final TextRange replacementRange; +/// An [Intent] to move the selection to the end of the field. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionToEndTextIntent extends Intent { + /// Creates an instance of MoveSelectionToEndTextIntent. + const MoveSelectionToEndTextIntent(); +} - /// {@macro flutter.widgets.TextEditingIntents.cause} - final SelectionChangedCause cause; +/// An [Intent] to move the selection up by one character. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class MoveSelectionUpTextIntent extends Intent { + /// Creates an instance of MoveSelectionUpTextIntent. + const MoveSelectionUpTextIntent(); } -/// An [Intent] that represents a user interaction that attempts to change the -/// selection in an input field. -class UpdateSelectionIntent extends Intent { - /// Creates a [UpdateSelectionIntent]. - const UpdateSelectionIntent(this.currentTextEditingValue, this.newSelection, this.cause); +/// An [Intent] to select everything in the field. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class SelectAllTextIntent extends Intent { + /// Creates an instance of SelectAllTextIntent. + const SelectAllTextIntent(); +} - /// The [TextEditingValue] that this [Intent]'s action should perform on. - final TextEditingValue currentTextEditingValue; +/// An [Intent] to copy selection in the field. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class CopySelectionTextIntent extends Intent { + /// Creates an instance of CopyTextIntent. + const CopySelectionTextIntent(); +} - /// The new [TextSelection] the input field should adopt. - final TextSelection newSelection; +/// An [Intent] to cut selection in the field. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class CutSelectionTextIntent extends Intent { + /// Creates an instance of CutTextIntent. + const CutSelectionTextIntent(); +} - /// {@macro flutter.widgets.TextEditingIntents.cause} - final SelectionChangedCause cause; +/// An [Intent] to paste text from [Clipboard] to the field. +/// +/// {@macro flutter.widgets.TextEditingIntents.seeAlso} +class PasteTextIntent extends Intent { + /// Creates an instance of PasteTextIntent. + const PasteTextIntent(); } diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index 4a24bf6279ec8..9feb7fe024ae6 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -946,65 +946,6 @@ class TextSelectionGestureDetectorBuilder { && renderEditable.selection!.end >= textPosition.offset; } - // Expand the selection to the given global position. - // - // Either base or extent will be moved to the last tapped position, whichever - // is closest. The selection will never shrink or pivot, only grow. - // - // See also: - // - // * [_extendSelection], which is similar but pivots the selection around - // the base. - void _expandSelection(Offset offset, SelectionChangedCause cause) { - assert(cause != null); - assert(offset != null); - assert(renderEditable.selection?.baseOffset != null); - - final TextPosition tappedPosition = renderEditable.getPositionForPoint(offset); - final TextSelection selection = renderEditable.selection!; - final bool baseIsCloser = - (tappedPosition.offset - selection.baseOffset).abs() - < (tappedPosition.offset - selection.extentOffset).abs(); - final TextSelection nextSelection = selection.copyWith( - baseOffset: baseIsCloser ? selection.extentOffset : selection.baseOffset, - extentOffset: tappedPosition.offset, - ); - - editableText.userUpdateTextEditingValue( - editableText.textEditingValue.copyWith( - selection: nextSelection, - ), - cause, - ); - } - - // Extend the selection to the given global position. - // - // Holds the base in place and moves the extent. - // - // See also: - // - // * [_expandSelection], which is similar but always increases the size of - // the selection. - void _extendSelection(Offset offset, SelectionChangedCause cause) { - assert(cause != null); - assert(offset != null); - assert(renderEditable.selection?.baseOffset != null); - - final TextPosition tappedPosition = renderEditable.getPositionForPoint(offset); - final TextSelection selection = renderEditable.selection!; - final TextSelection nextSelection = selection.copyWith( - extentOffset: tappedPosition.offset, - ); - - editableText.userUpdateTextEditingValue( - editableText.textEditingValue.copyWith( - selection: nextSelection, - ), - cause, - ); - } - /// Whether to show the selection toolbar. /// /// It is based on the signal source when a [onTapDown] is called. This getter @@ -1023,12 +964,9 @@ class TextSelectionGestureDetectorBuilder { @protected RenderEditable get renderEditable => editableText.renderEditable; - // The viewport offset pixels of the [RenderEditable] at the last drag start. + /// The viewport offset pixels of the [RenderEditable] at the last drag start. double _dragStartViewportOffset = 0.0; - // True iff a tap + shift has been detected but the tap has not yet come up. - bool _isShiftTapping = false; - /// Handler for [TextSelectionGestureDetector.onTapDown]. /// /// By default, it forwards the tap to [RenderEditable.handleTapDown] and sets @@ -1048,28 +986,6 @@ class TextSelectionGestureDetectorBuilder { _shouldShowSelectionToolbar = kind == null || kind == PointerDeviceKind.touch || kind == PointerDeviceKind.stylus; - - // Handle shift + click selection if needed. - final bool isShiftPressed = HardwareKeyboard.instance.logicalKeysPressed - .any({ - LogicalKeyboardKey.shiftLeft, - LogicalKeyboardKey.shiftRight, - }.contains); - if (isShiftPressed && renderEditable.selection?.baseOffset != null) { - _isShiftTapping = true; - switch (defaultTargetPlatform) { - case TargetPlatform.iOS: - case TargetPlatform.macOS: - _expandSelection(details.globalPosition, SelectionChangedCause.tap); - break; - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: - _extendSelection(details.globalPosition, SelectionChangedCause.tap); - break; - } - } } /// Handler for [TextSelectionGestureDetector.onForcePressStart]. @@ -1127,37 +1043,8 @@ class TextSelectionGestureDetectorBuilder { /// this callback. @protected void onSingleTapUp(TapUpDetails details) { - if (_isShiftTapping) { - _isShiftTapping = false; - return; - } - if (delegate.selectionEnabled) { - switch (defaultTargetPlatform) { - case TargetPlatform.iOS: - case TargetPlatform.macOS: - switch (details.kind) { - case PointerDeviceKind.mouse: - case PointerDeviceKind.stylus: - case PointerDeviceKind.invertedStylus: - // Precise devices should place the cursor at a precise position. - renderEditable.selectPosition(cause: SelectionChangedCause.tap); - break; - case PointerDeviceKind.touch: - case PointerDeviceKind.unknown: - // On macOS/iOS/iPadOS a touch tap places the cursor at the edge - // of the word. - renderEditable.selectWordEdge(cause: SelectionChangedCause.tap); - break; - } - break; - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: - renderEditable.selectPosition(cause: SelectionChangedCause.tap); - break; - } + renderEditable.selectWordEdge(cause: SelectionChangedCause.tap); } } @@ -1640,9 +1527,11 @@ class _TextSelectionGestureDetectorState extends State( - () => PanGestureRecognizer(debugOwner: this, supportedDevices: { PointerDeviceKind.mouse }), - (PanGestureRecognizer instance) { + // TODO(mdebbar): Support dragging in any direction (for multiline text). + // https://github.com/flutter/flutter/issues/28676 + gestures[HorizontalDragGestureRecognizer] = GestureRecognizerFactoryWithHandlers( + () => HorizontalDragGestureRecognizer(debugOwner: this, kind: PointerDeviceKind.mouse), + (HorizontalDragGestureRecognizer instance) { instance // Text selection should start from the position of the first pointer // down event. diff --git a/packages/flutter/lib/src/widgets/ticker_provider.dart b/packages/flutter/lib/src/widgets/ticker_provider.dart index ef45229a7234c..9f9b3cdd338bc 100644 --- a/packages/flutter/lib/src/widgets/ticker_provider.dart +++ b/packages/flutter/lib/src/widgets/ticker_provider.dart @@ -15,7 +15,7 @@ export 'package:flutter/scheduler.dart' show TickerProvider; /// This only works if [AnimationController] objects are created using /// widget-aware ticker providers. For example, using a /// [TickerProviderStateMixin] or a [SingleTickerProviderStateMixin]. -class TickerMode extends StatefulWidget { +class TickerMode extends StatelessWidget { /// Creates a widget that enables or disables tickers. /// /// The [enabled] argument must not be null. @@ -62,85 +62,18 @@ class TickerMode extends StatefulWidget { return widget?.enabled ?? true; } - /// Obtains a [ValueNotifier] from the [TickerMode] surrounding the `context`, - /// which indicates whether tickers are enabled in the given subtree. - /// - /// When that [TickerMode] enabled or disabled tickers, the notifier notifies - /// its listeners. - /// - /// While the [ValueNotifier] is stable for the lifetime of the surrounding - /// [TickerMode], calling this method does not establish a dependency between - /// the `context` and the [TickerMode] and the widget owning the `context` - /// does not rebuild when the ticker mode changes from true to false or vice - /// versa. This is preferable when the ticker mode does not impact what is - /// currently rendered on screen, e.g. because it is ony used to mute/unmute a - /// [Ticker]. Since no dependency is established, the widget owning the - /// `context` is also not informed when it is moved to a new location in the - /// tree where it may have a different [TickerMode] ancestor. When this - /// happens, the widget must manually unsubscribe from the old notifier, - /// obtain a new one from the new ancestor [TickerMode] by calling this method - /// again, and re-subscribe to it. [StatefulWidget]s can, for example, do this - /// in [State.activate], which is called after the widget has been moved to - /// a new location. - /// - /// Alternatively, [of] can be used instead of this method to create a - /// dependency between the provided `context` and the ancestor [TickerMode]. - /// In this case, the widget automatically rebuilds when the ticker mode - /// changes or when it is moved to a new [TickerMode] ancestor, which - /// simplifies the management cost in the widget at the expensive of some - /// potential unnecessary rebuilds. - /// - /// In the absence of a [TickerMode] widget, this function returns a - /// [ValueNotifier], whose [ValueNotifier.value] is always true. - static ValueNotifier getNotifier(BuildContext context) { - final _EffectiveTickerMode? widget = context.getElementForInheritedWidgetOfExactType<_EffectiveTickerMode>()?.widget as _EffectiveTickerMode?; - return widget?.notifier ?? ValueNotifier(true); - } - - @override - State createState() => _TickerModeState(); -} - -class _TickerModeState extends State { - bool _ancestorTicketMode = true; - final ValueNotifier _effectiveMode = ValueNotifier(true); - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _ancestorTicketMode = TickerMode.of(context); - _updateEffectiveMode(); - } - - @override - void didUpdateWidget(TickerMode oldWidget) { - super.didUpdateWidget(oldWidget); - _updateEffectiveMode(); - } - - @override - void dispose() { - _effectiveMode.dispose(); - super.dispose(); - } - - void _updateEffectiveMode() { - _effectiveMode.value = _ancestorTicketMode && widget.enabled; - } - @override Widget build(BuildContext context) { return _EffectiveTickerMode( - enabled: _effectiveMode.value, - notifier: _effectiveMode, - child: widget.child, + enabled: enabled && TickerMode.of(context), + child: child, ); } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(FlagProperty('requested mode', value: widget.enabled, ifTrue: 'enabled', ifFalse: 'disabled', showName: true)); + properties.add(FlagProperty('requested mode', value: enabled, ifTrue: 'enabled', ifFalse: 'disabled', showName: true)); } } @@ -148,13 +81,11 @@ class _EffectiveTickerMode extends InheritedWidget { const _EffectiveTickerMode({ Key? key, required this.enabled, - required this.notifier, required Widget child, }) : assert(enabled != null), - super(key: key, child: child); + super(key: key, child: child); final bool enabled; - final ValueNotifier notifier; @override bool updateShouldNotify(_EffectiveTickerMode oldWidget) => enabled != oldWidget.enabled; @@ -196,8 +127,10 @@ mixin SingleTickerProviderStateMixin on State imple ]); }()); _ticker = Ticker(onTick, debugLabel: kDebugMode ? 'created by ${describeIdentity(this)}' : null); - _updateTickerModeNotifier(); - _updateTicker(); // Sets _ticker.mute correctly. + // We assume that this is called from initState, build, or some sort of + // event handler, and that thus TickerMode.of(context) would return true. We + // can't actually check that here because if we're in initState then we're + // not allowed to do inheritance checks yet. return _ticker!; } @@ -221,35 +154,14 @@ mixin SingleTickerProviderStateMixin on State imple _ticker!.describeForError('The offending ticker was'), ]); }()); - _tickerModeNotifier?.removeListener(_updateTicker); - _tickerModeNotifier = null; super.dispose(); } - ValueNotifier? _tickerModeNotifier; - @override - void activate() { - super.activate(); - // We may have a new TickerMode ancestor. - _updateTickerModeNotifier(); - _updateTicker(); - } - - void _updateTicker() { - if (_ticker != null) { - _ticker!.muted = !_tickerModeNotifier!.value; - } - } - - void _updateTickerModeNotifier() { - final ValueNotifier newNotifier = TickerMode.getNotifier(context); - if (newNotifier == _tickerModeNotifier) { - return; - } - _tickerModeNotifier?.removeListener(_updateTicker); - newNotifier.addListener(_updateTicker); - _tickerModeNotifier = newNotifier; + void didChangeDependencies() { + if (_ticker != null) + _ticker!.muted = !TickerMode.of(context); + super.didChangeDependencies(); } @override @@ -286,14 +198,8 @@ mixin TickerProviderStateMixin on State implements @override Ticker createTicker(TickerCallback onTick) { - if (_tickerModeNotifier == null) { - // Setup TickerMode notifier before we vend the first ticker. - _updateTickerModeNotifier(); - } - assert(_tickerModeNotifier != null); _tickers ??= <_WidgetTicker>{}; - final _WidgetTicker result = _WidgetTicker(onTick, this, debugLabel: kDebugMode ? 'created by ${describeIdentity(this)}' : null) - ..muted = !_tickerModeNotifier!.value; + final _WidgetTicker result = _WidgetTicker(onTick, this, debugLabel: kDebugMode ? 'created by ${describeIdentity(this)}' : null); _tickers!.add(result); return result; } @@ -304,35 +210,6 @@ mixin TickerProviderStateMixin on State implements _tickers!.remove(ticker); } - ValueNotifier? _tickerModeNotifier; - - @override - void activate() { - super.activate(); - // We may have a new TickerMode ancestor, get its Notifier. - _updateTickerModeNotifier(); - _updateTickers(); - } - - void _updateTickers() { - if (_tickers != null) { - final bool muted = !_tickerModeNotifier!.value; - for (final Ticker ticker in _tickers!) { - ticker.muted = muted; - } - } - } - - void _updateTickerModeNotifier() { - final ValueNotifier newNotifier = TickerMode.getNotifier(context); - if (newNotifier == _tickerModeNotifier) { - return; - } - _tickerModeNotifier?.removeListener(_updateTickers); - newNotifier.addListener(_updateTickers); - _tickerModeNotifier = newNotifier; - } - @override void dispose() { assert(() { @@ -358,11 +235,20 @@ mixin TickerProviderStateMixin on State implements } return true; }()); - _tickerModeNotifier?.removeListener(_updateTickers); - _tickerModeNotifier = null; super.dispose(); } + @override + void didChangeDependencies() { + final bool muted = !TickerMode.of(context); + if (_tickers != null) { + for (final Ticker ticker in _tickers!) { + ticker.muted = muted; + } + } + super.didChangeDependencies(); + } + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); diff --git a/packages/flutter/lib/src/widgets/viewport.dart b/packages/flutter/lib/src/widgets/viewport.dart index dc506542c6c55..17d4607100da2 100644 --- a/packages/flutter/lib/src/widgets/viewport.dart +++ b/packages/flutter/lib/src/widgets/viewport.dart @@ -211,9 +211,6 @@ class _ViewportElement extends MultiChildRenderObjectElement { /// Creates an element that uses the given widget as its configuration. _ViewportElement(Viewport widget) : super(widget); - bool _doingMountOrUpdate = false; - int? _centerSlotIndex; - @override Viewport get widget => super.widget as Viewport; @@ -222,67 +219,26 @@ class _ViewportElement extends MultiChildRenderObjectElement { @override void mount(Element? parent, Object? newSlot) { - assert(!_doingMountOrUpdate); - _doingMountOrUpdate = true; super.mount(parent, newSlot); _updateCenter(); - assert(_doingMountOrUpdate); - _doingMountOrUpdate = false; } @override void update(MultiChildRenderObjectWidget newWidget) { - assert(!_doingMountOrUpdate); - _doingMountOrUpdate = true; super.update(newWidget); _updateCenter(); - assert(_doingMountOrUpdate); - _doingMountOrUpdate = false; } void _updateCenter() { // TODO(ianh): cache the keys to make this faster if (widget.center != null) { - int elementIndex = 0; - for (final Element e in children) { - if (e.widget.key == widget.center) { - renderObject.center = e.renderObject as RenderSliver?; - break; - } - elementIndex++; - } - assert(elementIndex < children.length); - _centerSlotIndex = elementIndex; + renderObject.center = children.singleWhere( + (Element element) => element.widget.key == widget.center, + ).renderObject as RenderSliver?; } else if (children.isNotEmpty) { renderObject.center = children.first.renderObject as RenderSliver?; - _centerSlotIndex = 0; } else { renderObject.center = null; - _centerSlotIndex = null; - } - } - - @override - void insertRenderObjectChild(RenderObject child, IndexedSlot slot) { - super.insertRenderObjectChild(child, slot); - // Once [mount]/[update] are done, the `renderObject.center` will be updated - // in [_updateCenter]. - if (!_doingMountOrUpdate && slot.index == _centerSlotIndex) { - renderObject.center = child as RenderSliver?; - } - } - - @override - void moveRenderObjectChild(RenderObject child, IndexedSlot oldSlot, IndexedSlot newSlot) { - super.moveRenderObjectChild(child, oldSlot, newSlot); - assert(_doingMountOrUpdate); - } - - @override - void removeRenderObjectChild(RenderObject child, Object? slot) { - super.removeRenderObjectChild(child, slot); - if (!_doingMountOrUpdate && renderObject.center == child) { - renderObject.center = null; } } diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index cea02b1081c98..3ca2436537538 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -2869,7 +2869,6 @@ class _Location { required this.file, required this.line, required this.column, - // ignore: unused_element this.name, }); @@ -2917,9 +2916,9 @@ bool _isDebugCreator(DiagnosticsNode node) => node is DiagnosticsDebugCreator; /// in [WidgetsBinding.initInstances]. /// /// This is meant to be called only in debug mode. In other modes, it yields an empty list. -Iterable debugTransformDebugCreator(Iterable properties) { +Iterable debugTransformDebugCreator(Iterable properties) sync* { if (!kDebugMode) { - return []; + return; } final List pending = []; ErrorSummary? errorSummary; @@ -2930,22 +2929,20 @@ Iterable debugTransformDebugCreator(Iterable p } } bool foundStackTrace = false; - final List result = []; for (final DiagnosticsNode node in properties) { if (!foundStackTrace && node is DiagnosticsStackTrace) foundStackTrace = true; if (_isDebugCreator(node)) { - result.addAll(_parseDiagnosticsNode(node, errorSummary)); + yield* _parseDiagnosticsNode(node, errorSummary); } else { if (foundStackTrace) { pending.add(node); } else { - result.add(node); + yield node; } } } - result.addAll(pending); - return result; + yield* pending; } /// Transform the input [DiagnosticsNode]. @@ -2954,24 +2951,23 @@ Iterable debugTransformDebugCreator(Iterable p Iterable _parseDiagnosticsNode( DiagnosticsNode node, ErrorSummary? errorSummary, -) { +) sync* { assert(_isDebugCreator(node)); try { final DebugCreator debugCreator = node.value! as DebugCreator; final Element element = debugCreator.element; - return _describeRelevantUserCode(element, errorSummary); + yield* _describeRelevantUserCode(element, errorSummary); } catch (error, stack) { scheduleMicrotask(() { FlutterError.reportError(FlutterErrorDetails( exception: error, stack: stack, library: 'widget inspector', - informationCollector: () => [ - DiagnosticsNode.message('This exception was caught while trying to describe the user-relevant code of another error.'), - ], + informationCollector: () sync* { + yield DiagnosticsNode.message('This exception was caught while trying to describe the user-relevant code of another error.'); + } )); }); - return []; } } diff --git a/packages/flutter/lib/src/widgets/will_pop_scope.dart b/packages/flutter/lib/src/widgets/will_pop_scope.dart index 605c5d16cee2b..af5fb1bf06509 100644 --- a/packages/flutter/lib/src/widgets/will_pop_scope.dart +++ b/packages/flutter/lib/src/widgets/will_pop_scope.dart @@ -9,12 +9,30 @@ import 'routes.dart'; /// Registers a callback to veto attempts by the user to dismiss the enclosing /// [ModalRoute]. /// -/// {@tool dartpad} +/// {@tool snippet --template=stateful_widget} +/// /// Whenever the back button is pressed, you will get a callback at [onWillPop], /// which returns a [Future]. If the [Future] returns true, the screen is /// popped. /// -/// ** See code in examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart ** +/// ```dart +/// bool shouldPop = true; +/// @override +/// Widget build(BuildContext context) { +/// return WillPopScope ( +/// onWillPop: () async { +/// return shouldPop; +/// }, +/// child: const Text('WillPopScope sample'), +/// ); +/// } +/// ``` +/// {@end-tool} +/// +/// {@tool dartpad} +/// +/// +/// ** See code in examples/api/lib/widgets/will_pop_scope/will_pop_scope.1.dart ** /// {@end-tool} /// /// See also: @@ -67,6 +85,7 @@ class _WillPopScopeState extends State { @override void didUpdateWidget(WillPopScope oldWidget) { super.didUpdateWidget(oldWidget); + assert(_route == ModalRoute.of(context)); if (widget.onWillPop != oldWidget.onWillPop && _route != null) { if (oldWidget.onWillPop != null) _route!.removeScopedWillPopCallback(oldWidget.onWillPop!); diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index 62e702e79db37..b58c40f9c1820 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -33,6 +33,7 @@ export 'src/widgets/bottom_navigation_bar_item.dart'; export 'src/widgets/color_filter.dart'; export 'src/widgets/container.dart'; export 'src/widgets/debug.dart'; +export 'src/widgets/default_text_editing_actions.dart'; export 'src/widgets/default_text_editing_shortcuts.dart'; export 'src/widgets/desktop_text_selection_toolbar_layout_delegate.dart'; export 'src/widgets/dismissible.dart'; @@ -116,11 +117,12 @@ export 'src/widgets/sliver_fill.dart'; export 'src/widgets/sliver_layout_builder.dart'; export 'src/widgets/sliver_persistent_header.dart'; export 'src/widgets/sliver_prototype_extent_list.dart'; -export 'src/widgets/slotted_render_object_widget.dart'; export 'src/widgets/spacer.dart'; export 'src/widgets/status_transitions.dart'; export 'src/widgets/table.dart'; export 'src/widgets/text.dart'; +export 'src/widgets/text_editing_action.dart'; +export 'src/widgets/text_editing_action_target.dart'; export 'src/widgets/text_editing_intents.dart'; export 'src/widgets/text_selection.dart'; export 'src/widgets/text_selection_toolbar_layout_delegate.dart'; diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 25f9c2e33f297..dc86d736af7ab 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter description: A framework for writing Flutter applications -homepage: https://flutter.dev +homepage: http://flutter.dev environment: sdk: ">=2.12.0-0 <3.0.0" @@ -9,7 +9,6 @@ dependencies: # To update these, use "flutter update-packages --force-upgrade". characters: 1.2.0 collection: 1.15.0 - material_color_utilities: 0.1.3 meta: 1.7.0 typed_data: 1.3.0 vector_math: 2.1.1 @@ -29,14 +28,14 @@ dev_dependencies: clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 8477 +# PUBSPEC CHECKSUM: 7714 diff --git a/packages/flutter/test/cupertino/activity_indicator_test.dart b/packages/flutter/test/cupertino/activity_indicator_test.dart index 9d19ab177c75a..4ea3902cad260 100644 --- a/packages/flutter/test/cupertino/activity_indicator_test.dart +++ b/packages/flutter/test/cupertino/activity_indicator_test.dart @@ -158,32 +158,6 @@ void main() { ..rrect(rrect: const RRect.fromLTRBXY(-10, -100 / 3, 10, -100, 10, 10)), ); }); - - testWidgets('Can specify color', (WidgetTester tester) async { - final Key key = UniqueKey(); - await tester.pumpWidget( - Center( - child: RepaintBoundary( - key: key, - child: Container( - color: CupertinoColors.white, - child: const CupertinoActivityIndicator( - animating: false, - color: Color(0xFF5D3FD3), - radius: 100, - ), - ), - ), - ), - ); - - expect( - find.byType(CupertinoActivityIndicator), - paints - ..rrect(rrect: const RRect.fromLTRBXY(-10, -100 / 3, 10, -100, 10, 10), - color: const Color(0x935d3fd3)), - ); - }); } Widget buildCupertinoActivityIndicator([bool? animating]) { diff --git a/packages/flutter/test/cupertino/bottom_tab_bar_test.dart b/packages/flutter/test/cupertino/bottom_tab_bar_test.dart index f024aba864736..6bd33d48e7bcc 100644 --- a/packages/flutter/test/cupertino/bottom_tab_bar_test.dart +++ b/packages/flutter/test/cupertino/bottom_tab_bar_test.dart @@ -327,49 +327,6 @@ Future main() async { expect(tester.getSize(find.byType(CupertinoTabBar)).height, 90.0); }); - testWidgets('Set custom height', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/51704 - const double tabBarHeight = 56.0; - final CupertinoTabBar tabBar = CupertinoTabBar( - height: tabBarHeight, - items: [ - BottomNavigationBarItem( - icon: ImageIcon(MemoryImage(Uint8List.fromList(kTransparentImage))), - label: 'Aka', - ), - BottomNavigationBarItem( - icon: ImageIcon(MemoryImage(Uint8List.fromList(kTransparentImage))), - label: 'Shiro', - ), - ], - ); - - // Verify height with no bottom padding. - await pumpWidgetWithBoilerplate(tester, MediaQuery( - data: const MediaQueryData(), - child: CupertinoTabScaffold( - tabBar: tabBar, - tabBuilder: (BuildContext context, int index) { - return const Placeholder(); - }, - ), - )); - expect(tester.getSize(find.byType(CupertinoTabBar)).height, tabBarHeight); - - // Verify height with bottom padding. - const double bottomPadding = 40.0; - await pumpWidgetWithBoilerplate(tester, MediaQuery( - data: const MediaQueryData(padding: EdgeInsets.only(bottom: bottomPadding)), - child: CupertinoTabScaffold( - tabBar: tabBar, - tabBuilder: (BuildContext context, int index) { - return const Placeholder(); - }, - ), - )); - expect(tester.getSize(find.byType(CupertinoTabBar)).height, tabBarHeight + bottomPadding); - }); - testWidgets('Opaque background does not add blur effects', (WidgetTester tester) async { await pumpWidgetWithBoilerplate(tester, MediaQuery( data: const MediaQueryData(), @@ -472,7 +429,7 @@ Future main() async { semantics.dispose(); }); - testWidgets('Label of items should be nullable', (WidgetTester tester) async { + testWidgets('Title of items should be nullable', (WidgetTester tester) async { final MemoryImage iconProvider = MemoryImage(Uint8List.fromList(kTransparentImage)); final List itemsTapped = []; diff --git a/packages/flutter/test/cupertino/context_menu_action_test.dart b/packages/flutter/test/cupertino/context_menu_action_test.dart index 00d75f32fcd8f..f3d7981e5fd80 100644 --- a/packages/flutter/test/cupertino/context_menu_action_test.dart +++ b/packages/flutter/test/cupertino/context_menu_action_test.dart @@ -5,28 +5,15 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { // Constants taken from _ContextMenuActionState. - const CupertinoDynamicColor _kBackgroundColor = CupertinoDynamicColor.withBrightness( - color: Color(0xFFEEEEEE), - darkColor: Color(0xFF212122), - ); - // static const Color _kBackgroundColorPressed = Color(0xFFDDDDDD); - const CupertinoDynamicColor _kBackgroundColorPressed = CupertinoDynamicColor.withBrightness( - color: Color(0xFFDDDDDD), - darkColor: Color(0xFF3F3F40), - ); + const Color _kBackgroundColor = Color(0xFFEEEEEE); + const Color _kBackgroundColorPressed = Color(0xFFDDDDDD); + const Color _kRegularActionColor = CupertinoColors.black; const Color _kDestructiveActionColor = CupertinoColors.destructiveRed; const FontWeight _kDefaultActionWeight = FontWeight.w600; - Widget _getApp({ - VoidCallback? onPressed, - bool isDestructiveAction = false, - bool isDefaultAction = false, - Brightness? brightness, - }) { + Widget _getApp({VoidCallback? onPressed, bool isDestructiveAction = false, bool isDefaultAction = false}) { final UniqueKey actionKey = UniqueKey(); final CupertinoContextMenuAction action = CupertinoContextMenuAction( key: actionKey, @@ -38,9 +25,6 @@ void main() { ); return CupertinoApp( - theme: CupertinoThemeData( - brightness: brightness ?? Brightness.light, - ), home: CupertinoPageScaffold( child: Center( child: action, @@ -49,6 +33,16 @@ void main() { ); } + BoxDecoration _getDecoration(WidgetTester tester) { + final Finder finder = find.descendant( + of: find.byType(CupertinoContextMenuAction), + matching: find.byType(Container), + ); + expect(finder, findsOneWidget); + final Container container = tester.widget(finder); + return container.decoration! as BoxDecoration; + } + TextStyle _getTextStyle(WidgetTester tester) { final Finder finder = find.descendant( of: find.byType(CupertinoContextMenuAction), @@ -82,34 +76,22 @@ void main() { testWidgets('turns grey when pressed and held', (WidgetTester tester) async { await tester.pumpWidget(_getApp()); - expect(find.byType(CupertinoContextMenuAction), paints..rect(color: _kBackgroundColor.color)); - - final Offset actionCenterLight = tester.getCenter(find.byType(CupertinoContextMenuAction)); - final TestGesture gestureLight = await tester.startGesture(actionCenterLight); - await tester.pump(); - expect(find.byType(CupertinoContextMenuAction), paints..rect(color: _kBackgroundColorPressed.color)); - - await gestureLight.up(); - await tester.pump(); - expect(find.byType(CupertinoContextMenuAction), paints..rect(color: _kBackgroundColor.color)); - - await tester.pumpWidget(_getApp(brightness: Brightness.dark)); - expect(find.byType(CupertinoContextMenuAction), paints..rect(color: _kBackgroundColor.darkColor)); + expect(_getDecoration(tester).color, _kBackgroundColor); - final Offset actionCenterDark = tester.getCenter(find.byType(CupertinoContextMenuAction)); - final TestGesture gestureDark = await tester.startGesture(actionCenterDark); + final Offset actionCenter = tester.getCenter(find.byType(CupertinoContextMenuAction)); + final TestGesture gesture = await tester.startGesture(actionCenter); await tester.pump(); - expect(find.byType(CupertinoContextMenuAction), paints..rect(color: _kBackgroundColorPressed.darkColor)); + expect(_getDecoration(tester).color, _kBackgroundColorPressed); - await gestureDark.up(); + await gesture.up(); await tester.pump(); - expect(find.byType(CupertinoContextMenuAction), paints..rect(color: _kBackgroundColor.darkColor)); + expect(_getDecoration(tester).color, _kBackgroundColor); }); testWidgets('icon and textStyle colors are correct out of the box', (WidgetTester tester) async { await tester.pumpWidget(_getApp()); - expect(_getTextStyle(tester).color, CupertinoColors.label); - expect(_getIcon(tester).color, CupertinoColors.label); + expect(_getTextStyle(tester).color, _kRegularActionColor); + expect(_getIcon(tester).color, _kRegularActionColor); }); testWidgets('icon and textStyle colors are correct for destructive actions', (WidgetTester tester) async { diff --git a/packages/flutter/test/cupertino/context_menu_test.dart b/packages/flutter/test/cupertino/context_menu_test.dart index ffb0011778954..dc5ed1de57aab 100644 --- a/packages/flutter/test/cupertino/context_menu_test.dart +++ b/packages/flutter/test/cupertino/context_menu_test.dart @@ -9,6 +9,7 @@ void main() { final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding; const double _kOpenScale = 1.1; + Widget _getChild() { return Container( width: 300.0, @@ -65,13 +66,6 @@ void main() { ); } - Finder _findStaticChildDecoration(WidgetTester tester) { - return find.descendant( - of: _findStatic(), - matching: find.byType(DecoratedBox), - ); - } - group('CupertinoContextMenu before and during opening', () { testWidgets('An unopened CupertinoContextMenu renders child in the same place as without', (WidgetTester tester) async { // Measure the child in the scene with no CupertinoContextMenu. @@ -196,65 +190,6 @@ void main() { }); group('CupertinoContextMenu when open', () { - testWidgets('Last action does not have border', (WidgetTester tester) async { - final Widget child = _getChild(); - await tester.pumpWidget(CupertinoApp( - home: CupertinoPageScaffold( - child: Center( - child: CupertinoContextMenu( - actions: const [ - CupertinoContextMenuAction( - child: Text('CupertinoContextMenuAction One'), - ), - ], - child: child, - ), - ), - ), - )); - - // Open the CupertinoContextMenu - final TestGesture firstGesture = await tester.startGesture(tester.getCenter(find.byWidget(child))); - await tester.pumpAndSettle(); - await firstGesture.up(); - await tester.pumpAndSettle(); - expect(_findStatic(), findsOneWidget); - - expect(_findStaticChildDecoration(tester), findsNWidgets(1)); - - // Close the CupertinoContextMenu. - await tester.tapAt(const Offset(1.0, 1.0)); - await tester.pumpAndSettle(); - expect(_findStatic(), findsNothing); - - await tester.pumpWidget(CupertinoApp( - home: CupertinoPageScaffold( - child: Center( - child: CupertinoContextMenu( - actions: const [ - CupertinoContextMenuAction( - child: Text('CupertinoContextMenuAction One'), - ), - CupertinoContextMenuAction( - child: Text('CupertinoContextMenuAction Two'), - ), - ], - child: child, - ), - ), - ), - )); - - // Open the CupertinoContextMenu - final TestGesture secondGesture = await tester.startGesture(tester.getCenter(find.byWidget(child))); - await tester.pumpAndSettle(); - await secondGesture.up(); - await tester.pumpAndSettle(); - expect(_findStatic(), findsOneWidget); - - expect(_findStaticChildDecoration(tester), findsNWidgets(3)); - }); - testWidgets('Can close CupertinoContextMenu by background tap', (WidgetTester tester) async { final Widget child = _getChild(); await tester.pumpWidget(_getContextMenu(child: child)); diff --git a/packages/flutter/test/cupertino/picker_test.dart b/packages/flutter/test/cupertino/picker_test.dart index e0a0babc9cf17..f0217500e0040 100644 --- a/packages/flutter/test/cupertino/picker_test.dart +++ b/packages/flutter/test/cupertino/picker_test.dart @@ -226,7 +226,6 @@ void main() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { systemCalls.add(methodCall); - return null; }); await tester.pumpWidget( @@ -280,7 +279,6 @@ void main() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { systemCalls.add(methodCall); - return null; }); await tester.pumpWidget( diff --git a/packages/flutter/test/cupertino/refresh_test.dart b/packages/flutter/test/cupertino/refresh_test.dart index 6afe666f748c0..02b41cc918f15 100644 --- a/packages/flutter/test/cupertino/refresh_test.dart +++ b/packages/flutter/test/cupertino/refresh_test.dart @@ -177,7 +177,6 @@ void main() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { platformCallLog.add(methodCall); - return null; }); await tester.pumpWidget( diff --git a/packages/flutter/test/cupertino/route_test.dart b/packages/flutter/test/cupertino/route_test.dart index 1d70902512798..1ec00c3a2ccde 100644 --- a/packages/flutter/test/cupertino/route_test.dart +++ b/packages/flutter/test/cupertino/route_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { @@ -938,170 +937,6 @@ void main() { ); }); - group('Cupertino page transitions', () { - CupertinoPageRoute buildRoute({required bool fullscreenDialog}) { - return CupertinoPageRoute( - fullscreenDialog: fullscreenDialog, - builder: (_) => const SizedBox(), - ); - } - - testWidgets('when route is not fullscreenDialog, it has a barrierColor', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: SizedBox.expand(), - ), - ); - - tester.state(find.byType(Navigator)).push( - buildRoute(fullscreenDialog: false), - ); - await tester.pumpAndSettle(); - - expect(tester.widget(find.byType(ModalBarrier).last).color, const Color(0x18000000)); - }); - - testWidgets('when route is a fullscreenDialog, it has no barrierColor', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: SizedBox.expand(), - ), - ); - - tester.state(find.byType(Navigator)).push( - buildRoute(fullscreenDialog: true), - ); - await tester.pumpAndSettle(); - - expect(tester.widget(find.byType(ModalBarrier).last).color, isNull); - }); - - testWidgets('when route is not fullscreenDialog, it has a _CupertinoEdgeShadowDecoration', (WidgetTester tester) async { - PaintPattern paintsShadowRect({required double dx, required Color color}) { - return paints..everything((Symbol methodName, List arguments) { - if (methodName != #drawRect) - return true; - final Rect rect = arguments[0] as Rect; - final Color paintColor = (arguments[1] as Paint).color; - if (rect.top != 0 || rect.width != 1.0 || rect.height != 600) - // _CupertinoEdgeShadowDecoration draws the shadows with a series of - // differently colored 1px-wide rects. Skip rects that aren't being - // drawn by the _CupertinoEdgeShadowDecoration. - return true; - if ((rect.left - dx).abs() >= 1) - // Skip calls for rects until the one with the given position offset - return true; - if (paintColor.value == color.value) - return true; - throw ''' - For a rect with an expected left-side position: $dx (drawn at ${rect.left}): - Expected a rect with color: $color, - And drew a rect with color: $paintColor. - '''; - }); - } - - await tester.pumpWidget( - const MaterialApp( - home: SizedBox.expand(), - ), - ); - - tester.state(find.byType(Navigator)).push( - buildRoute(fullscreenDialog: false), - ); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 1)); - - final RenderBox box = tester.firstRenderObject(find.byType(CustomPaint)); - - // Animation starts with effectively no shadow - expect(box, paintsShadowRect(dx: 795, color: const Color(0x00000000))); - expect(box, paintsShadowRect(dx: 785, color: const Color(0x00000000))); - expect(box, paintsShadowRect(dx: 775, color: const Color(0x00000000))); - expect(box, paintsShadowRect(dx: 765, color: const Color(0x00000000))); - expect(box, paintsShadowRect(dx: 755, color: const Color(0x00000000))); - - await tester.pump(const Duration(milliseconds: 100)); - - // Part-way through the transition, the shadow is approaching the full gradient - expect(box, paintsShadowRect(dx: 296, color: const Color(0x03000000))); - expect(box, paintsShadowRect(dx: 286, color: const Color(0x02000000))); - expect(box, paintsShadowRect(dx: 276, color: const Color(0x01000000))); - expect(box, paintsShadowRect(dx: 266, color: const Color(0x00000000))); - expect(box, paintsShadowRect(dx: 266, color: const Color(0x00000000))); - - await tester.pumpAndSettle(); - - // At the end of the transition, the shadow is a gradient between - // 0x04000000 and 0x00000000 and is now offscreen - expect(box, paintsShadowRect(dx: -1, color: const Color(0x04000000))); - expect(box, paintsShadowRect(dx: -10, color: const Color(0x03000000))); - expect(box, paintsShadowRect(dx: -20, color: const Color(0x02000000))); - expect(box, paintsShadowRect(dx: -30, color: const Color(0x01000000))); - expect(box, paintsShadowRect(dx: -40, color: const Color(0x00000000))); - - // Start animation in reverse - tester.state(find.byType(Navigator)).pop(); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 100)); - - expect(box, paintsShadowRect(dx: 498, color: const Color(0x04000000))); - expect(box, paintsShadowRect(dx: 488, color: const Color(0x03000000))); - expect(box, paintsShadowRect(dx: 478, color: const Color(0x02000000))); - expect(box, paintsShadowRect(dx: 468, color: const Color(0x01000000))); - expect(box, paintsShadowRect(dx: 458, color: const Color(0x00000000))); - - await tester.pump(const Duration(milliseconds: 250)); - - // At the end of the animation, the shadow approaches full transparency - expect(box, paintsShadowRect(dx: 794, color: const Color(0x01000000))); - expect(box, paintsShadowRect(dx: 784, color: const Color(0x00000000))); - expect(box, paintsShadowRect(dx: 774, color: const Color(0x00000000))); - expect(box, paintsShadowRect(dx: 764, color: const Color(0x00000000))); - expect(box, paintsShadowRect(dx: 754, color: const Color(0x00000000))); - }); - - testWidgets('when route is fullscreenDialog, it has no visible _CupertinoEdgeShadowDecoration', (WidgetTester tester) async { - PaintPattern paintsNoShadows() { - return paints..everything((Symbol methodName, List arguments) { - if (methodName != #drawRect) - return true; - final Rect rect = arguments[0] as Rect; - // _CupertinoEdgeShadowDecoration draws the shadows with a series of - // differently colored 1px rects. Skip all rects not drawn by a - // _CupertinoEdgeShadowDecoration. - if (rect.width != 1.0) - return true; - throw ''' - Expected: no rects with a width of 1px. - Found: $rect. - '''; - }); - } - - await tester.pumpWidget( - const MaterialApp( - home: SizedBox.expand(), - ), - ); - - final RenderBox box = tester.firstRenderObject(find.byType(CustomPaint)); - - tester.state(find.byType(Navigator)).push( - buildRoute(fullscreenDialog: true), - ); - - await tester.pumpAndSettle(); - expect(box, paintsNoShadows()); - - tester.state(find.byType(Navigator)).pop(); - - await tester.pumpAndSettle(); - expect(box, paintsNoShadows()); - }); - }); - testWidgets('ModalPopup overlay dark mode', (WidgetTester tester) async { late StateSetter stateSetter; Brightness brightness = Brightness.light; diff --git a/packages/flutter/test/cupertino/scrollbar_test.dart b/packages/flutter/test/cupertino/scrollbar_test.dart index dbc017a30a023..cd7711f495f1e 100644 --- a/packages/flutter/test/cupertino/scrollbar_test.dart +++ b/packages/flutter/test/cupertino/scrollbar_test.dart @@ -137,7 +137,6 @@ void main() { if (methodCall.method == 'HapticFeedback.vibrate') { hapticFeedbackCalls += 1; } - return null; }); // Long press on the scrollbar thumb and expect a vibration after it resizes. @@ -778,7 +777,6 @@ void main() { if (methodCall.method == 'HapticFeedback.vibrate') { hapticFeedbackCalls += 1; } - return null; }); // Long press on the scrollbar thumb and expect a vibration after it resizes. diff --git a/packages/flutter/test/cupertino/switch_test.dart b/packages/flutter/test/cupertino/switch_test.dart index 97dc10b69a14e..dd3d5492a6479 100644 --- a/packages/flutter/test/cupertino/switch_test.dart +++ b/packages/flutter/test/cupertino/switch_test.dart @@ -53,7 +53,6 @@ void main() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget( @@ -94,7 +93,6 @@ void main() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget( @@ -162,7 +160,6 @@ void main() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget( @@ -201,7 +198,6 @@ void main() { final List log = []; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget( diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index fb0495ce9214c..e37e33d582c97 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -16,7 +16,7 @@ import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle, Color; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart' show DragStartBehavior, PointerDeviceKind, kSecondaryMouseButton, kDoubleTapTimeout; +import 'package:flutter/gestures.dart' show DragStartBehavior, PointerDeviceKind, kSecondaryMouseButton; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -27,7 +27,7 @@ import '../widgets/editable_text_utils.dart' show OverflowWidgetTextEditingContr import '../widgets/semantics_tester.dart'; // On web, the context menu (aka toolbar) is provided by the browser. -const bool isContextMenuProvidedByPlatform = isBrowser; +final bool isContextMenuProvidedByPlatform = isBrowser; class MockTextSelectionControls extends TextSelectionControls { @override @@ -263,7 +263,7 @@ void main() { await tester.tap(find.text('Paste')); await tester.pumpAndSettle(); expect(controller.text, 'blah1 blah2blah1'); - expect(controller.selection, const TextSelection.collapsed(offset: 16)); + expect(controller.selection, const TextSelection(baseOffset: 16, extentOffset: 16, affinity: TextAffinity.upstream)); // Cut the first word. await gesture.down(midBlah1); @@ -284,37 +284,7 @@ void main() { skip: kIsWeb, // [intended] the web handles this on its own. ); - testWidgets('can get text selection color initially on desktop', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController( - text: 'blah1 blah2', - ); - await tester.pumpWidget( - CupertinoApp( - home: Center( - child: RepaintBoundary( - child: CupertinoTextField( - key: const ValueKey(1), - controller: controller, - focusNode: focusNode, - ), - ), - ), - ), - ); - - controller.selection = const TextSelection(baseOffset: 0, extentOffset: 11); - focusNode.requestFocus(); - await tester.pump(); - - expect(focusNode.hasFocus, true); - await expectLater( - find.byKey(const ValueKey(1)), - matchesGoldenFile('text_field_golden.text_selection_color.0.png'), - ); - }); - - testWidgets('Activates the text field when receives semantics focus on Mac, Windows', (WidgetTester tester) async { + testWidgets('Activates the text field when receives semantics focus on Mac', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; final FocusNode focusNode = FocusNode(); @@ -362,7 +332,7 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasFocus, isTrue); semantics.dispose(); - }, variant: const TargetPlatformVariant({ TargetPlatform.macOS, TargetPlatform.windows })); + }, variant: const TargetPlatformVariant({ TargetPlatform.macOS })); testWidgets( 'takes available space horizontally and takes intrinsic space vertically no-strut', @@ -717,7 +687,7 @@ void main() { await expectLater( find.byKey(const ValueKey(1)), matchesGoldenFile( - 'text_field_cursor_test.cupertino_${debugDefaultTargetPlatformOverride!.name.toLowerCase()}.1.png', + 'text_field_cursor_test.cupertino_${describeEnum(debugDefaultTargetPlatformOverride!).toLowerCase()}.1.png', ), ); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); @@ -1672,7 +1642,8 @@ void main() { // But don't trigger the toolbar. expect(find.byType(CupertinoButton), findsNothing); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, + ); testWidgets( 'slow double tap does not trigger double tap', @@ -1705,7 +1676,8 @@ void main() { // No toolbar. expect(find.byType(CupertinoButton), findsNothing); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, + ); testWidgets( 'double tap selects word and first tap of double tap moves cursor', @@ -1747,44 +1719,6 @@ void main() { }, ); - testWidgets( - 'double tap does not select word on read-only obscured field', - (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure', - ); - await tester.pumpWidget( - CupertinoApp( - home: Center( - child: CupertinoTextField( - readOnly: true, - obscureText: true, - controller: controller, - ), - ), - ), - ); - - // Long press to put the cursor after the "w". - const int index = 3; - await tester.longPressAt(textOffsetToPosition(tester, index)); - await tester.pump(); - - // Second tap doesn't select anything. - await tester.tapAt(textOffsetToPosition(tester, index)); - await tester.pump(const Duration(milliseconds: 50)); - await tester.tapAt(textOffsetToPosition(tester, index)); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 35), - ); - - // Selected text shows nothing. - expect(find.byType(CupertinoButton), findsNothing); - }, - ); - testWidgets('Readonly text field does not have tap action', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); @@ -1843,7 +1777,8 @@ void main() { // Selected text shows 3 toolbar buttons. expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, + ); testWidgets( 'double tap hold selects word', @@ -1932,7 +1867,8 @@ void main() { // No toolbar. expect(find.byType(CupertinoButton), findsNothing); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, + ); testWidgets('double tapping a space selects the previous word on iOS', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( @@ -2170,54 +2106,6 @@ void main() { }, ); - testWidgets( - 'A read-only obscured CupertinoTextField is not selectable', - (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure', - ); - await tester.pumpWidget( - CupertinoApp( - home: Center( - child: CupertinoTextField( - controller: controller, - obscureText: true, - readOnly: true, - ), - ), - ), - ); - - final Offset textFieldStart = tester.getTopLeft(find.byType(CupertinoTextField)); - - await tester.tapAt(textFieldStart + const Offset(150.0, 5.0)); - await tester.pump(const Duration(milliseconds: 50)); - final TestGesture gesture = - await tester.startGesture(textFieldStart + const Offset(150.0, 5.0)); - // Hold the press. - await tester.pump(const Duration(milliseconds: 500)); - - // Nothing is selected despite the double tap long press gesture. - expect( - controller.selection, - const TextSelection(baseOffset: 35, extentOffset: 35), - ); - - // The selection menu is not present. - expect(find.byType(CupertinoButton), findsNWidgets(0)); - - await gesture.up(); - await tester.pump(); - - // Still nothing selected and no selection menu. - expect( - controller.selection, - const TextSelection.collapsed(offset: 35), - ); - expect(find.byType(CupertinoButton), findsNWidgets(0)); - }, - ); - testWidgets( 'An obscured CupertinoTextField is selectable by default', (WidgetTester tester) async { @@ -2374,7 +2262,8 @@ void main() { // The toolbar from the long press is now dismissed by the second tap. expect(find.byType(CupertinoButton), findsNothing); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, + ); testWidgets( 'long press drag moves the cursor under the drag and shows toolbar on lift', @@ -2525,7 +2414,7 @@ void main() { expect(firstCharEndpoint.length, 1); // The first character is now offscreen to the left. expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-308.20, epsilon: 0.25)); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }); testWidgets( 'long tap after a double tap select is not affected', @@ -2566,7 +2455,8 @@ void main() { // Long press toolbar. expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(2)); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, + ); testWidgets( 'double tap after a long tap is not affected', @@ -2606,7 +2496,8 @@ void main() { ); // Shows toolbar. expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, + ); testWidgets( 'double tap chains work', @@ -2670,7 +2561,8 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, + ); testWidgets('force press selects word', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( @@ -2751,7 +2643,7 @@ void main() { await tester.pump(); // Falling back to a single tap doesn't trigger a toolbar. expect(find.byType(CupertinoButton), findsNothing); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }); testWidgets('Cannot drag one handle past the other', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( @@ -2813,7 +2705,7 @@ void main() { // The selection doesn't move beyond the left handle. There's always at // least 1 char selected. expect(controller.selection.extentOffset, 5); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }); testWidgets('Can select text by dragging with a mouse', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(); @@ -3334,7 +3226,6 @@ void main() { final List log = []; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget( @@ -3358,7 +3249,6 @@ void main() { final List log = []; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget( @@ -4447,7 +4337,6 @@ void main() { actions: >{ ScrollIntent: CallbackAction(onInvoke: (Intent intent) { scrollInvoked = true; - return null; }), }, child: ListView( @@ -4573,10 +4462,7 @@ void main() { find.byType(CupertinoApp), matchesGoldenFile('text_field_golden.TextSelectionStyle.1.png'), ); - }, - variant: const TargetPlatformVariant({ TargetPlatform.iOS }), - skip: kIsWeb, // [intended] the web has its own Select All. - ); + }); testWidgets('text selection style 2', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( @@ -4622,10 +4508,7 @@ void main() { find.byType(CupertinoApp), matchesGoldenFile('text_field_golden.TextSelectionStyle.2.png'), ); - }, - variant: const TargetPlatformVariant({ TargetPlatform.iOS }), - skip: kIsWeb, // [intended] the web has its own Select All. - ); + }); testWidgets('textSelectionControls is passed to EditableText', (WidgetTester tester) async { final MockTextSelectionControls selectionControl = MockTextSelectionControls(); @@ -4964,92 +4847,4 @@ void main() { matchesGoldenFile('overflow_clipbehavior_none.cupertino.0.png'), ); }); - - testWidgets('can shift + tap to select with a keyboard (Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure', - ); - await tester.pumpWidget( - CupertinoApp( - home: Center( - child: CupertinoTextField( - controller: controller, - ), - ), - ), - ); - - await tester.tapAt(textOffsetToPosition(tester, 13)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 13); - - await tester.pump(kDoubleTapTimeout); - await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); - await tester.tapAt(textOffsetToPosition(tester, 20)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 20); - - await tester.pump(kDoubleTapTimeout); - await tester.tapAt(textOffsetToPosition(tester, 23)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 23); - - await tester.pump(kDoubleTapTimeout); - await tester.tapAt(textOffsetToPosition(tester, 4)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 23); - expect(controller.selection.extentOffset, 4); - - await tester.sendKeyUpEvent(LogicalKeyboardKey.shift); - expect(controller.selection.baseOffset, 23); - expect(controller.selection.extentOffset, 4); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - - testWidgets('can shift + tap to select with a keyboard (non-Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure', - ); - await tester.pumpWidget( - CupertinoApp( - home: Center( - child: CupertinoTextField( - controller: controller, - ), - ), - ), - ); - - await tester.tapAt(textOffsetToPosition(tester, 13)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 13); - - await tester.pump(kDoubleTapTimeout); - await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); - await tester.tapAt(textOffsetToPosition(tester, 20)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 20); - - await tester.pump(kDoubleTapTimeout); - await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); - await tester.tapAt(textOffsetToPosition(tester, 23)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 23); - - await tester.pump(kDoubleTapTimeout); - await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); - await tester.tapAt(textOffsetToPosition(tester, 4)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 4); - - await tester.sendKeyUpEvent(LogicalKeyboardKey.shift); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 4); - }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); } diff --git a/packages/flutter/test/foundation/diagnostics_test.dart b/packages/flutter/test/foundation/diagnostics_test.dart index 29eedb054186d..ebc3672e8bb3b 100644 --- a/packages/flutter/test/foundation/diagnostics_test.dart +++ b/packages/flutter/test/foundation/diagnostics_test.dart @@ -59,10 +59,10 @@ void validateNodeJsonSerializationHelper(Map json, DiagnosticsN expect(json['name'], equals(node.name)); expect(json['showSeparator'] ?? true, equals(node.showSeparator)); expect(json['description'], equals(node.toDescription())); - expect(json['level'] ?? DiagnosticLevel.info.name, equals(node.level.name)); + expect(json['level'] ?? describeEnum(DiagnosticLevel.info), equals(describeEnum(node.level))); expect(json['showName'] ?? true, equals(node.showName)); expect(json['emptyBodyDescription'], equals(node.emptyBodyDescription)); - expect(json['style'] ?? DiagnosticsTreeStyle.sparse.name, equals(node.style!.name)); + expect(json['style'] ?? describeEnum(DiagnosticsTreeStyle.sparse), equals(describeEnum(node.style!))); expect(json['type'], equals(node.runtimeType.toString())); expect(json['hasChildren'] ?? false, equals(node.getChildren().isNotEmpty)); } diff --git a/packages/flutter/test/gestures/tap_test.dart b/packages/flutter/test/gestures/tap_test.dart index 77e5d93b73e63..89ab65eb48b0e 100644 --- a/packages/flutter/test/gestures/tap_test.dart +++ b/packages/flutter/test/gestures/tap_test.dart @@ -119,84 +119,6 @@ void main() { tap.dispose(); }); - testGesture('Should recognize tap for supported devices only', (GestureTester tester) { - final TapGestureRecognizer tap = TapGestureRecognizer( - supportedDevices: { PointerDeviceKind.mouse, PointerDeviceKind.stylus }, - ); - - bool tapRecognized = false; - tap.onTap = () { - tapRecognized = true; - }; - const PointerDownEvent touchDown = PointerDownEvent( - pointer: 1, - position: Offset(10.0, 10.0), - ); - const PointerUpEvent touchUp = PointerUpEvent( - pointer: 1, - position: Offset(11.0, 9.0), - ); - - tap.addPointer(touchDown); - tester.closeArena(1); - expect(tapRecognized, isFalse); - tester.route(touchDown); - expect(tapRecognized, isFalse); - - tester.route(touchUp); - expect(tapRecognized, isFalse); - GestureBinding.instance!.gestureArena.sweep(1); - expect(tapRecognized, isFalse); - - const PointerDownEvent mouseDown = PointerDownEvent( - kind: PointerDeviceKind.mouse, - pointer: 1, - position: Offset(10.0, 10.0), - ); - const PointerUpEvent mouseUp = PointerUpEvent( - kind: PointerDeviceKind.mouse, - pointer: 1, - position: Offset(11.0, 9.0), - ); - - tap.addPointer(mouseDown); - tester.closeArena(1); - expect(tapRecognized, isFalse); - tester.route(mouseDown); - expect(tapRecognized, isFalse); - - tester.route(mouseUp); - expect(tapRecognized, isTrue); - GestureBinding.instance!.gestureArena.sweep(1); - expect(tapRecognized, isTrue); - - tapRecognized = false; - - const PointerDownEvent stylusDown = PointerDownEvent( - kind: PointerDeviceKind.stylus, - pointer: 1, - position: Offset(10.0, 10.0), - ); - const PointerUpEvent stylusUp = PointerUpEvent( - kind: PointerDeviceKind.stylus, - pointer: 1, - position: Offset(11.0, 9.0), - ); - - tap.addPointer(stylusDown); - tester.closeArena(1); - expect(tapRecognized, isFalse); - tester.route(stylusDown); - expect(tapRecognized, isFalse); - - tester.route(stylusUp); - expect(tapRecognized, isTrue); - GestureBinding.instance!.gestureArena.sweep(1); - expect(tapRecognized, isTrue); - - tap.dispose(); - }); - testGesture('Details contain the correct device kind', (GestureTester tester) { final TapGestureRecognizer tap = TapGestureRecognizer(); diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 31167cbbde5ea..07958653793e8 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -289,11 +289,11 @@ void main() { const TextStyle titleTextStyle = TextStyle( fontSize: 20, - color: Colors.indigo, + color: Colors.black, ); const TextStyle subtitleTextStyle = TextStyle( fontSize: 15, - color: Colors.indigo, + color: Colors.red, ); await tester.pumpWidget( @@ -315,7 +315,6 @@ void main() { headline6: titleTextStyle, subtitle2: subtitleTextStyle, ), - foregroundColor: Colors.indigo, ), ), home: const Center( diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 3f78736f692a5..b1ee46756013d 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -100,8 +100,8 @@ void main() { center = tester.getCenter(title); size = tester.getSize(title); - expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${platform.name}'); - expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${platform.name}'); + expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}'); + expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${describeEnum(platform)}'); // One action is still centered. @@ -121,8 +121,8 @@ void main() { center = tester.getCenter(title); size = tester.getSize(title); - expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${platform.name}'); - expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${platform.name}'); + expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}'); + expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${describeEnum(platform)}'); // Two actions is left aligned again. @@ -143,7 +143,7 @@ void main() { center = tester.getCenter(title); size = tester.getSize(title); - expect(center.dx, lessThan(400 - size.width / 2.0), reason: 'on ${platform.name}'); + expect(center.dx, lessThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}'); } }); diff --git a/packages/flutter/test/material/bottom_navigation_bar_test.dart b/packages/flutter/test/material/bottom_navigation_bar_test.dart index c71b62fde72b3..88cf921ec8b26 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_test.dart @@ -28,11 +28,11 @@ void main() { items: const [ BottomNavigationBarItem( icon: Icon(Icons.ac_unit), - label: 'AC', + title: Text('AC'), ), BottomNavigationBarItem( icon: Icon(Icons.access_alarm), - label: 'Alarm', + title: Text('Alarm'), ), ], onTap: (int index) { @@ -1031,11 +1031,11 @@ void main() { bottomNavigationBar: BottomNavigationBar( items: const [ BottomNavigationBarItem( - label: 'A', + title: Text('A'), icon: Icon(Icons.ac_unit), ), BottomNavigationBarItem( - label: 'B', + title: Text('B'), icon: Icon(Icons.battery_alert), ), ], @@ -1046,7 +1046,7 @@ void main() { ); final RenderBox box = tester.renderObject(find.byType(BottomNavigationBar)); - expect(box.size.height, equals(56.0)); + expect(box.size.height, equals(66.0)); }); testWidgets('BottomNavigationBar does not grow with textScaleFactor when labels are provided', (WidgetTester tester) async { @@ -1216,9 +1216,9 @@ void main() { expect(find.byTooltip('C'), findsNothing); }); - testWidgets('BottomNavigationBar limits width of tiles with long labels', (WidgetTester tester) async { - final String longTextA = List.generate(100, (int index) => 'A').toString(); - final String longTextB = List.generate(100, (int index) => 'B').toString(); + testWidgets('BottomNavigationBar limits width of tiles with long titles', (WidgetTester tester) async { + final Text longTextA = Text(''.padLeft(100, 'A')); + final Text longTextB = Text(''.padLeft(100, 'B')); await tester.pumpWidget( MaterialApp( @@ -1226,11 +1226,11 @@ void main() { bottomNavigationBar: BottomNavigationBar( items: [ BottomNavigationBarItem( - label: longTextA, + title: longTextA, icon: const Icon(Icons.ac_unit), ), BottomNavigationBarItem( - label: longTextB, + title: longTextB, icon: const Icon(Icons.battery_alert), ), ], @@ -1242,9 +1242,9 @@ void main() { final RenderBox box = tester.renderObject(find.byType(BottomNavigationBar)); expect(box.size.height, equals(kBottomNavigationBarHeight)); - final RenderBox itemBoxA = tester.renderObject(find.text(longTextA)); + final RenderBox itemBoxA = tester.renderObject(find.text(longTextA.data!)); expect(itemBoxA.size, equals(const Size(400.0, 14.0))); - final RenderBox itemBoxB = tester.renderObject(find.text(longTextB)); + final RenderBox itemBoxB = tester.renderObject(find.text(longTextB.data!)); expect(itemBoxB.size, equals(const Size(400.0, 14.0))); }); @@ -1379,15 +1379,15 @@ void main() { items: const [ BottomNavigationBarItem( icon: Icon(Icons.ac_unit), - label: 'AC', + title: Text('AC'), ), BottomNavigationBarItem( icon: Icon(Icons.access_alarm), - label: 'Alarm', + title: Text('Alarm'), ), BottomNavigationBarItem( icon: Icon(Icons.hot_tub), - label: 'Hot Tub', + title: Text('Hot Tub'), ), ], ), @@ -1433,15 +1433,15 @@ void main() { items: const [ BottomNavigationBarItem( icon: Icon(Icons.ac_unit), - label: 'AC', + title: Text('AC'), ), BottomNavigationBarItem( icon: Icon(Icons.access_alarm), - label: 'Alarm', + title: Text('Alarm'), ), BottomNavigationBarItem( icon: Icon(Icons.hot_tub), - label: 'Hot Tub', + title: Text('Hot Tub'), ), ], ), @@ -1626,7 +1626,7 @@ void main() { } }); - testWidgets('BottomNavigationBar item label should not be nullable', (WidgetTester tester) async { + testWidgets('BottomNavigationBar item title should not be nullable', (WidgetTester tester) async { expect(() { MaterialApp( home: Scaffold( @@ -1732,11 +1732,11 @@ void main() { items: const [ BottomNavigationBarItem( icon: Icon(Icons.ac_unit), - label: 'Red', + title: Text('Red'), ), BottomNavigationBarItem( icon: Icon(Icons.access_alarm), - label: 'Green', + title: Text('Green'), ), ], ), @@ -1775,11 +1775,11 @@ void main() { items: const [ BottomNavigationBarItem( icon: Icon(Icons.ac_unit), - label: 'Red', + title: Text('Red'), ), BottomNavigationBarItem( icon: Icon(Icons.access_alarm), - label: 'Green', + title: Text('Green'), ), ], ), @@ -1817,8 +1817,8 @@ void main() { child: BottomNavigationBar( mouseCursor: SystemMouseCursors.text, items: const [ - BottomNavigationBarItem(icon: Icon(Icons.ac_unit), label: 'AC'), - BottomNavigationBarItem(icon: Icon(Icons.access_alarm), label: 'Alarm'), + BottomNavigationBarItem(icon: Icon(Icons.ac_unit), title: Text('AC')), + BottomNavigationBarItem(icon: Icon(Icons.access_alarm), title: Text('Alarm')), ], ), ), @@ -1842,8 +1842,8 @@ void main() { cursor: SystemMouseCursors.forbidden, child: BottomNavigationBar( items: const [ - BottomNavigationBarItem(icon: Icon(Icons.ac_unit), label: 'AC'), - BottomNavigationBarItem(icon: Icon(Icons.access_alarm), label: 'Alarm'), + BottomNavigationBarItem(icon: Icon(Icons.ac_unit), title: Text('AC')), + BottomNavigationBarItem(icon: Icon(Icons.access_alarm), title: Text('Alarm')), ], ), ), @@ -1875,8 +1875,8 @@ void main() { child: BottomNavigationBar( enableFeedback: enableFeedback, items: const [ - BottomNavigationBarItem(icon: Icon(Icons.ac_unit), label: 'AC'), - BottomNavigationBarItem(icon: Icon(Icons.access_alarm), label: 'Alarm'), + BottomNavigationBarItem(icon: Icon(Icons.ac_unit), title: Text('AC')), + BottomNavigationBarItem(icon: Icon(Icons.access_alarm), title: Text('Alarm')), ], ), ), @@ -2015,7 +2015,9 @@ void main() { testWidgets('BottomNavigationBar default layout', (WidgetTester tester) async { final Key icon0 = UniqueKey(); + final Key title0 = UniqueKey(); final Key icon1 = UniqueKey(); + final Key title1 = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -2026,11 +2028,11 @@ void main() { items: [ BottomNavigationBarItem( icon: SizedBox(key: icon0, width: 200, height: 10), - label: 'Title0', + title: SizedBox(key: title0, width: 200, height: 10), ), BottomNavigationBarItem( icon: SizedBox(key: icon1, width: 200, height: 10), - label: 'Title1', + title: SizedBox(key: title1, width: 200, height: 10), ), ], ), @@ -2045,24 +2047,25 @@ void main() { // The height of the navigation bar is kBottomNavigationBarHeight = 56 // The top of the navigation bar is 600 - 56 = 544 // The top and bottom of the selected item is defined by its centered icon/label column: - // top = 544 + ((56 - (10 + 10)) / 2) = 562 + // top = 544 - (56 - (10 + 10)) / 2 = 562 // bottom = top + 10 + 10 = 582 - expect(tester.getRect(find.byKey(icon0)).top, 560.0); - expect(tester.getRect(find.text('Title0')).bottom, 584.0); - - // The items are padded horizontally according to - // MainAxisAlignment.spaceAround. Left/right padding is: - // 800 - (200 * 2) / 4 = 100 - // The layout of the unselected item's label is slightly different; not - // checking that here. - expect(tester.getRect(find.text('Title0')), const Rect.fromLTRB(158.0, 570.0, 242.0, 584.0)); - expect(tester.getRect(find.byKey(icon0)), const Rect.fromLTRB(100.0, 560.0, 300.0, 570.0)); - expect(tester.getRect(find.byKey(icon1)), const Rect.fromLTRB(500.0, 560.0, 700.0, 570.0)); + expect(tester.getRect(find.byKey(icon0)).top, 562); + expect(tester.getRect(find.byKey(title0)).bottom, 582); + + // The items are horizontal padded according to + // MainAxisAlignment.spaceBetween Left/right padding is 800 - (200 + // * 4) / 4 = 100. The layout of the unselected item's title is + // slightly different; not checking that here. + expect(tester.getRect(find.byKey(title0)), const Rect.fromLTRB(100, 572, 300, 582)); + expect(tester.getRect(find.byKey(icon0)), const Rect.fromLTRB(100, 562, 300, 572)); + expect(tester.getRect(find.byKey(icon1)), const Rect.fromLTRB(500, 562, 700, 572)); }); testWidgets('BottomNavigationBar centered landscape layout', (WidgetTester tester) async { final Key icon0 = UniqueKey(); + final Key title0 = UniqueKey(); final Key icon1 = UniqueKey(); + final Key title1 = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -2074,11 +2077,11 @@ void main() { items: [ BottomNavigationBarItem( icon: SizedBox(key: icon0, width: 200, height: 10), - label: 'Title0', + title: SizedBox(key: title0, width: 200, height: 10), ), BottomNavigationBarItem( icon: SizedBox(key: icon1, width: 200, height: 10), - label: 'Title1', + title: SizedBox(key: title1, width: 200, height: 10), ), ], ), @@ -2091,23 +2094,22 @@ void main() { expect(tester.getSize(find.byType(BottomNavigationBar)), const Size(800, kBottomNavigationBarHeight)); expect(tester.getRect(find.byType(BottomNavigationBar)), const Rect.fromLTRB(0, 600 - kBottomNavigationBarHeight, 800, 600)); - // The items are laid out as in the default case, within width = 600 + // The items are laid out as in the default case, within width=600 // (the "portrait" width) and the result is centered with the - // landscape width = 800. - // So item 0's left edges are: - // ((800 - 600) / 2) + ((600 - 400) / 4) = 150. - // Item 1's right edge is: - // 800 - 150 = 650 - // The layout of the unselected item's label is slightly different; not - // checking that here. - expect(tester.getRect(find.text('Title0')), const Rect.fromLTRB(208.0, 570.0, 292.0, 584.0)); - expect(tester.getRect(find.byKey(icon0)), const Rect.fromLTRB(150.0, 560.0, 350.0, 570.0)); - expect(tester.getRect(find.byKey(icon1)), const Rect.fromLTRB(450.0, 560.0, 650.0, 570.0)); + // landscape width=800. So item 0's left edges are (800 - 600) / 2 + + // (600 - 400) / 4 = 150. Item 1's right edge is 800 - 150 = + // 650. The layout of the unselected item's title is slightly + // different; not checking that here. + expect(tester.getRect(find.byKey(title0)), const Rect.fromLTRB(150.0, 572.0, 350.0, 582.0)); + expect(tester.getRect(find.byKey(icon0)), const Rect.fromLTRB(150, 562, 350, 572)); + expect(tester.getRect(find.byKey(icon1)), const Rect.fromLTRB(450, 562, 650, 572)); }); testWidgets('BottomNavigationBar linear landscape layout', (WidgetTester tester) async { final Key icon0 = UniqueKey(); + final Key title0 = UniqueKey(); final Key icon1 = UniqueKey(); + final Key title1 = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -2119,11 +2121,11 @@ void main() { items: [ BottomNavigationBarItem( icon: SizedBox(key: icon0, width: 100, height: 20), - label: 'Title0', + title: SizedBox(key: title0, width: 100, height: 20), ), BottomNavigationBarItem( icon: SizedBox(key: icon1, width: 100, height: 20), - label: 'Title1', + title: SizedBox(key: title1, width: 100, height: 20), ), ], ), @@ -2137,12 +2139,12 @@ void main() { expect(tester.getRect(find.byType(BottomNavigationBar)), const Rect.fromLTRB(0, 600 - kBottomNavigationBarHeight, 800, 600)); // The items are laid out as in the default case except each - // item's icon/label is arranged in a row, with 8 pixels in - // between the icon and label. The layout of the unselected - // item's label is slightly different; not checking that here. - expect(tester.getRect(find.text('Title0')), const Rect.fromLTRB(212.0, 565.0, 296.0, 579.0)); - expect(tester.getRect(find.byKey(icon0)), const Rect.fromLTRB(104.0, 562.0, 204.0, 582.0)); - expect(tester.getRect(find.byKey(icon1)), const Rect.fromLTRB(504.0, 562.0, 604.0, 582.0)); + // item's icon/title is arranged in a row, with 8 pixels in + // between the icon and title. The layout of the unselected + // item's title is slightly different; not checking that here. + expect(tester.getRect(find.byKey(title0)), const Rect.fromLTRB(204, 562, 304, 582)); + expect(tester.getRect(find.byKey(icon0)), const Rect.fromLTRB(96, 562, 196, 582)); + expect(tester.getRect(find.byKey(icon1)), const Rect.fromLTRB(496, 562, 596, 582)); }); } diff --git a/packages/flutter/test/material/bottom_sheet_test.dart b/packages/flutter/test/material/bottom_sheet_test.dart index c70848ea4a269..e3a569f771166 100644 --- a/packages/flutter/test/material/bottom_sheet_test.dart +++ b/packages/flutter/test/material/bottom_sheet_test.dart @@ -51,187 +51,6 @@ void main() { FlutterError.onError = handler; }); - testWidgets('Disposing app while bottom sheet is disappearing does not crash', (WidgetTester tester) async { - late BuildContext savedContext; - - await tester.pumpWidget( - MaterialApp( - home: Builder( - builder: (BuildContext context) { - savedContext = context; - return Container(); - }, - ), - ), - ); - - await tester.pump(); - expect(find.text('BottomSheet'), findsNothing); - - // Bring up bottom sheet. - bool showBottomSheetThenCalled = false; - showModalBottomSheet( - context: savedContext, - builder: (BuildContext context) => const Text('BottomSheet'), - ).then((void value) { - showBottomSheetThenCalled = true; - }); - await tester.pumpAndSettle(); - expect(find.text('BottomSheet'), findsOneWidget); - expect(showBottomSheetThenCalled, isFalse); - - // Start closing animation of Bottom sheet. - tester.state(find.byType(Navigator)).pop(); - await tester.pump(); - - // Dispose app by replacing it with a container. This shouldn't crash. - await tester.pumpWidget(Container()); - }); - - - testWidgets('Swiping down a BottomSheet should dismiss it by default', (WidgetTester tester) async { - - final GlobalKey scaffoldKey = GlobalKey(); - bool showBottomSheetThenCalled = false; - - await tester.pumpWidget(MaterialApp( - home: Scaffold( - key: scaffoldKey, - body: const Center(child: Text('body')), - ), - )); - - await tester.pump(); - expect(showBottomSheetThenCalled, isFalse); - expect(find.text('BottomSheet'), findsNothing); - - scaffoldKey.currentState!.showBottomSheet((BuildContext context) { - return const SizedBox( - height: 200.0, - child: Text('BottomSheet'), - ); - }).closed.whenComplete(() { - showBottomSheetThenCalled = true; - }); - - await tester.pumpAndSettle(); - expect(showBottomSheetThenCalled, isFalse); - expect(find.text('BottomSheet'), findsOneWidget); - - // Swipe the bottom sheet to dismiss it. - await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0)); - await tester.pumpAndSettle(); // Bottom sheet dismiss animation. - expect(showBottomSheetThenCalled, isTrue); - expect(find.text('BottomSheet'), findsNothing); - }); - - testWidgets('Swiping down a BottomSheet should not dismiss it when enableDrag is false', (WidgetTester tester) async { - - final GlobalKey scaffoldKey = GlobalKey(); - bool showBottomSheetThenCalled = false; - - await tester.pumpWidget(MaterialApp( - home: Scaffold( - key: scaffoldKey, - body: const Center(child: Text('body')), - ), - )); - - await tester.pump(); - expect(showBottomSheetThenCalled, isFalse); - expect(find.text('BottomSheet'), findsNothing); - - scaffoldKey.currentState!.showBottomSheet((BuildContext context) { - return const SizedBox( - height: 200.0, - child: Text('BottomSheet'), - ); - }, - enableDrag: false - ).closed.whenComplete(() { - showBottomSheetThenCalled = true; - }); - - await tester.pumpAndSettle(); - expect(showBottomSheetThenCalled, isFalse); - expect(find.text('BottomSheet'), findsOneWidget); - - // Swipe the bottom sheet, attempting to dismiss it. - await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0)); - await tester.pumpAndSettle(); // Bottom sheet should not dismiss. - expect(showBottomSheetThenCalled, isFalse); - expect(find.text('BottomSheet'), findsOneWidget); - }); - - testWidgets('Swiping down a BottomSheet should dismiss it when enableDrag is true', (WidgetTester tester) async { - final GlobalKey scaffoldKey = GlobalKey(); - bool showBottomSheetThenCalled = false; - - await tester.pumpWidget(MaterialApp( - home: Scaffold( - key: scaffoldKey, - body: const Center(child: Text('body')), - ), - )); - - await tester.pump(); - expect(showBottomSheetThenCalled, isFalse); - expect(find.text('BottomSheet'), findsNothing); - - scaffoldKey.currentState!.showBottomSheet((BuildContext context) { - return const SizedBox( - height: 200.0, - child: Text('BottomSheet'), - ); - }, - enableDrag: true - ).closed.whenComplete(() { - showBottomSheetThenCalled = true; - }); - - await tester.pumpAndSettle(); - expect(showBottomSheetThenCalled, isFalse); - expect(find.text('BottomSheet'), findsOneWidget); - - // Swipe the bottom sheet to dismiss it. - await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0)); - await tester.pumpAndSettle(); // Bottom sheet dismiss animation. - expect(showBottomSheetThenCalled, isTrue); - expect(find.text('BottomSheet'), findsNothing); - }); - - testWidgets('Modal BottomSheet builder should only be called once', (WidgetTester tester) async { - late BuildContext savedContext; - - await tester.pumpWidget(MaterialApp( - home: Builder( - builder: (BuildContext context) { - savedContext = context; - return Container(); - }, - ), - )); - - int numBuilderCalls = 0; - showModalBottomSheet( - context: savedContext, - isDismissible: false, - enableDrag: true, - builder: (BuildContext context) { - numBuilderCalls++; - return const Text('BottomSheet'); - }, - ); - - await tester.pumpAndSettle(); - expect(numBuilderCalls, 1); - - // Swipe the bottom sheet to dismiss it. - await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0)); - await tester.pumpAndSettle(); // Bottom sheet dismiss animation. - expect(numBuilderCalls, 1); - }); - testWidgets('Tapping on a modal BottomSheet should not dismiss it', (WidgetTester tester) async { late BuildContext savedContext; @@ -1204,58 +1023,6 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Calling PersistentBottomSheetController.close does not crash when it is not the current bottom sheet', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/93717 - PersistentBottomSheetController? sheetController1; - await tester.pumpWidget(MaterialApp( - home: Scaffold( - body: Builder(builder: (BuildContext context) { - return SafeArea( - child: Column( - children: [ - ElevatedButton( - child: const Text('show 1'), - onPressed: () { - sheetController1 = Scaffold.of(context).showBottomSheet( - (BuildContext context) => const Text('BottomSheet 1'), - ); - }, - ), - ElevatedButton( - child: const Text('show 2'), - onPressed: () { - Scaffold.of(context).showBottomSheet( - (BuildContext context) => const Text('BottomSheet 2'), - ); - }, - ), - ElevatedButton( - child: const Text('close 1'), - onPressed: (){ - sheetController1!.close(); - }, - ), - ], - ), - ); - }), - ), - )); - - await tester.tap(find.text('show 1')); - await tester.pumpAndSettle(); - expect(find.text('BottomSheet 1'), findsOneWidget); - - await tester.tap(find.text('show 2')); - await tester.pumpAndSettle(); - expect(find.text('BottomSheet 2'), findsOneWidget); - - // This will throw an assertion if regressed - await tester.tap(find.text('close 1')); - await tester.pumpAndSettle(); - expect(find.text('BottomSheet 2'), findsOneWidget); - }); - group('constraints', () { testWidgets('No constraints by default for bottomSheet property', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/calendar_date_picker_test.dart b/packages/flutter/test/material/calendar_date_picker_test.dart index 2f4dc9499ea15..3a47e27d4ba0f 100644 --- a/packages/flutter/test/material/calendar_date_picker_test.dart +++ b/packages/flutter/test/material/calendar_date_picker_test.dart @@ -577,7 +577,17 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.space); await tester.pumpAndSettle(); - // Should have selected Jan 19. + // Navigate out of the grid and to the OK button. + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pumpAndSettle(); + + // Activate OK. + await tester.sendKeyEvent(LogicalKeyboardKey.space); + await tester.pumpAndSettle(); + + // Should have selected Jan 18. expect(selectedDate, DateTime(2016, DateTime.january, 19)); }); }); @@ -840,7 +850,6 @@ void main() { hasTapAction: true, isSelected: year == 2016, isFocusable: true, - isButton: true, )); } }); diff --git a/packages/flutter/test/material/checkbox_list_tile_test.dart b/packages/flutter/test/material/checkbox_list_tile_test.dart index 89052d5f485e6..6004fd8cc2d9d 100644 --- a/packages/flutter/test/material/checkbox_list_tile_test.dart +++ b/packages/flutter/test/material/checkbox_list_tile_test.dart @@ -321,45 +321,6 @@ void main() { expect(textColor('title'), activeColor); }); - testWidgets('CheckboxListTile respects checkbox side', (WidgetTester tester) async { - Widget buildApp(BorderSide side) { - return MaterialApp( - home: Material( - child: Center( - child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { - return CheckboxListTile( - value: false, - onChanged: (bool? newValue) {}, - side: side, - ); - }), - ), - ), - ); - } - const BorderSide side1 = BorderSide( - color: Color(0xfff44336), - ); - await tester.pumpWidget(buildApp(side1)); - expect(tester.widget(find.byType(CheckboxListTile)).side, side1); - expect(tester.widget(find.byType(Checkbox)).side, side1); - expect( - Material.of(tester.element(find.byType(Checkbox))), - paints - ..drrect(color: const Color(0xfff44336)), - ); - const BorderSide side2 = BorderSide( - color: Color(0xff424242), - ); - await tester.pumpWidget(buildApp(side2)); - expect(tester.widget(find.byType(Checkbox)).side, side2); - expect( - Material.of(tester.element(find.byType(Checkbox))), - paints - ..drrect(color: const Color(0xff424242)), - ); - }); - testWidgets('CheckboxListTile respects visualDensity', (WidgetTester tester) async { const Key key = Key('test'); Future buildTest(VisualDensity visualDensity) async { diff --git a/packages/flutter/test/material/checkbox_test.dart b/packages/flutter/test/material/checkbox_test.dart index 2845fab5851b1..cc4d9ee5aaac7 100644 --- a/packages/flutter/test/material/checkbox_test.dart +++ b/packages/flutter/test/material/checkbox_test.dart @@ -1077,7 +1077,6 @@ void main() { } return inactivePressedOverlayColor; } - return null; } const double splashRadius = 24.0; TestGesture gesture; diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 90a3f7a1cc725..6fbe9655430ed 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -15,7 +15,7 @@ import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; Finder findRenderChipElement() { - return find.byElementPredicate((Element e) => '${e.renderObject.runtimeType}' == '_RenderChip'); + return find.byElementPredicate((Element e) => '${e.runtimeType}' == '_RenderChipElement'); } RenderBox getMaterialBox(WidgetTester tester) { @@ -46,12 +46,12 @@ IconThemeData getIconData(WidgetTester tester) { return iconTheme.data; } -DefaultTextStyle getLabelStyle(WidgetTester tester, String labelText) { +DefaultTextStyle getLabelStyle(WidgetTester tester) { return tester.widget( - find.ancestor( - of: find.text(labelText), + find.descendant( + of: find.byType(RawChip), matching: find.byType(DefaultTextStyle), - ).first, + ).last, ); } @@ -270,116 +270,6 @@ Finder findTooltipContainer(String tooltipText) { } void main() { - testWidgets('Chip defaults', (WidgetTester tester) async { - late TextTheme textTheme; - - Widget buildFrame(Brightness brightness) { - return MaterialApp( - theme: ThemeData(brightness: brightness), - home: Scaffold( - body: Center( - child: Builder( - builder: (BuildContext context) { - textTheme = Theme.of(context).textTheme; - return Chip( - avatar: const CircleAvatar(child: Text('A')), - label: const Text('Chip A'), - onDeleted: () { }, - ); - }, - ), - ), - ), - ); - } - - await tester.pumpWidget(buildFrame(Brightness.light)); - expect(getMaterialBox(tester), paints..path(color: const Color(0x1f000000))); - expect(tester.getSize(find.byType(Chip)), const Size(156.0, 48.0)); - expect(getMaterial(tester).color, null); - expect(getMaterial(tester).elevation, 0); - expect(getMaterial(tester).shape, const StadiumBorder()); - expect(getIconData(tester).color?.value, 0xffffffff); - expect(getIconData(tester).opacity, null); - expect(getIconData(tester).size, null); - - TextStyle labelStyle = getLabelStyle(tester, 'Chip A').style; - expect(labelStyle.color?.value, 0xde000000); - expect(labelStyle.fontFamily, textTheme.bodyText1?.fontFamily); - expect(labelStyle.fontFamilyFallback, textTheme.bodyText1?.fontFamilyFallback); - expect(labelStyle.fontFeatures, textTheme.bodyText1?.fontFeatures); - expect(labelStyle.fontSize, textTheme.bodyText1?.fontSize); - expect(labelStyle.fontStyle, textTheme.bodyText1?.fontStyle); - expect(labelStyle.fontWeight, textTheme.bodyText1?.fontWeight); - expect(labelStyle.height, textTheme.bodyText1?.height); - expect(labelStyle.inherit, textTheme.bodyText1?.inherit); - expect(labelStyle.leadingDistribution, textTheme.bodyText1?.leadingDistribution); - expect(labelStyle.letterSpacing, textTheme.bodyText1?.letterSpacing); - expect(labelStyle.overflow, textTheme.bodyText1?.overflow); - expect(labelStyle.textBaseline, textTheme.bodyText1?.textBaseline); - expect(labelStyle.wordSpacing, textTheme.bodyText1?.wordSpacing); - - await tester.pumpWidget(buildFrame(Brightness.dark)); - await tester.pumpAndSettle(); // Theme transition animation - expect(getMaterialBox(tester), paints..path(color: const Color(0x1fffffff))); - expect(tester.getSize(find.byType(Chip)), const Size(156.0, 48.0)); - expect(getMaterial(tester).color, null); - expect(getMaterial(tester).elevation, 0); - expect(getMaterial(tester).shape, const StadiumBorder()); - expect(getIconData(tester).color?.value, 0xffffffff); - expect(getIconData(tester).opacity, null); - expect(getIconData(tester).size, null); - - labelStyle = getLabelStyle(tester, 'Chip A').style; - expect(labelStyle.color?.value, 0xdeffffff); - expect(labelStyle.fontFamily, textTheme.bodyText1?.fontFamily); - expect(labelStyle.fontFamilyFallback, textTheme.bodyText1?.fontFamilyFallback); - expect(labelStyle.fontFeatures, textTheme.bodyText1?.fontFeatures); - expect(labelStyle.fontSize, textTheme.bodyText1?.fontSize); - expect(labelStyle.fontStyle, textTheme.bodyText1?.fontStyle); - expect(labelStyle.fontWeight, textTheme.bodyText1?.fontWeight); - expect(labelStyle.height, textTheme.bodyText1?.height); - expect(labelStyle.inherit, textTheme.bodyText1?.inherit); - expect(labelStyle.leadingDistribution, textTheme.bodyText1?.leadingDistribution); - expect(labelStyle.letterSpacing, textTheme.bodyText1?.letterSpacing); - expect(labelStyle.overflow, textTheme.bodyText1?.overflow); - expect(labelStyle.textBaseline, textTheme.bodyText1?.textBaseline); - expect(labelStyle.wordSpacing, textTheme.bodyText1?.wordSpacing); - }); - - testWidgets('ChoiceChip defaults', (WidgetTester tester) async { - Widget buildFrame(Brightness brightness) { - return MaterialApp( - theme: ThemeData(brightness: brightness), - home: const Scaffold( - body: Center( - child: ChoiceChip( - label: Text('Chip A'), - selected: true, - ), - ), - ), - ); - } - - await tester.pumpWidget(buildFrame(Brightness.light)); - expect(getMaterialBox(tester), paints..path(color: const Color(0x3d000000))); - expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0)); - expect(getMaterial(tester).color, null); - expect(getMaterial(tester).elevation, 0); - expect(getMaterial(tester).shape, const StadiumBorder()); - expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xde000000); - - await tester.pumpWidget(buildFrame(Brightness.dark)); - await tester.pumpAndSettle(); // Theme transition animation - expect(getMaterialBox(tester), paints..path(color: const Color(0x3dffffff))); - expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0)); - expect(getMaterial(tester).color, null); - expect(getMaterial(tester).elevation, 0); - expect(getMaterial(tester).shape, const StadiumBorder()); - expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xdeffffff); - }); - testWidgets('Chip control test', (WidgetTester tester) async { final FeedbackTester feedback = FeedbackTester(); final List deletedChipLabels = []; @@ -1761,56 +1651,11 @@ void main() { await tester.pumpWidget(buildChip()); - final TextStyle labelStyle = getLabelStyle(tester, 'Label').style; - expect(labelStyle.inherit, false); + final TextStyle labelStyle = getLabelStyle(tester).style; expect(labelStyle.fontFamily, 'MyFont'); expect(labelStyle.fontWeight, FontWeight.w200); }); - testWidgets('ChipTheme labelStyle with inherit:true', (WidgetTester tester) async { - Widget buildChip() { - return _wrapForChip( - child: Theme( - data: ThemeData.light().copyWith( - chipTheme: const ChipThemeData( - labelStyle: TextStyle(height: 4), // inherit: true - ), - ), - child: const Chip(label: Text('Label')), // labeStyle: null - ), - ); - } - - await tester.pumpWidget(buildChip()); - final TextStyle labelStyle = getLabelStyle(tester, 'Label').style; - expect(labelStyle.inherit, true); // because chipTheme.labelStyle.merge(null) - expect(labelStyle.height, 4); - }); - - testWidgets('Chip does not merge inherit:false label style with the theme label style', (WidgetTester tester) async { - Widget buildChip() { - return _wrapForChip( - child: Theme( - data: ThemeData(fontFamily: 'MyFont'), - child: const DefaultTextStyle( - style: TextStyle(height: 8), - child: Chip( - label: Text('Label'), - labelStyle: TextStyle(fontWeight: FontWeight.w200, inherit: false), - ), - ), - ), - ); - } - - await tester.pumpWidget(buildChip()); - final TextStyle labelStyle = getLabelStyle(tester, 'Label').style; - expect(labelStyle.inherit, false); - expect(labelStyle.fontFamily, null); - expect(labelStyle.height, null); - expect(labelStyle.fontWeight, FontWeight.w200); - }); - testWidgets('Chip size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { final Key key1 = UniqueKey(); await tester.pumpWidget( @@ -1852,11 +1697,7 @@ void main() { platform: TargetPlatform.android, primarySwatch: Colors.blue, ); - final ChipThemeData defaultChipTheme = ChipThemeData.fromDefaults( - brightness: themeData.brightness, - secondaryColor: Colors.blue, - labelStyle: themeData.textTheme.bodyText1!, - ); + final ChipThemeData defaultChipTheme = themeData.chipTheme; bool value = false; Widget buildApp({ ChipThemeData? chipTheme, @@ -1908,7 +1749,7 @@ void main() { RenderBox materialBox = getMaterialBox(tester); IconThemeData iconData = getIconData(tester); - DefaultTextStyle labelStyle = getLabelStyle(tester, 'false'); + DefaultTextStyle labelStyle = getLabelStyle(tester); // Check default theme for enabled widget. expect(materialBox, paints..path(color: defaultChipTheme.backgroundColor)); @@ -1925,7 +1766,7 @@ void main() { await tester.pumpWidget(buildApp(isSelectable: false)); await tester.pumpAndSettle(); materialBox = getMaterialBox(tester); - labelStyle = getLabelStyle(tester, 'false'); + labelStyle = getLabelStyle(tester); expect(materialBox, paints..path(color: defaultChipTheme.disabledColor)); expect(labelStyle.style.color, equals(Colors.black.withAlpha(0xde))); @@ -1945,7 +1786,7 @@ void main() { await tester.pumpAndSettle(); materialBox = getMaterialBox(tester); iconData = getIconData(tester); - labelStyle = getLabelStyle(tester, 'false'); + labelStyle = getLabelStyle(tester); // Check custom theme for enabled widget. expect(materialBox, paints..path(color: customTheme.backgroundColor)); @@ -1965,7 +1806,7 @@ void main() { )); await tester.pumpAndSettle(); materialBox = getMaterialBox(tester); - labelStyle = getLabelStyle(tester, 'false'); + labelStyle = getLabelStyle(tester); expect(materialBox, paints..path(color: customTheme.disabledColor)); expect(labelStyle.style.color, equals(Colors.black.withAlpha(0xde))); }); diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index b805e86dbf9ce..2fbdd7792c21f 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -39,267 +39,130 @@ IconThemeData getIconData(WidgetTester tester) { DefaultTextStyle getLabelStyle(WidgetTester tester) { return tester.widget( - find.descendant( - of: find.byType(RawChip), - matching: find.byType(DefaultTextStyle), - ).last, + find + .descendant( + of: find.byType(RawChip), + matching: find.byType(DefaultTextStyle), + ) + .last, ); } void main() { - test('ChipThemeData copyWith, ==, hashCode basics', () { - expect(const ChipThemeData(), const ChipThemeData().copyWith()); - expect(const ChipThemeData().hashCode, const ChipThemeData().copyWith().hashCode); - }); - - test('ChipThemeData defaults', () { - const ChipThemeData themeData = ChipThemeData(); - expect(themeData.backgroundColor, null); - expect(themeData.deleteIconColor, null); - expect(themeData.disabledColor, null); - expect(themeData.selectedColor, null); - expect(themeData.secondarySelectedColor, null); - expect(themeData.shadowColor, null); - expect(themeData.selectedShadowColor, null); - expect(themeData.showCheckmark, null); - expect(themeData.checkmarkColor, null); - expect(themeData.labelPadding, null); - expect(themeData.padding, null); - expect(themeData.side, null); - expect(themeData.shape, null); - expect(themeData.labelStyle, null); - expect(themeData.secondaryLabelStyle, null); - expect(themeData.brightness, null); - expect(themeData.elevation, null); - expect(themeData.pressElevation, null); - }); - - testWidgets('Default ChipThemeData debugFillProperties', (WidgetTester tester) async { - final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - const ChipThemeData().debugFillProperties(builder); - - final List description = builder.properties - .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) - .map((DiagnosticsNode node) => node.toString()) - .toList(); + testWidgets('Chip theme is built by ThemeData', (WidgetTester tester) async { + final ThemeData theme = ThemeData( + platform: TargetPlatform.android, + primarySwatch: Colors.red, + ); + final ChipThemeData chipTheme = theme.chipTheme; - expect(description, []); + expect(chipTheme.backgroundColor, equals(Colors.black.withAlpha(0x1f))); + expect(chipTheme.selectedColor, equals(Colors.black.withAlpha(0x3d))); + expect(chipTheme.secondarySelectedColor, equals(Colors.red.withAlpha(0x3d))); + expect(chipTheme.deleteIconColor, equals(Colors.black.withAlpha(0xde))); }); - testWidgets('ChipThemeData implements debugFillProperties', (WidgetTester tester) async { - final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - const ChipThemeData( - backgroundColor: Color(0xfffffff0), - deleteIconColor: Color(0xfffffff1), - disabledColor: Color(0xfffffff2), - selectedColor: Color(0xfffffff3), - secondarySelectedColor: Color(0xfffffff4), - shadowColor: Color(0xfffffff5), - selectedShadowColor: Color(0xfffffff6), - showCheckmark: true, - checkmarkColor: Color(0xfffffff7), - labelPadding: EdgeInsets.all(1), - padding: EdgeInsets.all(2), - side: BorderSide(width: 10), - shape: RoundedRectangleBorder(), - labelStyle: TextStyle(fontSize: 10), - secondaryLabelStyle: TextStyle(fontSize: 20), + testWidgets('Chip theme is built by ThemeData with dark mode enabled', (WidgetTester tester) async { + final ThemeData theme = ThemeData( + platform: TargetPlatform.android, brightness: Brightness.dark, - elevation: 5, - pressElevation: 6, - ).debugFillProperties(builder); - - final List description = builder.properties - .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) - .map((DiagnosticsNode node) => node.toString()) - .toList(); - - expect(description, [ - 'backgroundColor: Color(0xfffffff0)', - 'deleteIconColor: Color(0xfffffff1)', - 'disabledColor: Color(0xfffffff2)', - 'selectedColor: Color(0xfffffff3)', - 'secondarySelectedColor: Color(0xfffffff4)', - 'shadowColor: Color(0xfffffff5)', - 'selectedShadowColor: Color(0xfffffff6)', - 'checkMarkColor: Color(0xfffffff7)', - 'labelPadding: EdgeInsets.all(1.0)', - 'padding: EdgeInsets.all(2.0)', - 'side: BorderSide(Color(0xff000000), 10.0, BorderStyle.solid)', - 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)', - 'labelStyle: TextStyle(inherit: true, size: 10.0)', - 'secondaryLabelStyle: TextStyle(inherit: true, size: 20.0)', - 'brightness: dark', - 'elevation: 5.0', - 'pressElevation: 6.0', - ]); + ); + final ChipThemeData chipTheme = theme.chipTheme; + + expect(chipTheme.backgroundColor, equals(Colors.white.withAlpha(0x1f))); + expect(chipTheme.selectedColor, equals(Colors.white.withAlpha(0x3d))); + expect(chipTheme.secondarySelectedColor, equals(Colors.tealAccent[200]!.withAlpha(0x3d))); + expect(chipTheme.deleteIconColor, equals(Colors.white.withAlpha(0xde))); }); - testWidgets('Chip uses ThemeData chip theme', (WidgetTester tester) async { - const ChipThemeData chipTheme = ChipThemeData( - backgroundColor: Color(0xff112233), - elevation: 4, - padding: EdgeInsets.all(50), - labelPadding: EdgeInsets.all(25), - shape: RoundedRectangleBorder(), - labelStyle: TextStyle(fontSize: 32), + testWidgets('Chip uses ThemeData chip theme if present', (WidgetTester tester) async { + final ThemeData theme = ThemeData( + platform: TargetPlatform.android, + primarySwatch: Colors.red, + backgroundColor: Colors.blue, ); + final ChipThemeData chipTheme = theme.chipTheme; - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.light().copyWith( - chipTheme: chipTheme, - ), + Widget buildChip(ChipThemeData data) { + return MaterialApp( + locale: const Locale('en', 'us'), home: Directionality( textDirection: TextDirection.ltr, child: Material( child: Center( - child: RawChip( - label: const SizedBox(width: 100, height: 100), - onSelected: (bool newValue) { }, + child: Theme( + data: theme, + child: RawChip( + onDeleted: () { }, + avatar: const Placeholder(), + deleteIcon: const Placeholder(), + label: const Text('Chip'), + onSelected: (bool newValue) { }, + ), ), ), ), ), - ), - ); + ); + } + + await tester.pumpWidget(buildChip(chipTheme)); + await tester.pumpAndSettle(); final RenderBox materialBox = getMaterialBox(tester); + expect(materialBox, paints..path(color: chipTheme.backgroundColor)); - expect(getMaterial(tester).elevation, chipTheme.elevation); - expect(tester.getSize(find.byType(RawChip)), const Size(250, 250)); // label + padding + labelPadding - expect(getMaterial(tester).shape, chipTheme.shape); - expect(getLabelStyle(tester).style.fontSize, 32); }); - testWidgets('Chip uses ChipTheme', (WidgetTester tester) async { - const ChipThemeData chipTheme = ChipThemeData( - backgroundColor: Color(0xff112233), - elevation: 4, - padding: EdgeInsets.all(50), - labelPadding: EdgeInsets.all(25), - labelStyle: TextStyle(fontSize: 32), - shape: RoundedRectangleBorder(), + testWidgets('Chip overrides ThemeData theme if ChipTheme present', (WidgetTester tester) async { + final ThemeData theme = ThemeData( + platform: TargetPlatform.android, + primarySwatch: Colors.red, ); - - const ChipThemeData shadowedChipTheme = ChipThemeData( - backgroundColor: Color(0xff332211), - elevation: 3, - padding: EdgeInsets.all(5), - labelPadding: EdgeInsets.all(10), - labelStyle: TextStyle(fontSize: 64), - shape: CircleBorder(), + final ChipThemeData chipTheme = theme.chipTheme; + final ChipThemeData customTheme = chipTheme.copyWith( + backgroundColor: Colors.purple, + deleteIconColor: Colors.purple.withAlpha(0x3d), + elevation: 3.0, + shadowColor: Colors.pink, ); - - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.light().copyWith( - chipTheme: shadowedChipTheme, - ), - home: ChipTheme( - data: chipTheme, - child: Builder( - builder: (BuildContext context) { - return Directionality( - textDirection: TextDirection.ltr, - child: Material( - child: Center( - child: RawChip( - label: const SizedBox(width: 100, height: 100), - onSelected: (bool newValue) { }, - ), + const bool value = false; + Widget buildChip(ChipThemeData data) { + return MaterialApp( + home: Directionality( + textDirection: TextDirection.ltr, + child: Material( + child: Center( + child: Theme( + data: theme, + child: ChipTheme( + data: customTheme, + child: RawChip( + onDeleted: () { }, + avatar: const Placeholder(), + deleteIcon: const Placeholder(), + label: const Text('$value'), + onSelected: (bool newValue) { }, ), ), - ); - }, + ), + ), ), ), - ), - ); - - final RenderBox materialBox = getMaterialBox(tester); - expect(materialBox, paints..path(color: chipTheme.backgroundColor)); - expect(tester.getSize(find.byType(RawChip)), const Size(250, 250)); // label + padding + labelPadding - expect(getMaterial(tester).elevation, chipTheme.elevation); - expect(getMaterial(tester).shape, chipTheme.shape); - expect(getLabelStyle(tester).style.fontSize, 32); - }); - - testWidgets('Chip uses constructor parameters', (WidgetTester tester) async { - const ChipThemeData shadowedChipTheme = ChipThemeData( - backgroundColor: Color(0xff112233), - elevation: 4, - padding: EdgeInsets.all(5), - labelPadding: EdgeInsets.all(2), - labelStyle: TextStyle(), - shape: RoundedRectangleBorder(), - ); + ); + } - const Color backgroundColor = Color(0xff332211); - const double elevation = 3; - const double fontSize = 32; - const OutlinedBorder shape = CircleBorder(); - - await tester.pumpWidget( - MaterialApp( - home: ChipTheme( - data: shadowedChipTheme, - child: Builder( - builder: (BuildContext context) { - return Directionality( - textDirection: TextDirection.ltr, - child: Material( - child: Center( - child: RawChip( - backgroundColor: backgroundColor, - elevation: elevation, - padding: const EdgeInsets.all(50), - labelPadding:const EdgeInsets.all(25), - labelStyle: const TextStyle(fontSize: fontSize), - shape: shape, - label: const SizedBox(width: 100, height: 100), - onSelected: (bool newValue) { }, - ), - ), - ), - ); - }, - ), - ), - ), - ); + await tester.pumpWidget(buildChip(chipTheme)); + await tester.pumpAndSettle(); final RenderBox materialBox = getMaterialBox(tester); - expect(materialBox, paints..path(color: backgroundColor)); - expect(tester.getSize(find.byType(RawChip)), const Size(250, 250)); // label + padding + labelPadding - expect(getMaterial(tester).elevation, elevation); - expect(getMaterial(tester).shape, shape); - expect(getLabelStyle(tester).style.fontSize, 32); - }); - - testWidgets('ChipTheme.fromDefaults', (WidgetTester tester) async { - ChipThemeData chipTheme = ChipThemeData.fromDefaults( - brightness: Brightness.light, - secondaryColor: Colors.red, - labelStyle: const TextStyle(), - ); - expect(chipTheme.backgroundColor, equals(Colors.black.withAlpha(0x1f))); - expect(chipTheme.selectedColor, equals(Colors.black.withAlpha(0x3d))); - expect(chipTheme.secondarySelectedColor, equals(Colors.red.withAlpha(0x3d))); - expect(chipTheme.deleteIconColor, equals(Colors.black.withAlpha(0xde))); + final Material material = getMaterial(tester); - chipTheme = ChipThemeData.fromDefaults( - brightness: Brightness.dark, - secondaryColor: Colors.tealAccent[200]!, - labelStyle: const TextStyle(), - ); - expect(chipTheme.backgroundColor, equals(Colors.white.withAlpha(0x1f))); - expect(chipTheme.selectedColor, equals(Colors.white.withAlpha(0x3d))); - expect(chipTheme.secondarySelectedColor, equals(Colors.tealAccent[200]!.withAlpha(0x3d))); - expect(chipTheme.deleteIconColor, equals(Colors.white.withAlpha(0xde))); + expect(materialBox, paints..path(color: Color(customTheme.backgroundColor.value))); + expect(material.elevation, customTheme.elevation); + expect(material.shadowColor, customTheme.shadowColor); }); - testWidgets('ChipThemeData generates correct opacities for defaults', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); @@ -320,8 +183,8 @@ void main() { expect(lightTheme.padding, equals(const EdgeInsets.all(4.0))); expect(lightTheme.side, isNull); expect(lightTheme.shape, isNull); - expect(lightTheme.labelStyle?.color, equals(Colors.black.withAlpha(0xde))); - expect(lightTheme.secondaryLabelStyle?.color, equals(customColor1.withAlpha(0xde))); + expect(lightTheme.labelStyle.color, equals(Colors.black.withAlpha(0xde))); + expect(lightTheme.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde))); expect(lightTheme.brightness, equals(Brightness.light)); final ChipThemeData darkTheme = ChipThemeData.fromDefaults( @@ -339,8 +202,8 @@ void main() { expect(darkTheme.padding, equals(const EdgeInsets.all(4.0))); expect(darkTheme.side, isNull); expect(darkTheme.shape, isNull); - expect(darkTheme.labelStyle?.color, equals(Colors.white.withAlpha(0xde))); - expect(darkTheme.secondaryLabelStyle?.color, equals(customColor1.withAlpha(0xde))); + expect(darkTheme.labelStyle.color, equals(Colors.white.withAlpha(0xde))); + expect(darkTheme.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde))); expect(darkTheme.brightness, equals(Brightness.dark)); final ChipThemeData customTheme = ChipThemeData.fromDefaults( @@ -349,7 +212,7 @@ void main() { labelStyle: customStyle, ); - //expect(customTheme.backgroundColor, equals(customColor1.withAlpha(0x1f))); + expect(customTheme.backgroundColor, equals(customColor1.withAlpha(0x1f))); expect(customTheme.deleteIconColor, equals(customColor1.withAlpha(0xde))); expect(customTheme.disabledColor, equals(customColor1.withAlpha(0x0c))); expect(customTheme.selectedColor, equals(customColor1.withAlpha(0x3d))); @@ -358,8 +221,8 @@ void main() { expect(customTheme.padding, equals(const EdgeInsets.all(4.0))); expect(customTheme.side, isNull); expect(customTheme.shape, isNull); - expect(customTheme.labelStyle?.color, equals(customColor1.withAlpha(0xde))); - expect(customTheme.secondaryLabelStyle?.color, equals(customColor2.withAlpha(0xde))); + expect(customTheme.labelStyle.color, equals(customColor1.withAlpha(0xde))); + expect(customTheme.secondaryLabelStyle.color, equals(customColor2.withAlpha(0xde))); expect(customTheme.brightness, equals(Brightness.light)); }); @@ -407,8 +270,8 @@ void main() { expect(lerp.padding, equals(const EdgeInsets.all(3.0))); expect(lerp.side!.color, equals(middleGrey)); expect(lerp.shape, isA()); - expect(lerp.labelStyle?.color, equals(middleGrey.withAlpha(0xde))); - expect(lerp.secondaryLabelStyle?.color, equals(middleGrey.withAlpha(0xde))); + expect(lerp.labelStyle.color, equals(middleGrey.withAlpha(0xde))); + expect(lerp.secondaryLabelStyle.color, equals(middleGrey.withAlpha(0xde))); expect(lerp.brightness, equals(Brightness.light)); expect(lerp.elevation, 3.0); expect(lerp.pressElevation, 7.0); @@ -428,8 +291,8 @@ void main() { expect(lerpANull25.padding, equals(const EdgeInsets.all(0.5))); expect(lerpANull25.side!.color, equals(Colors.white.withAlpha(0x3f))); expect(lerpANull25.shape, isA()); - expect(lerpANull25.labelStyle?.color, equals(Colors.black.withAlpha(0x38))); - expect(lerpANull25.secondaryLabelStyle?.color, equals(Colors.white.withAlpha(0x38))); + expect(lerpANull25.labelStyle.color, equals(Colors.black.withAlpha(0x38))); + expect(lerpANull25.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0x38))); expect(lerpANull25.brightness, equals(Brightness.light)); expect(lerpANull25.elevation, 1.25); expect(lerpANull25.pressElevation, 2.5); @@ -447,8 +310,8 @@ void main() { expect(lerpANull75.padding, equals(const EdgeInsets.all(1.5))); expect(lerpANull75.side!.color, equals(Colors.white.withAlpha(0xbf))); expect(lerpANull75.shape, isA()); - expect(lerpANull75.labelStyle?.color, equals(Colors.black.withAlpha(0xa7))); - expect(lerpANull75.secondaryLabelStyle?.color, equals(Colors.white.withAlpha(0xa7))); + expect(lerpANull75.labelStyle.color, equals(Colors.black.withAlpha(0xa7))); + expect(lerpANull75.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0xa7))); expect(lerpANull75.brightness, equals(Brightness.light)); expect(lerpANull75.elevation, 3.75); expect(lerpANull75.pressElevation, 7.5); @@ -466,8 +329,8 @@ void main() { expect(lerpBNull25.padding, equals(const EdgeInsets.all(3.0))); expect(lerpBNull25.side!.color, equals(Colors.black.withAlpha(0x3f))); expect(lerpBNull25.shape, isA()); - expect(lerpBNull25.labelStyle?.color, equals(Colors.white.withAlpha(0xa7))); - expect(lerpBNull25.secondaryLabelStyle?.color, equals(Colors.black.withAlpha(0xa7))); + expect(lerpBNull25.labelStyle.color, equals(Colors.white.withAlpha(0xa7))); + expect(lerpBNull25.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0xa7))); expect(lerpBNull25.brightness, equals(Brightness.dark)); expect(lerpBNull25.elevation, 0.75); expect(lerpBNull25.pressElevation, 3.0); @@ -485,8 +348,8 @@ void main() { expect(lerpBNull75.padding, equals(const EdgeInsets.all(1.0))); expect(lerpBNull75.side!.color, equals(Colors.black.withAlpha(0xbf))); expect(lerpBNull75.shape, isA()); - expect(lerpBNull75.labelStyle?.color, equals(Colors.white.withAlpha(0x38))); - expect(lerpBNull75.secondaryLabelStyle?.color, equals(Colors.black.withAlpha(0x38))); + expect(lerpBNull75.labelStyle.color, equals(Colors.white.withAlpha(0x38))); + expect(lerpBNull75.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0x38))); expect(lerpBNull75.brightness, equals(Brightness.light)); expect(lerpBNull75.elevation, 0.25); expect(lerpBNull75.pressElevation, 1.0); @@ -632,22 +495,20 @@ void main() { BorderSide getBorderSide(Set states) { Color color = defaultColor; + if (states.contains(MaterialState.selected)) color = selectedColor; + return BorderSide(color: color); } - final ChipThemeData chipTheme = ChipThemeData.fromDefaults( - brightness: Brightness.light, - secondaryColor: Colors.blue, - labelStyle: const TextStyle(), - ).copyWith( - side: _MaterialStateBorderSide(getBorderSide), - ); - Widget chipWidget({ bool selected = false }) { return MaterialApp( - theme: ThemeData(chipTheme: chipTheme), + theme: ThemeData( + chipTheme: ThemeData.light().chipTheme.copyWith( + side: _MaterialStateBorderSide(getBorderSide), + ), + ), home: Scaffold( body: ChoiceChip( label: const Text('Chip'), @@ -675,18 +536,13 @@ void main() { return null; } - final ChipThemeData chipTheme = ChipThemeData.fromDefaults( - brightness: Brightness.light, - secondaryColor: Colors.blue, - labelStyle: const TextStyle(), - ).copyWith( - shape: _MaterialStateOutlinedBorder(getShape), - ); - - Widget chipWidget({ bool selected = false }) { return MaterialApp( - theme: ThemeData(chipTheme: chipTheme), + theme: ThemeData( + chipTheme: ThemeData.light().chipTheme.copyWith( + shape: _MaterialStateOutlinedBorder(getShape), + ), + ), home: Scaffold( body: ChoiceChip( label: const Text('Chip'), diff --git a/packages/flutter/test/material/circle_avatar_test.dart b/packages/flutter/test/material/circle_avatar_test.dart index cfeb97742a575..19015f9f3daa0 100644 --- a/packages/flutter/test/material/circle_avatar_test.dart +++ b/packages/flutter/test/material/circle_avatar_test.dart @@ -5,6 +5,7 @@ // This file is run as part of a reduced test set in CI on Mac and Windows // machines. @Tags(['reduced-test-set']) + import 'dart:typed_data'; import 'package:flutter/material.dart'; diff --git a/packages/flutter/test/material/color_scheme_test.dart b/packages/flutter/test/material/color_scheme_test.dart index ded927ca83486..2e2ea20a5f4b0 100644 --- a/packages/flutter/test/material/color_scheme_test.dart +++ b/packages/flutter/test/material/color_scheme_test.dart @@ -9,291 +9,76 @@ void main() { test('light scheme matches the spec', () { // Colors should match the Material Design baseline default theme: // https://material.io/design/color/dark-theme.html#ui-application - // with the new Material 3 colors defaulting to values from the M2 - // baseline. const ColorScheme scheme = ColorScheme.light(); - expect(scheme.brightness, Brightness.light); expect(scheme.primary, const Color(0xff6200ee)); - expect(scheme.onPrimary, const Color(0xffffffff)); - expect(scheme.primaryContainer, scheme.primary); - expect(scheme.onPrimaryContainer, scheme.onPrimary); + expect(scheme.primaryVariant, const Color(0xff3700b3)); expect(scheme.secondary, const Color(0xff03dac6)); - expect(scheme.onSecondary, const Color(0xff000000)); - expect(scheme.secondaryContainer, scheme.secondary); - expect(scheme.onSecondaryContainer, scheme.onSecondary); - expect(scheme.tertiary, scheme.secondary); - expect(scheme.onTertiary, scheme.onSecondary); - expect(scheme.tertiaryContainer, scheme.tertiary); - expect(scheme.onTertiaryContainer, scheme.onTertiary); - expect(scheme.error, const Color(0xffb00020)); - expect(scheme.onError, const Color(0xffffffff)); - expect(scheme.errorContainer, scheme.error); - expect(scheme.onErrorContainer, scheme.onError); + expect(scheme.secondaryVariant, const Color(0xff018786)); expect(scheme.background, const Color(0xffffffff)); - expect(scheme.onBackground, const Color(0xff000000)); expect(scheme.surface, const Color(0xffffffff)); + expect(scheme.error, const Color(0xffb00020)); + expect(scheme.onPrimary, const Color(0xffffffff)); + expect(scheme.onSecondary, const Color(0xff000000)); + expect(scheme.onBackground, const Color(0xff000000)); expect(scheme.onSurface, const Color(0xff000000)); - expect(scheme.surfaceVariant, scheme.surface); - expect(scheme.onSurfaceVariant, scheme.onSurface); - expect(scheme.outline, scheme.onBackground); - expect(scheme.shadow, scheme.onBackground); - expect(scheme.inverseSurface, scheme.onSurface); - expect(scheme.onInverseSurface, scheme.surface); - expect(scheme.inversePrimary, scheme.onPrimary); - - expect(scheme.primaryVariant, const Color(0xff3700b3)); - expect(scheme.secondaryVariant, const Color(0xff018786)); + expect(scheme.onError, const Color(0xffffffff)); + expect(scheme.brightness, Brightness.light); }); test('dark scheme matches the spec', () { // Colors should match the Material Design baseline dark theme: // https://material.io/design/color/dark-theme.html#ui-application - // with the new Material 3 colors defaulting to values from the M2 - // baseline. const ColorScheme scheme = ColorScheme.dark(); - expect(scheme.brightness, Brightness.dark); expect(scheme.primary, const Color(0xffbb86fc)); - expect(scheme.onPrimary, const Color(0xff000000)); - expect(scheme.primaryContainer, scheme.primary); - expect(scheme.onPrimaryContainer, scheme.onPrimary); + expect(scheme.primaryVariant, const Color(0xff3700b3)); expect(scheme.secondary, const Color(0xff03dac6)); - expect(scheme.onSecondary, const Color(0xff000000)); - expect(scheme.secondaryContainer, scheme.secondary); - expect(scheme.onSecondaryContainer, scheme.onSecondary); - expect(scheme.tertiary, scheme.secondary); - expect(scheme.onTertiary, scheme.onSecondary); - expect(scheme.tertiaryContainer, scheme.tertiary); - expect(scheme.onTertiaryContainer, scheme.onTertiary); - expect(scheme.error, const Color(0xffcf6679)); - expect(scheme.onError, const Color(0xff000000)); - expect(scheme.errorContainer, scheme.error); - expect(scheme.onErrorContainer, scheme.onError); + expect(scheme.secondaryVariant, const Color(0xff03dac6)); expect(scheme.background, const Color(0xff121212)); - expect(scheme.onBackground, const Color(0xffffffff)); expect(scheme.surface, const Color(0xff121212)); + expect(scheme.error, const Color(0xffcf6679)); + expect(scheme.onPrimary, const Color(0xff000000)); + expect(scheme.onSecondary, const Color(0xff000000)); + expect(scheme.onBackground, const Color(0xffffffff)); expect(scheme.onSurface, const Color(0xffffffff)); - expect(scheme.surfaceVariant, scheme.surface); - expect(scheme.onSurfaceVariant, scheme.onSurface); - expect(scheme.outline, scheme.onBackground); - expect(scheme.shadow, scheme.onBackground); - expect(scheme.inverseSurface, scheme.onSurface); - expect(scheme.onInverseSurface, scheme.surface); - expect(scheme.inversePrimary, scheme.onPrimary); - - expect(scheme.primaryVariant, const Color(0xff3700b3)); - expect(scheme.secondaryVariant, const Color(0xff03dac6)); + expect(scheme.onError, const Color(0xff000000)); + expect(scheme.brightness, Brightness.dark); }); test('high contrast light scheme matches the spec', () { // Colors are based off of the Material Design baseline default theme: // https://material.io/design/color/dark-theme.html#ui-application - // with the new Material 3 colors defaulting to values from the M2 - // baseline. const ColorScheme scheme = ColorScheme.highContrastLight(); - expect(scheme.brightness, Brightness.light); expect(scheme.primary, const Color(0xff0000ba)); - expect(scheme.onPrimary, const Color(0xffffffff)); - expect(scheme.primaryContainer, scheme.primary); - expect(scheme.onPrimaryContainer, scheme.onPrimary); + expect(scheme.primaryVariant, const Color(0xff000088)); expect(scheme.secondary, const Color(0xff66fff9)); - expect(scheme.onSecondary, const Color(0xff000000)); - expect(scheme.secondaryContainer, scheme.secondary); - expect(scheme.onSecondaryContainer, scheme.onSecondary); - expect(scheme.tertiary, scheme.secondary); - expect(scheme.onTertiary, scheme.onSecondary); - expect(scheme.tertiaryContainer, scheme.tertiary); - expect(scheme.onTertiaryContainer, scheme.onTertiary); - expect(scheme.error, const Color(0xff790000)); - expect(scheme.onError, const Color(0xffffffff)); - expect(scheme.errorContainer, scheme.error); - expect(scheme.onErrorContainer, scheme.onError); + expect(scheme.secondaryVariant, const Color(0xff018786)); expect(scheme.background, const Color(0xffffffff)); - expect(scheme.onBackground, const Color(0xff000000)); expect(scheme.surface, const Color(0xffffffff)); + expect(scheme.error, const Color(0xff790000)); + expect(scheme.onPrimary, const Color(0xffffffff)); + expect(scheme.onSecondary, const Color(0xff000000)); + expect(scheme.onBackground, const Color(0xff000000)); expect(scheme.onSurface, const Color(0xff000000)); - expect(scheme.surfaceVariant, scheme.surface); - expect(scheme.onSurfaceVariant, scheme.onSurface); - expect(scheme.outline, scheme.onBackground); - expect(scheme.shadow, scheme.onBackground); - expect(scheme.inverseSurface, scheme.onSurface); - expect(scheme.onInverseSurface, scheme.surface); - expect(scheme.inversePrimary, scheme.onPrimary); - - expect(scheme.primaryVariant, const Color(0xff000088)); - expect(scheme.secondaryVariant, const Color(0xff018786)); + expect(scheme.onError, const Color(0xffffffff)); + expect(scheme.brightness, Brightness.light); }); test('high contrast dark scheme matches the spec', () { // Colors are based off of the Material Design baseline dark theme: // https://material.io/design/color/dark-theme.html#ui-application - // with the new Material 3 colors defaulting to values from the M2 - // baseline. const ColorScheme scheme = ColorScheme.highContrastDark(); - expect(scheme.brightness, Brightness.dark); expect(scheme.primary, const Color(0xffefb7ff)); - expect(scheme.onPrimary, const Color(0xff000000)); - expect(scheme.primaryContainer, scheme.primary); - expect(scheme.onPrimaryContainer, scheme.onPrimary); + expect(scheme.primaryVariant, const Color(0xffbe9eff)); expect(scheme.secondary, const Color(0xff66fff9)); - expect(scheme.onSecondary, const Color(0xff000000)); - expect(scheme.secondaryContainer, scheme.secondary); - expect(scheme.onSecondaryContainer, scheme.onSecondary); - expect(scheme.tertiary, scheme.secondary); - expect(scheme.onTertiary, scheme.onSecondary); - expect(scheme.tertiaryContainer, scheme.tertiary); - expect(scheme.onTertiaryContainer, scheme.onTertiary); - expect(scheme.error, const Color(0xff9b374d)); - expect(scheme.onError, const Color(0xff000000)); - expect(scheme.errorContainer, scheme.error); - expect(scheme.onErrorContainer, scheme.onError); + expect(scheme.secondaryVariant, const Color(0xff66fff9)); expect(scheme.background, const Color(0xff121212)); - expect(scheme.onBackground, const Color(0xffffffff)); expect(scheme.surface, const Color(0xff121212)); + expect(scheme.error, const Color(0xff9b374d)); + expect(scheme.onPrimary, const Color(0xff000000)); + expect(scheme.onSecondary, const Color(0xff000000)); + expect(scheme.onBackground, const Color(0xffffffff)); expect(scheme.onSurface, const Color(0xffffffff)); - expect(scheme.surfaceVariant, scheme.surface); - expect(scheme.onSurfaceVariant, scheme.onSurface); - expect(scheme.outline, scheme.onBackground); - expect(scheme.shadow, scheme.onBackground); - expect(scheme.inverseSurface, scheme.onSurface); - expect(scheme.onInverseSurface, scheme.surface); - expect(scheme.inversePrimary, scheme.onPrimary); - - expect(scheme.primaryVariant, const Color(0xffbe9eff)); - expect(scheme.secondaryVariant, const Color(0xff66fff9)); - }); - - test('can generate a light scheme from a seed color', () { - final ColorScheme scheme = ColorScheme.fromSeed(seedColor: Colors.blue); - expect(scheme.primary, const Color(0xff0061a6)); - expect(scheme.onPrimary, const Color(0xffffffff)); - expect(scheme.primaryContainer, const Color(0xffd0e4ff)); - expect(scheme.onPrimaryContainer, const Color(0xff001d36)); - expect(scheme.secondary, const Color(0xff535f70)); - expect(scheme.onSecondary, const Color(0xffffffff)); - expect(scheme.secondaryContainer, const Color(0xffd6e3f7)); - expect(scheme.onSecondaryContainer, const Color(0xff101c2b)); - expect(scheme.tertiary, const Color(0xff6b5778)); - expect(scheme.onTertiary, const Color(0xffffffff)); - expect(scheme.tertiaryContainer, const Color(0xfff3daff)); - expect(scheme.onTertiaryContainer, const Color(0xff251432)); - expect(scheme.error, const Color(0xffba1b1b)); - expect(scheme.onError, const Color(0xffffffff)); - expect(scheme.errorContainer, const Color(0xffffdad4)); - expect(scheme.onErrorContainer, const Color(0xff410001)); - expect(scheme.outline, const Color(0xff73777f)); - expect(scheme.background, const Color(0xfffdfcff)); - expect(scheme.onBackground, const Color(0xff1b1b1b)); - expect(scheme.surface, const Color(0xfffdfcff)); - expect(scheme.onSurface, const Color(0xff1b1b1b)); - expect(scheme.surfaceVariant, const Color(0xffdfe2eb)); - expect(scheme.onSurfaceVariant, const Color(0xff42474e)); - expect(scheme.inverseSurface, const Color(0xff2f3033)); - expect(scheme.onInverseSurface, const Color(0xfff1f0f4)); - expect(scheme.inversePrimary, const Color(0xff9ccaff)); - expect(scheme.shadow, const Color(0xff000000)); - expect(scheme.brightness, Brightness.light); - }); - - test('can generate a dark scheme from a seed color', () { - final ColorScheme scheme = ColorScheme.fromSeed(seedColor: Colors.blue, brightness: Brightness.dark); - expect(scheme.primary, const Color(0xff9ccaff)); - expect(scheme.onPrimary, const Color(0xff00325a)); - expect(scheme.primaryContainer, const Color(0xff00497f)); - expect(scheme.onPrimaryContainer, const Color(0xffd0e4ff)); - expect(scheme.secondary, const Color(0xffbbc8db)); - expect(scheme.onSecondary, const Color(0xff253140)); - expect(scheme.secondaryContainer, const Color(0xff3c4858)); - expect(scheme.onSecondaryContainer, const Color(0xffd6e3f7)); - expect(scheme.tertiary, const Color(0xffd6bee4)); - expect(scheme.onTertiary, const Color(0xff3b2948)); - expect(scheme.tertiaryContainer, const Color(0xff523f5f)); - expect(scheme.onTertiaryContainer, const Color(0xfff3daff)); - expect(scheme.error, const Color(0xffffb4a9)); - expect(scheme.onError, const Color(0xff680003)); - expect(scheme.errorContainer, const Color(0xff930006)); - expect(scheme.onErrorContainer, const Color(0xffffb4a9)); - expect(scheme.outline, const Color(0xff8d9199)); - expect(scheme.background, const Color(0xff1b1b1b)); - expect(scheme.onBackground, const Color(0xffe2e2e6)); - expect(scheme.surface, const Color(0xff1b1b1b)); - expect(scheme.onSurface, const Color(0xffe2e2e6)); - expect(scheme.surfaceVariant, const Color(0xff42474e)); - expect(scheme.onSurfaceVariant, const Color(0xffc3c7d0)); - expect(scheme.inverseSurface, const Color(0xffe2e2e6)); - expect(scheme.onInverseSurface, const Color(0xff2f3033)); - expect(scheme.inversePrimary, const Color(0xff0061a6)); - expect(scheme.shadow, const Color(0xff000000)); + expect(scheme.onError, const Color(0xff000000)); expect(scheme.brightness, Brightness.dark); }); - - test('can override specific colors in a generated scheme', () { - final ColorScheme baseScheme = ColorScheme.fromSeed(seedColor: Colors.blue); - const Color primaryOverride = Color(0xffabcdef); - final ColorScheme scheme = ColorScheme.fromSeed( - seedColor: Colors.blue, - primary: primaryOverride, - ); - expect(scheme.primary, primaryOverride); - // The rest should be the same. - expect(scheme.onPrimary, baseScheme.onPrimary); - expect(scheme.primaryContainer, baseScheme.primaryContainer); - expect(scheme.onPrimaryContainer, baseScheme.onPrimaryContainer); - expect(scheme.secondary, baseScheme.secondary); - expect(scheme.onSecondary, baseScheme.onSecondary); - expect(scheme.secondaryContainer, baseScheme.secondaryContainer); - expect(scheme.onSecondaryContainer, baseScheme.onSecondaryContainer); - expect(scheme.tertiary, baseScheme.tertiary); - expect(scheme.onTertiary, baseScheme.onTertiary); - expect(scheme.tertiaryContainer, baseScheme.tertiaryContainer); - expect(scheme.onTertiaryContainer, baseScheme.onTertiaryContainer); - expect(scheme.error, baseScheme.error); - expect(scheme.onError, baseScheme.onError); - expect(scheme.errorContainer, baseScheme.errorContainer); - expect(scheme.onErrorContainer, baseScheme.onErrorContainer); - expect(scheme.outline, baseScheme.outline); - expect(scheme.background, baseScheme.background); - expect(scheme.onBackground, baseScheme.onBackground); - expect(scheme.surface, baseScheme.surface); - expect(scheme.onSurface, baseScheme.onSurface); - expect(scheme.surfaceVariant, baseScheme.surfaceVariant); - expect(scheme.onSurfaceVariant, baseScheme.onSurfaceVariant); - expect(scheme.inverseSurface, baseScheme.inverseSurface); - expect(scheme.onInverseSurface, baseScheme.onInverseSurface); - expect(scheme.inversePrimary, baseScheme.inversePrimary); - expect(scheme.shadow, baseScheme.shadow); - expect(scheme.brightness, baseScheme.brightness); - }); - - testWidgets('generated scheme "on" colors meet a11y contrast guidelines', (WidgetTester tester) async { - final ColorScheme colors = ColorScheme.fromSeed(seedColor: Colors.teal); - - Widget label(String text, Color textColor, Color background) { - return Container( - color: background, - padding: const EdgeInsets.all(8), - child: Text(text, style: TextStyle(color: textColor)), - ); - } - - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.from(colorScheme: colors), - home: Scaffold( - body: Column( - children: [ - label('primary', colors.onPrimary, colors.primary), - label('secondary', colors.onSecondary, colors.secondary), - label('tertiary', colors.onTertiary, colors.tertiary), - label('error', colors.onError, colors.error), - label('background', colors.onBackground, colors.background), - label('surface', colors.onSurface, colors.surface), - ], - ), - ), - ), - ); - await expectLater(tester, meetsGuideline(textContrastGuideline)); - }, - skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 - ); } diff --git a/packages/flutter/test/material/data_table_test.dart b/packages/flutter/test/material/data_table_test.dart index 1381a68cad1f0..6858a96037960 100644 --- a/packages/flutter/test/material/data_table_test.dart +++ b/packages/flutter/test/material/data_table_test.dart @@ -486,105 +486,6 @@ void main() { ); }); - testWidgets('DataTable sort indicator orientation does not change on state update', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/43724 - Widget buildTable({String title = 'Name1'}) { - return DataTable( - sortColumnIndex: 0, - columns: [ - DataColumn( - label: Text(title), - tooltip: 'Name', - onSort: (int columnIndex, bool ascending) {}, - ), - ], - rows: kDesserts.map((Dessert dessert) { - return DataRow( - cells: [ - DataCell( - Text(dessert.name), - ), - ], - ); - }).toList(), - ); - } - - // Check for ascending list - await tester.pumpWidget(MaterialApp( - home: Material(child: buildTable()), - )); - // The `tester.widget` ensures that there is exactly one upward arrow. - final Finder iconFinder = find.widgetWithIcon(Transform, Icons.arrow_upward); - Transform transformOfArrow = tester.widget(iconFinder); - expect( - transformOfArrow.transform.getRotation(), - equals(Matrix3.identity()), - ); - - // Cause a rebuild by updating the widget - await tester.pumpWidget(MaterialApp( - home: Material(child: buildTable(title: 'Name2')), - )); - await tester.pumpAndSettle(); - // The `tester.widget` ensures that there is exactly one upward arrow. - transformOfArrow = tester.widget(iconFinder); - expect( - transformOfArrow.transform.getRotation(), - equals(Matrix3.identity()), // Should not have changed - ); - }); - - testWidgets('DataTable sort indicator orientation does not change on state update - reverse', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/43724 - Widget buildTable({String title = 'Name1'}) { - return DataTable( - sortColumnIndex: 0, - sortAscending: false, - columns: [ - DataColumn( - label: Text(title), - tooltip: 'Name', - onSort: (int columnIndex, bool ascending) {}, - ), - ], - rows: kDesserts.map((Dessert dessert) { - return DataRow( - cells: [ - DataCell( - Text(dessert.name), - ), - ], - ); - }).toList(), - ); - } - - // Check for ascending list - await tester.pumpWidget(MaterialApp( - home: Material(child: buildTable()), - )); - // The `tester.widget` ensures that there is exactly one upward arrow. - final Finder iconFinder = find.widgetWithIcon(Transform, Icons.arrow_upward); - Transform transformOfArrow = tester.widget(iconFinder); - expect( - transformOfArrow.transform.getRotation(), - equals(Matrix3.rotationZ(math.pi)), - ); - - // Cause a rebuild by updating the widget - await tester.pumpWidget(MaterialApp( - home: Material(child: buildTable(title: 'Name2')), - )); - await tester.pumpAndSettle(); - // The `tester.widget` ensures that there is exactly one upward arrow. - transformOfArrow = tester.widget(iconFinder); - expect( - transformOfArrow.transform.getRotation(), - equals(Matrix3.rotationZ(math.pi)), // Should not have changed - ); - }); - testWidgets('DataTable row onSelectChanged test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( @@ -1397,16 +1298,8 @@ void main() { ); }); - testWidgets('DataRow renders checkbox with colors from CheckboxTheme', (WidgetTester tester) async { - const Color fillColor = Color(0xFF00FF00); - const Color checkColor = Color(0xFF0000FF); - - final ThemeData _themeData = ThemeData( - checkboxTheme: CheckboxThemeData( - fillColor: MaterialStateProperty.all(fillColor), - checkColor: MaterialStateProperty.all(checkColor), - ), - ); + testWidgets('DataRow renders checkbox with colors from Theme', (WidgetTester tester) async { + final ThemeData _themeData = ThemeData.light(); Widget buildTable() { return MaterialApp( theme: _themeData, @@ -1419,7 +1312,6 @@ void main() { ], rows: [ DataRow( - selected: true, onSelectChanged: (bool? checked) {}, cells: const [ DataCell(Text('Content1')), @@ -1431,15 +1323,13 @@ void main() { ); } - await tester.pumpWidget(buildTable()); + Checkbox lastCheckbox() { + return tester.widgetList(find.byType(Checkbox)).last; + } - expect( - Material.of(tester.element(find.byType(Checkbox).last)), - paints - ..path() - ..path(color: fillColor) - ..path(color: checkColor), - ); + await tester.pumpWidget(buildTable()); + expect(lastCheckbox().activeColor, _themeData.colorScheme.primary); + expect(lastCheckbox().checkColor, _themeData.colorScheme.onPrimary); }); testWidgets('DataRow renders custom colors when selected', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/debug_test.dart b/packages/flutter/test/material/debug_test.dart index e319132463306..246b57521ced8 100644 --- a/packages/flutter/test/material/debug_test.dart +++ b/packages/flutter/test/material/debug_test.dart @@ -189,6 +189,8 @@ void main() { ' _FocusTraversalGroupMarker\n' ' FocusTraversalGroup\n' ' _ActionsMarker\n' + ' DefaultTextEditingActions\n' + ' _ActionsMarker\n' ' Actions\n' ' _ShortcutsMarker\n' ' Semantics\n' diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart index c69312c2c6075..9c6292c0760d3 100644 --- a/packages/flutter/test/material/dropdown_test.dart +++ b/packages/flutter/test/material/dropdown_test.dart @@ -2775,54 +2775,6 @@ void main() { expect(Focus.of(tester.element(find.byKey(const ValueKey(91)).last)).hasPrimaryFocus, isFalse); }); - testWidgets('DropdownButton onTap callback can request focus', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton')..addListener(() { }); - int? value = 1; - final List hugeMenuItems = List.generate(100, (int index) => index); - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - focusNode: focusNode, - onChanged: (int? newValue) { - setState(() { - value = newValue; - }); - }, - value: value, - itemHeight: null, - items: hugeMenuItems.map>((int item) { - return DropdownMenuItem( - key: ValueKey(item), - value: item, - child: Text(item.toString()), - ); - }).toList(), - ); - }, - ), - ), - ), - ), - ); - - await tester.pump(); // Pump a frame for autofocus to take effect. - expect(focusNode.hasPrimaryFocus, isFalse); - - await tester.tap(find.text('1')); - await tester.pumpAndSettle(); - - // Close the dropdown menu. - await tester.tapAt(const Offset(1.0, 1.0)); - await tester.pumpAndSettle(); - - expect(focusNode.hasPrimaryFocus, isTrue); - }); - testWidgets('DropdownButton changes selected item with arrow keys', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton'); String? value = 'one'; @@ -3678,51 +3630,4 @@ void main() { expect(tester.takeException(), null); }); - - testWidgets('BorderRadius property works properly for DropdownButtonFormField', (WidgetTester tester) async { - const double radius = 20.0; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: DropdownButtonFormField( - borderRadius: BorderRadius.circular(radius), - value: 'One', - items: ['One', 'Two', 'Three', 'Four'] - .map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - onChanged: (_) { }, - ), - ), - ), - ), - ); - - await tester.tap(find.text('One')); - await tester.pumpAndSettle(); - - expect( - find.ancestor( - of: find.text('One').last, - matching: find.byType(CustomPaint), - ).at(2), - paints - ..save() - ..rrect() - ..rrect() - ..rrect() - ..rrect(rrect: const RRect.fromLTRBXY(0.0, 0.0, 800.0, 208.0, radius, radius)), - ); - - final InkWell firstItem = tester.widget(find.widgetWithText(InkWell, 'One')); - final InkWell lastItem = tester.widget(find.widgetWithText(InkWell, 'Four')); - - expect(firstItem.borderRadius, const BorderRadius.vertical(top: Radius.circular(radius))); - expect(lastItem.borderRadius, const BorderRadius.vertical(bottom: Radius.circular(radius))); - }); } diff --git a/packages/flutter/test/material/elevated_button_test.dart b/packages/flutter/test/material/elevated_button_test.dart index f58613d6de1b3..e29c6142cdb4a 100644 --- a/packages/flutter/test/material/elevated_button_test.dart +++ b/packages/flutter/test/material/elevated_button_test.dart @@ -1418,85 +1418,6 @@ void main() { expect(tester.getSize(find.widgetWithText(ElevatedButton, '200x200')), const Size(200, 200)); expect(tester.getSize(find.widgetWithText(ElevatedButton, '200,200')), const Size(200, 200)); }); - - testWidgets('ElevatedButton changes mouse cursor when hovered', (WidgetTester tester) async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - enabledMouseCursor: SystemMouseCursors.text, - disabledMouseCursor: SystemMouseCursors.grab, - ), - onPressed: () {}, - child: const Text('button'), - ), - ), - ), - ); - - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); - await gesture.addPointer(location: Offset.zero); - addTearDown(gesture.removePointer); - - await tester.pump(); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); - - // Test cursor when disabled - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - enabledMouseCursor: SystemMouseCursors.text, - disabledMouseCursor: SystemMouseCursors.grab, - ), - onPressed: null, - child: const Text('button'), - ), - ), - ), - ); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab); - - // Test default cursor - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: ElevatedButton( - onPressed: () {}, - child: const Text('button'), - ), - ), - ), - ); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); - - // Test default cursor when disabled - await tester.pumpWidget( - const Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: ElevatedButton( - onPressed: null, - child: Text('button'), - ), - ), - ), - ); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); - }); } TextStyle _iconStyle(WidgetTester tester, IconData icon) { diff --git a/packages/flutter/test/material/flexible_space_bar_test.dart b/packages/flutter/test/material/flexible_space_bar_test.dart index 0e1e93bcea2dc..a39927bc2a9b3 100644 --- a/packages/flutter/test/material/flexible_space_bar_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_test.dart @@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This file is run as part of a reduced test set in CI on Mac and Windows -// machines. -@Tags(['reduced-test-set']) - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -474,199 +470,6 @@ void main() { ); }); - testWidgets('FlexibleSpaceBar sets constraints for the title - override expandedTitleScale', (WidgetTester tester) async { - const double titleFontSize = 20.0; - const double height = 300.0; - const double expandedTitleScale = 3.0; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: CustomScrollView( - slivers: [ - SliverAppBar( - expandedHeight: height, - pinned: true, - stretch: true, - flexibleSpace: FlexibleSpaceBar( - expandedTitleScale: expandedTitleScale, - titlePadding: EdgeInsets.zero, - title: Text( - 'X' * 41, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: titleFontSize,), - ), - centerTitle: false, - ), - ), - SliverList( - delegate: SliverChildListDelegate( - [ - for (int i = 0; i < 3; i++) - SizedBox( - height: 200.0, - child: Center(child: Text('Item $i')), - ), - ], - ), - ), - ], - ), - ), - ), - ); - - // We drag up to fully collapse the space bar. - await tester.drag(find.text('Item 0'), const Offset(0, -600.0)); - await tester.pumpAndSettle(); - - final Finder title = find.byType(Text).first; - final double collapsedWidth = tester.getRect(title).width; - - // We drag down to fully expand the space bar. - await tester.drag(find.text('Item 2'), const Offset(0, 600.0)); - await tester.pumpAndSettle(); - - // The title is shifted by this margin to maintain the position of the - // bottom edge. - const double bottomMargin = titleFontSize * (expandedTitleScale - 1); - - // The title is scaled and transformed to be 3 times bigger, when the - // FlexibleSpaceBar is fully expanded, thus we expect the width to be - // 3 times smaller than the full width. The height of the text is the same - // as the font size, with 40 dps bottom margin to maintain its bottom position. - expect( - tester.getRect(title), - Rect.fromLTRB( - 0, - height - titleFontSize - bottomMargin, - (collapsedWidth / 3).floorToDouble(), - height - bottomMargin, - ), - ); - }); - - testWidgets('FlexibleSpaceBar scaled title', (WidgetTester tester) async { - const double titleFontSize = 20.0; - const double height = 300.0; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: CustomScrollView( - slivers: [ - const SliverAppBar( - expandedHeight: height, - pinned: true, - stretch: true, - flexibleSpace: RepaintBoundary( - child: FlexibleSpaceBar( - title: Text( - 'X', - style: TextStyle(fontSize: titleFontSize,), - ), - centerTitle: false, - ), - ), - ), - SliverList( - delegate: SliverChildListDelegate( - [ - for (int i = 0; i < 3; i += 1) - SizedBox( - height: 200.0, - child: Center(child: Text('Item $i')), - ), - ], - ), - ), - ], - ), - ), - ), - ); - - // We drag up to fully collapse the space bar. - await tester.drag(find.text('Item 0'), const Offset(0, -600.0)); - await tester.pumpAndSettle(); - - final Finder flexibleSpaceBar = find.ancestor(of: find.byType(FlexibleSpaceBar), matching: find.byType(RepaintBoundary).first); - await expectLater( - flexibleSpaceBar, - matchesGoldenFile('flexible_space_bar.expanded_title_scale_default.collapsed.png') - ); - - // We drag down to fully expand the space bar. - await tester.drag(find.text('Item 2'), const Offset(0, 600.0)); - await tester.pumpAndSettle(); - - await expectLater( - flexibleSpaceBar, - matchesGoldenFile('flexible_space_bar.expanded_title_scale_default.expanded.png') - ); - }); - - testWidgets('FlexibleSpaceBar scaled title - override expandedTitleScale', (WidgetTester tester) async { - const double titleFontSize = 20.0; - const double height = 300.0; - const double expandedTitleScale = 3.0; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: CustomScrollView( - slivers: [ - const SliverAppBar( - expandedHeight: height, - pinned: true, - stretch: true, - flexibleSpace: RepaintBoundary( - child: FlexibleSpaceBar( - title: Text( - 'X', - style: TextStyle(fontSize: titleFontSize,), - ), - centerTitle: false, - expandedTitleScale: expandedTitleScale, - ), - ), - ), - SliverList( - delegate: SliverChildListDelegate( - [ - for (int i = 0; i < 3; i += 1) - SizedBox( - height: 200.0, - child: Center(child: Text('Item $i')), - ), - ], - ), - ), - ], - ), - ), - ), - ); - - // We drag up to fully collapse the space bar. - await tester.drag(find.text('Item 0'), const Offset(0, -600.0)); - await tester.pumpAndSettle(); - - final Finder flexibleSpaceBar = find.ancestor(of: find.byType(FlexibleSpaceBar), matching: find.byType(RepaintBoundary).first); - // This should match the default behavior - await expectLater( - flexibleSpaceBar, - matchesGoldenFile('flexible_space_bar.expanded_title_scale_default.collapsed.png') - ); - - // We drag down to fully expand the space bar. - await tester.drag(find.text('Item 2'), const Offset(0, 600.0)); - await tester.pumpAndSettle(); - - await expectLater( - flexibleSpaceBar, - matchesGoldenFile('flexible_space_bar.expanded_title_scale_override.expanded.png') - ); - }); - testWidgets('FlexibleSpaceBar test titlePadding defaults', (WidgetTester tester) async { Widget buildFrame(TargetPlatform platform, bool? centerTitle) { return MaterialApp( diff --git a/packages/flutter/test/material/floating_action_button_test.dart b/packages/flutter/test/material/floating_action_button_test.dart index 18322d97c731d..20d895f3a2194 100644 --- a/packages/flutter/test/material/floating_action_button_test.dart +++ b/packages/flutter/test/material/floating_action_button_test.dart @@ -18,10 +18,6 @@ import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; void main() { - - final ThemeData material3Theme = ThemeData.light().copyWith(useMaterial3: true); - final ThemeData material2Theme = ThemeData.light().copyWith(useMaterial3: false); - testWidgets('Floating Action Button control test', (WidgetTester tester) async { bool didPressButton = false; await tester.pumpWidget( @@ -175,7 +171,6 @@ void main() { testWidgets('Floating Action Button elevation when highlighted - effect', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( - theme: material3Theme, home: Scaffold( floatingActionButton: FloatingActionButton( onPressed: () { }, @@ -188,7 +183,7 @@ void main() { await tester.pump(); expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); await tester.pump(const Duration(seconds: 1)); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); + expect(tester.widget(find.byType(PhysicalShape)).elevation, 12.0); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -200,7 +195,7 @@ void main() { ), ); await tester.pump(); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); + expect(tester.widget(find.byType(PhysicalShape)).elevation, 12.0); await tester.pump(const Duration(seconds: 1)); expect(tester.widget(find.byType(PhysicalShape)).elevation, 20.0); await gesture.up(); @@ -282,7 +277,6 @@ void main() { testWidgets('Floating Action Button elevation when disabled while highlighted - effect', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( - theme: material3Theme, home: Scaffold( floatingActionButton: FloatingActionButton( onPressed: () { }, @@ -295,11 +289,10 @@ void main() { await tester.pump(); expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); await tester.pump(const Duration(seconds: 1)); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); + expect(tester.widget(find.byType(PhysicalShape)).elevation, 12.0); await tester.pumpWidget( - MaterialApp( - theme: material3Theme, - home: const Scaffold( + const MaterialApp( + home: Scaffold( floatingActionButton: FloatingActionButton( onPressed: null, ), @@ -307,12 +300,11 @@ void main() { ), ); await tester.pump(); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); + expect(tester.widget(find.byType(PhysicalShape)).elevation, 12.0); await tester.pump(const Duration(seconds: 1)); expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); await tester.pumpWidget( MaterialApp( - theme: material3Theme, home: Scaffold( floatingActionButton: FloatingActionButton( onPressed: () { }, @@ -331,7 +323,6 @@ void main() { await tester.pumpWidget( MaterialApp( - theme: material3Theme, home: Scaffold( body: FloatingActionButton.extended( label: const Text('tooltip'), @@ -368,7 +359,7 @@ void main() { await gesture.down(center); await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. - expect(getFABWidget(fabFinder).elevation, 6); + expect(getFABWidget(fabFinder).elevation, 12); }); testWidgets('FlatActionButton mini size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { @@ -411,9 +402,8 @@ void main() { testWidgets('FloatingActionButton.isExtended', (WidgetTester tester) async { await tester.pumpWidget( - MaterialApp( - theme: material3Theme, - home: const Scaffold( + const MaterialApp( + home: Scaffold( floatingActionButton: FloatingActionButton(onPressed: null), ), ), @@ -432,10 +422,7 @@ void main() { } expect(getFabWidget().isExtended, false); - expect( - getRawMaterialButtonWidget().shape, - const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))) - ); + expect(getRawMaterialButtonWidget().shape, const CircleBorder()); await tester.pumpWidget( const MaterialApp( @@ -453,16 +440,13 @@ void main() { ); expect(getFabWidget().isExtended, true); - expect( - getRawMaterialButtonWidget().shape, - const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))) - ); + expect(getRawMaterialButtonWidget().shape, const StadiumBorder()); expect(find.text('label'), findsOneWidget); expect(find.byType(Icon), findsOneWidget); - // Verify that the widget's height is 56 and that its internal + // Verify that the widget's height is 48 and that its internal /// horizontal layout is: 16 icon 8 label 20 - expect(tester.getSize(fabFinder).height, 56.0); + expect(tester.getSize(fabFinder).height, 48.0); final double fabLeft = tester.getTopLeft(fabFinder).dx; final double fabRight = tester.getTopRight(fabFinder).dx; @@ -495,9 +479,8 @@ void main() { } await tester.pumpWidget( - MaterialApp( - theme: material3Theme, - home: const Scaffold( + const MaterialApp( + home: Scaffold( floatingActionButton: FloatingActionButton.extended( label: SizedBox( width: 100.0, @@ -510,16 +493,13 @@ void main() { ); expect(getFabWidget().isExtended, true); - expect( - getRawMaterialButtonWidget().shape, - const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))) - ); + expect(getRawMaterialButtonWidget().shape, const StadiumBorder()); expect(find.text('label'), findsOneWidget); expect(find.byType(Icon), findsNothing); - // Verify that the widget's height is 56 and that its internal + // Verify that the widget's height is 48 and that its internal /// horizontal layout is: 20 label 20 - expect(tester.getSize(fabFinder).height, 56.0); + expect(tester.getSize(fabFinder).height, 48.0); final double fabLeft = tester.getTopLeft(fabFinder).dx; final double fabRight = tester.getTopRight(fabFinder).dx; @@ -790,7 +770,6 @@ void main() { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( - theme: material3Theme, home: Scaffold( body: Center( child: RepaintBoundary( @@ -1075,289 +1054,6 @@ void main() { expect(rawMaterialButton.textStyle, style.copyWith(color: const Color(0xffffffff))); }); - group('Material 2', () { - // Tests that are only relevant for Material 2. Once ThemeData.useMaterial3 - // is turned on by default, these tests can be removed. - - testWidgets('Floating Action Button elevation when highlighted - effect', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: Scaffold( - floatingActionButton: FloatingActionButton( - onPressed: () { }, - ), - ), - ), - ); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); - final TestGesture gesture = await tester.press(find.byType(PhysicalShape)); - await tester.pump(); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); - await tester.pump(const Duration(seconds: 1)); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 12.0); - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: Scaffold( - floatingActionButton: FloatingActionButton( - onPressed: () { }, - highlightElevation: 20.0, - ), - ), - ), - ); - await tester.pump(); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 12.0); - await tester.pump(const Duration(seconds: 1)); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 20.0); - await gesture.up(); - await tester.pump(); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 20.0); - await tester.pump(const Duration(seconds: 1)); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); - }); - - testWidgets('Floating Action Button elevation when disabled while highlighted - effect', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: Scaffold( - floatingActionButton: FloatingActionButton( - onPressed: () { }, - ), - ), - ), - ); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); - await tester.press(find.byType(PhysicalShape)); - await tester.pump(); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); - await tester.pump(const Duration(seconds: 1)); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 12.0); - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: const Scaffold( - floatingActionButton: FloatingActionButton( - onPressed: null, - ), - ), - ), - ); - await tester.pump(); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 12.0); - await tester.pump(const Duration(seconds: 1)); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: Scaffold( - floatingActionButton: FloatingActionButton( - onPressed: () { }, - ), - ), - ), - ); - await tester.pump(); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); - await tester.pump(const Duration(seconds: 1)); - expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); - }); - - testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: Scaffold( - body: FloatingActionButton.extended( - label: const Text('tooltip'), - onPressed: () {}, - focusNode: focusNode, - ), - ), - ), - ); - - final Finder fabFinder = find.byType(PhysicalShape); - PhysicalShape getFABWidget(Finder finder) => tester.widget(finder); - - // Default, not disabled. - expect(getFABWidget(fabFinder).elevation, 6); - - // Focused. - focusNode.requestFocus(); - await tester.pumpAndSettle(); - expect(getFABWidget(fabFinder).elevation, 6); - - // Hovered. - final Offset center = tester.getCenter(fabFinder); - final TestGesture gesture = await tester.createGesture( - kind: PointerDeviceKind.mouse, - ); - await gesture.addPointer(); - addTearDown(gesture.removePointer); - await gesture.moveTo(center); - await tester.pumpAndSettle(); - expect(getFABWidget(fabFinder).elevation, 8); - - // Highlighted (pressed). - await gesture.down(center); - await tester.pump(); // Start the splash and highlight animations. - await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. - expect(getFABWidget(fabFinder).elevation, 12); - }); - - testWidgets('FloatingActionButton.isExtended', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: const Scaffold( - floatingActionButton: FloatingActionButton(onPressed: null), - ), - ), - ); - - final Finder fabFinder = find.byType(FloatingActionButton); - - FloatingActionButton getFabWidget() { - return tester.widget(fabFinder); - } - - final Finder materialButtonFinder = find.byType(RawMaterialButton); - - RawMaterialButton getRawMaterialButtonWidget() { - return tester.widget(materialButtonFinder); - } - - expect(getFabWidget().isExtended, false); - expect(getRawMaterialButtonWidget().shape, const CircleBorder()); - - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: const Scaffold( - floatingActionButton: FloatingActionButton.extended( - label: SizedBox( - width: 100.0, - child: Text('label'), - ), - icon: Icon(Icons.android), - onPressed: null, - ), - ), - ), - ); - - expect(getFabWidget().isExtended, true); - expect(getRawMaterialButtonWidget().shape, const StadiumBorder()); - expect(find.text('label'), findsOneWidget); - expect(find.byType(Icon), findsOneWidget); - - // Verify that the widget's height is 48 and that its internal - /// horizontal layout is: 16 icon 8 label 20 - expect(tester.getSize(fabFinder).height, 48.0); - - final double fabLeft = tester.getTopLeft(fabFinder).dx; - final double fabRight = tester.getTopRight(fabFinder).dx; - final double iconLeft = tester.getTopLeft(find.byType(Icon)).dx; - final double iconRight = tester.getTopRight(find.byType(Icon)).dx; - final double labelLeft = tester.getTopLeft(find.text('label')).dx; - final double labelRight = tester.getTopRight(find.text('label')).dx; - expect(iconLeft - fabLeft, 16.0); - expect(labelLeft - iconRight, 8.0); - expect(fabRight - labelRight, 20.0); - - // The overall width of the button is: - // 168 = 16 + 24(icon) + 8 + 100(label) + 20 - expect(tester.getSize(find.byType(Icon)).width, 24.0); - expect(tester.getSize(find.text('label')).width, 100.0); - expect(tester.getSize(fabFinder).width, 168); - }); - - testWidgets('FloatingActionButton.isExtended (without icon)', (WidgetTester tester) async { - final Finder fabFinder = find.byType(FloatingActionButton); - - FloatingActionButton getFabWidget() { - return tester.widget(fabFinder); - } - - final Finder materialButtonFinder = find.byType(RawMaterialButton); - - RawMaterialButton getRawMaterialButtonWidget() { - return tester.widget(materialButtonFinder); - } - - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: const Scaffold( - floatingActionButton: FloatingActionButton.extended( - label: SizedBox( - width: 100.0, - child: Text('label'), - ), - onPressed: null, - ), - ), - ), - ); - - expect(getFabWidget().isExtended, true); - expect(getRawMaterialButtonWidget().shape, const StadiumBorder()); - expect(find.text('label'), findsOneWidget); - expect(find.byType(Icon), findsNothing); - - // Verify that the widget's height is 48 and that its internal - /// horizontal layout is: 20 label 20 - expect(tester.getSize(fabFinder).height, 48.0); - - final double fabLeft = tester.getTopLeft(fabFinder).dx; - final double fabRight = tester.getTopRight(fabFinder).dx; - final double labelLeft = tester.getTopLeft(find.text('label')).dx; - final double labelRight = tester.getTopRight(find.text('label')).dx; - expect(labelLeft - fabLeft, 20.0); - expect(fabRight - labelRight, 20.0); - - // The overall width of the button is: - // 140 = 20 + 100(label) + 20 - expect(tester.getSize(find.text('label')).width, 100.0); - expect(tester.getSize(fabFinder).width, 140); - }); - - - // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { - final GlobalKey key = GlobalKey(); - await tester.pumpWidget( - MaterialApp( - theme: material2Theme, - home: Scaffold( - body: Center( - child: RepaintBoundary( - key: key, - child: FloatingActionButton( - onPressed: () { }, - child: const Icon(Icons.add), - ), - ), - ), - ), - ), - ); - - await tester.press(find.byKey(key)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 1000)); - await expectLater( - find.byKey(key), - matchesGoldenFile('floating_action_button_test_m2.clip.png'), - ); - }); - }); - group('feedback', () { late FeedbackTester feedback; diff --git a/packages/flutter/test/material/floating_action_button_theme_test.dart b/packages/flutter/test/material/floating_action_button_theme_test.dart index 5cd5d27c375d6..1b302a60fa8a8 100644 --- a/packages/flutter/test/material/floating_action_button_theme_test.dart +++ b/packages/flutter/test/material/floating_action_button_theme_test.dart @@ -33,8 +33,6 @@ void main() { expect(_getRawMaterialButton(tester).shape, const CircleBorder()); expect(_getRawMaterialButton(tester).splashColor, ThemeData().splashColor); expect(_getRawMaterialButton(tester).constraints, const BoxConstraints.tightFor(width: 56.0, height: 56.0)); - expect(_getIconSize(tester).width, 24.0); - expect(_getIconSize(tester).height, 24.0); }); testWidgets('FloatingActionButtonThemeData values are used when no FloatingActionButton properties are specified', (WidgetTester tester) async { @@ -140,7 +138,6 @@ void main() { testWidgets('FloatingActionButton.small uses custom constraints when specified in the theme', (WidgetTester tester) async { const BoxConstraints constraints = BoxConstraints.tightFor(width: 100.0, height: 100.0); - const double iconSize = 24.0; await tester.pumpWidget(MaterialApp( theme: ThemeData().copyWith( @@ -157,13 +154,10 @@ void main() { )); expect(_getRawMaterialButton(tester).constraints, constraints); - expect(_getIconSize(tester).width, iconSize); - expect(_getIconSize(tester).height, iconSize); }); testWidgets('FloatingActionButton.large uses custom constraints when specified in the theme', (WidgetTester tester) async { const BoxConstraints constraints = BoxConstraints.tightFor(width: 100.0, height: 100.0); - const double iconSize = 36.0; await tester.pumpWidget(MaterialApp( theme: ThemeData().copyWith( @@ -180,8 +174,6 @@ void main() { )); expect(_getRawMaterialButton(tester).constraints, constraints); - expect(_getIconSize(tester).width, iconSize); - expect(_getIconSize(tester).height, iconSize); }); testWidgets('FloatingActionButton.extended uses custom properties when specified in the theme', (WidgetTester tester) async { @@ -279,7 +271,6 @@ void main() { highlightElevation: 43, shape: BeveledRectangleBorder(), enableFeedback: true, - iconSize: 42, sizeConstraints: BoxConstraints.tightFor(width: 100.0, height: 100.0), smallSizeConstraints: BoxConstraints.tightFor(width: 101.0, height: 101.0), largeSizeConstraints: BoxConstraints.tightFor(width: 102.0, height: 102.0), @@ -307,7 +298,6 @@ void main() { 'highlightElevation: 43.0', 'shape: BeveledRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)', 'enableFeedback: true', - 'iconSize: 42.0', 'sizeConstraints: BoxConstraints(w=100.0, h=100.0)', 'smallSizeConstraints: BoxConstraints(w=101.0, h=101.0)', 'largeSizeConstraints: BoxConstraints(w=102.0, h=102.0)', @@ -336,15 +326,3 @@ RichText _getRichText(WidgetTester tester) { ), ); } - -SizedBox _getIconSize(WidgetTester tester) { - return tester.widget( - find.descendant( - of: find.descendant( - of: find.byType(FloatingActionButton), - matching: find.byType(Icon), - ), - matching: find.byType(SizedBox), - ), - ); -} diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 675862cc12128..18f765f93c7d2 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -75,119 +75,6 @@ void main() { expect(iconButton.size, const Size(70.0, 70.0)); }); - testWidgets('when both iconSize and IconTheme.of(context).size are null, size falls back to 24.0', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); - await tester.pumpWidget( - wrap( - child: IconTheme( - data: const IconThemeData(), - child: IconButton( - focusNode: focusNode, - onPressed: mockOnPressedFunction.handler, - icon: const Icon(Icons.link), - ), - ) - ), - ); - - final RenderBox icon = tester.renderObject(find.byType(Icon)); - expect(icon.size, const Size(24.0, 24.0)); - }); - - testWidgets('when null, iconSize is overridden by closest IconTheme', (WidgetTester tester) async { - RenderBox icon; - - await tester.pumpWidget( - wrap( - child: IconTheme( - data: const IconThemeData(size: 10), - child: IconButton( - onPressed: mockOnPressedFunction.handler, - icon: const Icon(Icons.link), - ), - ) - ), - ); - - icon = tester.renderObject(find.byType(Icon)); - expect(icon.size, const Size(10.0, 10.0)); - - await tester.pumpWidget( - wrap( - child: Theme( - data: ThemeData( - iconTheme: const IconThemeData(size: 10), - ), - child: IconButton( - onPressed: mockOnPressedFunction.handler, - icon: const Icon(Icons.link), - ), - ) - ), - ); - - icon = tester.renderObject(find.byType(Icon)); - expect(icon.size, const Size(10.0, 10.0)); - - await tester.pumpWidget( - wrap( - child: Theme( - data: ThemeData( - iconTheme: const IconThemeData(size: 20), - ), - child: IconTheme( - data: const IconThemeData(size: 10), - child: IconButton( - onPressed: mockOnPressedFunction.handler, - icon: const Icon(Icons.link), - ), - ), - ) - ), - ); - - icon = tester.renderObject(find.byType(Icon)); - expect(icon.size, const Size(10.0, 10.0)); - - await tester.pumpWidget( - wrap( - child: IconTheme( - data: const IconThemeData(size: 20), - child: Theme( - data: ThemeData( - iconTheme: const IconThemeData(size: 10), - ), - child: IconButton( - onPressed: mockOnPressedFunction.handler, - icon: const Icon(Icons.link), - ), - ), - ) - ), - ); - - icon = tester.renderObject(find.byType(Icon)); - expect(icon.size, const Size(10.0, 10.0)); - }); - - testWidgets('when non-null, iconSize precedes IconTheme.of(context).size', (WidgetTester tester) async { - await tester.pumpWidget( - wrap( - child: IconTheme( - data: const IconThemeData(size: 30.0), - child: IconButton( - iconSize: 10.0, - onPressed: mockOnPressedFunction.handler, - icon: const Icon(Icons.link), - ), - ) - ), - ); - - final RenderBox icon = tester.renderObject(find.byType(Icon)); - expect(icon.size, const Size(10.0, 10.0)); - }); - testWidgets('Small icons with non-null constraints can be <48dp', (WidgetTester tester) async { await tester.pumpWidget( wrap( @@ -793,7 +680,7 @@ void main() { expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets('disabled IconButton has basic mouse cursor', (WidgetTester tester) async { + testWidgets('disabled IconButton has forbidden mouse cursor', (WidgetTester tester) async { await tester.pumpWidget( const Material( child: Directionality( @@ -814,7 +701,7 @@ void main() { await tester.pump(); - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); + expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden); }); testWidgets('IconButton.mouseCursor overrides implicit setting of mouse cursor', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/icons_test.dart b/packages/flutter/test/material/icons_test.dart index 8e8b3147dfca9..02fe3efdeadfe 100644 --- a/packages/flutter/test/material/icons_test.dart +++ b/packages/flutter/test/material/icons_test.dart @@ -82,27 +82,6 @@ void main() { await expectLater(find.byType(Wrap), matchesGoldenFile('test.icons.sample.png')); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/39998 - - // Regression test for https://github.com/flutter/flutter/issues/95886 - testWidgets('Another sample of icons look as expected', (WidgetTester tester) async { - await _loadIconFont(); - - await tester.pumpWidget(MaterialApp( - home: IconTheme( - data: const IconThemeData(size: 200), - child: Wrap( - children: const [ - Icon(Icons.water_drop), - Icon(Icons.water_drop_outlined), - Icon(Icons.water_drop_rounded), - Icon(Icons.water_drop_sharp), - ], - ), - ), - )); - - await expectLater(find.byType(Wrap), matchesGoldenFile('test.icons.sample2.png')); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/39998 } // Loads the cached material icon font. diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index f03bb3a8c8d19..ade64fd0a64a5 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -76,26 +76,6 @@ void main() { expect(log, equals(['tap-down', 'tap-cancel'])); }); - testWidgets('InkWell only onTapDown enables gestures', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/96030 - bool downTapped = false; - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: Material( - child: Center( - child: InkWell( - onTapDown: (TapDownDetails details) { - downTapped = true; - }, - ), - ), - ), - )); - - await tester.tap(find.byType(InkWell)); - expect(downTapped, true); - }); - testWidgets('InkWell invokes activation actions when expected', (WidgetTester tester) async { final List log = []; @@ -292,40 +272,6 @@ void main() { ); }); - testWidgets('ink well changes color on pressed with overlayColor', (WidgetTester tester) async { - const Color pressedColor = Color(0xffdd00ff); - - await tester.pumpWidget(Material( - child: Directionality( - textDirection: TextDirection.ltr, - child: Container( - alignment: Alignment.topLeft, - child: SizedBox( - width: 100, - height: 100, - child: InkWell( - splashFactory: NoSplash.splashFactory, - overlayColor: MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.pressed)) { - return pressedColor; - } - return const Color(0xffbadbad); // Shouldn't happen. - }), - onTap: () { }, - ), - ), - ), - ), - )); - await tester.pumpAndSettle(); - final TestGesture gesture = await tester.startGesture(tester.getRect(find.byType(InkWell)).center); - final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); - expect(inkFeatures, paints..rect(rect: const Rect.fromLTRB(0, 0, 100, 100), color: pressedColor.withAlpha(0))); - await tester.pumpAndSettle(); // Let the press highlight animation finish. - expect(inkFeatures, paints..rect(rect: const Rect.fromLTRB(0, 0, 100, 100), color: pressedColor)); - await gesture.up(); - }); - testWidgets('ink response splashColor matches splashColor parameter', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index 4b608b2c7fe3a..082eae2c0a91d 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -2963,232 +2963,6 @@ void main() { expect(tester.getTopRight(find.text('hint')).dx, 760.0); }); - testWidgets('FloatingLabelAlignment.toString()', (WidgetTester tester) async { - expect(FloatingLabelAlignment.start.toString(), 'FloatingLabelAlignment.start'); - expect(FloatingLabelAlignment.center.toString(), 'FloatingLabelAlignment.center'); - }); - - group('floatingLabelAlignment', () { - Widget buildInputDecoratorWithFloatingLabel({required TextDirection textDirection, - required bool hasIcon, - required FloatingLabelAlignment alignment, - bool borderIsOutline = false, - }) => buildInputDecorator( - // isEmpty: false (default) - // isFocused: false (default) - textDirection: textDirection, - decoration: InputDecoration( - contentPadding: const EdgeInsetsDirectional.only(start: 40.0, top: 12.0, bottom: 12.0), - floatingLabelAlignment: alignment, - icon: hasIcon ? const Icon(Icons.insert_link) : null, - labelText: 'label', - hintText: 'hint', - filled: true, - border: borderIsOutline ? const OutlineInputBorder() : null, - ), - ); - - group('LTR with icon aligned', () { - testWidgets('start', (WidgetTester tester) async { - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.ltr, - hasIcon: true, - alignment: FloatingLabelAlignment.start, - // borderIsOutline: false, (default) - ), - ); - // icon (40) + contentPadding (40) - expect(tester.getTopLeft(find.text('label')).dx, 80.0); - - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.ltr, - hasIcon: true, - alignment: FloatingLabelAlignment.start, - borderIsOutline: true, - ), - ); - // icon (40) + contentPadding (40) - expect(tester.getTopLeft(find.text('label')).dx, 80.0); - }); - - testWidgets('center', (WidgetTester tester) async { - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.ltr, - hasIcon: true, - alignment: FloatingLabelAlignment.center, - // borderIsOutline: false, (default) - ), - ); - // icon (40) + (decorator (800) - icon (40)) / 2 - expect(tester.getCenter(find.text('label')).dx, 420.0); - - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.ltr, - hasIcon: true, - alignment: FloatingLabelAlignment.center, - borderIsOutline: true, - ), - ); - // icon (40) + (decorator (800) - icon (40)) / 2 - expect(tester.getCenter(find.text('label')).dx, 420.0); - }); - }); - - group('LTR without icon aligned', () { - testWidgets('start', (WidgetTester tester) async { - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.ltr, - hasIcon: false, - alignment: FloatingLabelAlignment.start, - // borderIsOutline: false, (default) - ), - ); - // contentPadding (40) - expect(tester.getTopLeft(find.text('label')).dx, 40.0); - - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.ltr, - hasIcon: false, - alignment: FloatingLabelAlignment.start, - borderIsOutline: true, - ), - ); - // contentPadding (40) - expect(tester.getTopLeft(find.text('label')).dx, 40.0); - }); - - testWidgets('center', (WidgetTester tester) async { - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.ltr, - hasIcon: false, - alignment: FloatingLabelAlignment.center, - // borderIsOutline: false, (default) - ), - ); - // decorator (800) / 2 - expect(tester.getCenter(find.text('label')).dx, 400.0); - - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.ltr, - hasIcon: false, - alignment: FloatingLabelAlignment.center, - borderIsOutline: true, - ), - ); - // decorator (800) / 2 - expect(tester.getCenter(find.text('label')).dx, 400.0); - }); - }); - - group('RTL with icon aligned', () { - testWidgets('start', (WidgetTester tester) async { - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.rtl, - hasIcon: true, - alignment: FloatingLabelAlignment.start, - // borderIsOutline: false, (default) - ), - ); - // decorator (800) - icon (40) - contentPadding (40) - expect(tester.getTopRight(find.text('label')).dx, 720.0); - - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.rtl, - hasIcon: true, - alignment: FloatingLabelAlignment.start, - borderIsOutline: true, - ), - ); - // decorator (800) - icon (40) - contentPadding (40) - expect(tester.getTopRight(find.text('label')).dx, 720.0); - }); - - testWidgets('center', (WidgetTester tester) async { - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.rtl, - hasIcon: true, - alignment: FloatingLabelAlignment.center, - // borderIsOutline: false, (default) - ), - ); - // (decorator (800) / icon (40)) / 2 - expect(tester.getCenter(find.text('label')).dx, 380.0); - - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.rtl, - hasIcon: true, - alignment: FloatingLabelAlignment.center, - borderIsOutline: true, - ), - ); - // (decorator (800) / icon (40)) / 2 - expect(tester.getCenter(find.text('label')).dx, 380.0); - }); - }); - - group('RTL without icon aligned', () { - testWidgets('start', (WidgetTester tester) async { - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.rtl, - hasIcon: false, - alignment: FloatingLabelAlignment.start, - // borderIsOutline: false, (default) - ), - ); - // decorator (800) - contentPadding (40) - expect(tester.getTopRight(find.text('label')).dx, 760.0); - - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.rtl, - hasIcon: false, - alignment: FloatingLabelAlignment.start, - borderIsOutline: true, - ), - ); - // decorator (800) - contentPadding (40) - expect(tester.getTopRight(find.text('label')).dx, 760.0); - }); - - testWidgets('center', (WidgetTester tester) async { - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.rtl, - hasIcon: false, - alignment: FloatingLabelAlignment.center, - // borderIsOutline: false, (default) - ), - ); - // decorator (800) / 2 - expect(tester.getCenter(find.text('label')).dx, 400.0); - - await tester.pumpWidget( - buildInputDecoratorWithFloatingLabel( - textDirection: TextDirection.rtl, - hasIcon: false, - alignment: FloatingLabelAlignment.center, - borderIsOutline: true, - ), - ); - // decorator (800) / 2 - expect(tester.getCenter(find.text('label')).dx, 400.0); - }); - }); - }); - testWidgets('InputDecorator prefix/suffix dense layout', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( @@ -4064,53 +3838,6 @@ void main() { ); }); - testWidgets( - 'InputDecorator OutlineBorder focused label with icon', - (WidgetTester tester) async { - // This is a regression test for https://github.com/flutter/flutter/issues/82321 - Widget buildFrame(TextDirection textDirection) { - return MaterialApp( - home: Scaffold( - body: Container( - padding: const EdgeInsets.all(16.0), - alignment: Alignment.center, - child: Directionality( - textDirection: textDirection, - child: RepaintBoundary( - child: InputDecorator( - isFocused: true, - isEmpty: true, - decoration: InputDecoration( - filled: true, - fillColor: const Color(0xFF00FF00), - labelText: 'label text', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(30.0), - gapPadding: 0.0, - ), - ), - ), - ), - ), - ), - ), - ); - } - - await tester.pumpWidget(buildFrame(TextDirection.ltr)); - await expectLater( - find.byType(InputDecorator), - matchesGoldenFile('input_decorator.outline_label.ltr.png'), - ); - - await tester.pumpWidget(buildFrame(TextDirection.rtl)); - await expectLater( - find.byType(InputDecorator), - matchesGoldenFile('input_decorator.outline_label.rtl.png'), - ); - }, - ); - testWidgets( 'InputDecorator OutlineBorder focused label with icon', (WidgetTester tester) async { @@ -4731,98 +4458,6 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/55317 - testWidgets('rounded OutlineInputBorder with zero padding just wraps the label', (WidgetTester tester) async { - // This is a regression test for https://github.com/flutter/flutter/issues/82321 - const double borderRadius = 30.0; - const String labelText = 'label text'; - - // Overall height for this InputDecorator is 56dps: - // 12 - top padding - // 12 - floating label (ahem font size 16dps * 0.75 = 12) - // 4 - floating label / input text gap - // 16 - input text (ahem font size 16dps) - // 12 - bottom padding - const double inputDecoratorHeight = 56.0; - const double inputDecoratorWidth = 800.0; - - await tester.pumpWidget( - buildInputDecorator( - decoration: InputDecoration( - filled: true, - fillColor: const Color(0xFF00FF00), - labelText: labelText, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(borderRadius), - gapPadding: 0.0, - ), - ), - ), - ); - - const double denominator = borderRadius * 2.0; - const double borderRadiusScaled = borderRadius / denominator * inputDecoratorHeight; - - expect(find.text(labelText), findsOneWidget); - final Rect labelRect = tester.getRect(find.text(labelText)); - - expect(findBorderPainter(), paints - ..save() - ..path( - style: PaintingStyle.fill, - color: const Color(0xFF00FF00), - includes: [ - // The border should draw along the four edges of the - // InputDecorator. - - // Top center - const Offset(inputDecoratorWidth / 2.0, 0.0), - // Bottom center - const Offset(inputDecoratorWidth / 2.0, inputDecoratorHeight), - // Left center - const Offset(0.0, inputDecoratorHeight / 2.0), - // Right center - const Offset(inputDecoratorWidth, inputDecoratorHeight / 2.0), - - // The border path should contain points where each rounded corner - // ends. - - // Bottom-right arc - const Offset(inputDecoratorWidth, inputDecoratorHeight - borderRadiusScaled), - const Offset(inputDecoratorWidth - borderRadiusScaled, inputDecoratorHeight), - // Top-right arc - const Offset(inputDecoratorWidth,0.0 + borderRadiusScaled), - const Offset(inputDecoratorWidth - borderRadiusScaled, 0.0), - // Bottom-left arc - const Offset(0.0, inputDecoratorHeight - borderRadiusScaled), - const Offset(0.0 + borderRadiusScaled, inputDecoratorHeight), - // Top-left arc - const Offset(0.0,0.0 + borderRadiusScaled), - const Offset(0.0 + borderRadiusScaled, 0.0), - - // Gap edges - // gap start x = radius - radius * cos(arc sweep) - // gap start y = radius - radius * sin(arc sweep) - const Offset(39.49999999999999, 32.284366616798906), - Offset(39.49999999999999 + labelRect.width, 0.0), - ], - excludes: const [ - // The border should not contain the corner points, since the border - // is rounded. - - // Top-left - Offset.zero, - // Top-right - Offset(inputDecoratorWidth, 0.0), - // Bottom-left - Offset(0.0, inputDecoratorHeight), - // Bottom-right - Offset(inputDecoratorWidth, inputDecoratorHeight), - ], - ) - ..restore(), - ); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/55317 - testWidgets('OutlineInputBorder radius carries over when lerping', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/23982 const Key key = Key('textField'); diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index f9a26b5456b52..0248a4b59a730 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -379,11 +379,6 @@ void main() { expect(output, isEmpty); }); - testWidgets('ListTile.divideTiles with single item list', (WidgetTester tester) async { - final Iterable output = ListTile.divideTiles(tiles: const [SizedBox()], color: Colors.grey); - expect(output.single, isA()); - }); - testWidgets('ListTile.divideTiles only runs the generator once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/78879 int callCount = 0; diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index 5210b4372bd60..f63531079b4d6 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -2160,195 +2160,6 @@ void main() { expect(secondItem.padding, secondItemPadding); expect(thirdItem.padding, thirdItemPadding); }); - - testWidgets('NavigationRailDestination adds indicator by default when ThemeData.useMaterial3 is true', (WidgetTester tester) async { - await _pumpNavigationRail( - tester, - theme: ThemeData(useMaterial3: true), - navigationRail: NavigationRail( - labelType: NavigationRailLabelType.selected, - selectedIndex: 0, - destinations: const [ - NavigationRailDestination( - icon: Icon(Icons.favorite_border), - selectedIcon: Icon(Icons.favorite), - label: Text('Abc'), - ), - NavigationRailDestination( - icon: Icon(Icons.bookmark_border), - selectedIcon: Icon(Icons.bookmark), - label: Text('Def'), - ), - NavigationRailDestination( - icon: Icon(Icons.star_border), - selectedIcon: Icon(Icons.star), - label: Text('Ghi'), - ), - ], - ), - ); - - expect(find.byType(NavigationIndicator), findsWidgets); - }); - - testWidgets('NavigationRailDestination adds indicator when useIndicator is true', (WidgetTester tester) async { - await _pumpNavigationRail( - tester, - navigationRail: NavigationRail( - useIndicator: true, - labelType: NavigationRailLabelType.selected, - selectedIndex: 0, - destinations: const [ - NavigationRailDestination( - icon: Icon(Icons.favorite_border), - selectedIcon: Icon(Icons.favorite), - label: Text('Abc'), - ), - NavigationRailDestination( - icon: Icon(Icons.bookmark_border), - selectedIcon: Icon(Icons.bookmark), - label: Text('Def'), - ), - NavigationRailDestination( - icon: Icon(Icons.star_border), - selectedIcon: Icon(Icons.star), - label: Text('Ghi'), - ), - ], - ), - ); - - expect(find.byType(NavigationIndicator), findsWidgets); - }); - - testWidgets('NavigationRailDestination does not add indicator when useIndicator is false', (WidgetTester tester) async { - await _pumpNavigationRail( - tester, - navigationRail: NavigationRail( - useIndicator: false, - labelType: NavigationRailLabelType.selected, - selectedIndex: 0, - destinations: const [ - NavigationRailDestination( - icon: Icon(Icons.favorite_border), - selectedIcon: Icon(Icons.favorite), - label: Text('Abc'), - ), - NavigationRailDestination( - icon: Icon(Icons.bookmark_border), - selectedIcon: Icon(Icons.bookmark), - label: Text('Def'), - ), - NavigationRailDestination( - icon: Icon(Icons.star_border), - selectedIcon: Icon(Icons.star), - label: Text('Ghi'), - ), - ], - ), - ); - - expect(find.byType(NavigationIndicator), findsNothing); - }); - - testWidgets('NavigationRailDestination adds circular indicator when no labels are present', (WidgetTester tester) async { - await _pumpNavigationRail( - tester, - navigationRail: NavigationRail( - useIndicator: true, - labelType: NavigationRailLabelType.none, - selectedIndex: 0, - destinations: const [ - NavigationRailDestination( - icon: Icon(Icons.favorite_border), - selectedIcon: Icon(Icons.favorite), - label: Text('Abc'), - ), - NavigationRailDestination( - icon: Icon(Icons.bookmark_border), - selectedIcon: Icon(Icons.bookmark), - label: Text('Def'), - ), - NavigationRailDestination( - icon: Icon(Icons.star_border), - selectedIcon: Icon(Icons.star), - label: Text('Ghi'), - ), - ], - ), - ); - - final NavigationIndicator indicator = tester.widget(find.byType(NavigationIndicator).first); - - expect(indicator.width, 56); - expect(indicator.height, 56); - }); - - testWidgets('NavigationRailDestination adds circular indicator when selected labels are present', (WidgetTester tester) async { - await _pumpNavigationRail( - tester, - navigationRail: NavigationRail( - useIndicator: true, - labelType: NavigationRailLabelType.selected, - selectedIndex: 0, - destinations: const [ - NavigationRailDestination( - icon: Icon(Icons.favorite_border), - selectedIcon: Icon(Icons.favorite), - label: Text('Abc'), - ), - NavigationRailDestination( - icon: Icon(Icons.bookmark_border), - selectedIcon: Icon(Icons.bookmark), - label: Text('Def'), - ), - NavigationRailDestination( - icon: Icon(Icons.star_border), - selectedIcon: Icon(Icons.star), - label: Text('Ghi'), - ), - ], - ), - ); - - final NavigationIndicator indicator = tester.widget(find.byType(NavigationIndicator).first); - - expect(indicator.width, 56); - expect(indicator.height, 32); - }); - - testWidgets('NavigationRailDestination adds circular indicator when all labels are present', (WidgetTester tester) async { - await _pumpNavigationRail( - tester, - navigationRail: NavigationRail( - useIndicator: true, - labelType: NavigationRailLabelType.all, - selectedIndex: 0, - destinations: const [ - NavigationRailDestination( - icon: Icon(Icons.favorite_border), - selectedIcon: Icon(Icons.favorite), - label: Text('Abc'), - ), - NavigationRailDestination( - icon: Icon(Icons.bookmark_border), - selectedIcon: Icon(Icons.bookmark), - label: Text('Def'), - ), - NavigationRailDestination( - icon: Icon(Icons.star_border), - selectedIcon: Icon(Icons.star), - label: Text('Ghi'), - ), - ], - ), - ); - - final NavigationIndicator indicator = tester.widget(find.byType(NavigationIndicator).first); - - expect(indicator.width, 56); - expect(indicator.height, 32); - }); } TestSemantics _expectedSemantics() { @@ -2432,11 +2243,9 @@ Future _pumpNavigationRail( WidgetTester tester, { double textScaleFactor = 1.0, required NavigationRail navigationRail, - ThemeData? theme, }) async { await tester.pumpWidget( MaterialApp( - theme: theme, home: Builder( builder: (BuildContext context) { return MediaQuery( diff --git a/packages/flutter/test/material/navigation_rail_theme_test.dart b/packages/flutter/test/material/navigation_rail_theme_test.dart index 05243ba917f4a..c174fefc6f133 100644 --- a/packages/flutter/test/material/navigation_rail_theme_test.dart +++ b/packages/flutter/test/material/navigation_rail_theme_test.dart @@ -36,7 +36,6 @@ void main() { expect(_unselectedLabelStyle(tester).fontSize, 14.0); expect(_destinationsAlign(tester).alignment, Alignment.topCenter); expect(_labelType(tester), NavigationRailLabelType.none); - expect(find.byType(NavigationIndicator), findsNothing); }); testWidgets('NavigationRailThemeData values are used when no NavigationRail properties are specified', (WidgetTester tester) async { @@ -52,8 +51,6 @@ void main() { const double unselectedLabelFontSize = 11.0; const double groupAlignment = 0.0; const NavigationRailLabelType labelType = NavigationRailLabelType.all; - const bool useIndicator = true; - const Color indicatorColor = Color(0x00000004); await tester.pumpWidget( MaterialApp( @@ -76,8 +73,6 @@ void main() { unselectedLabelTextStyle: TextStyle(fontSize: unselectedLabelFontSize), groupAlignment: groupAlignment, labelType: labelType, - useIndicator: useIndicator, - indicatorColor: indicatorColor, ), child: NavigationRail( selectedIndex: 0, @@ -100,8 +95,6 @@ void main() { expect(_unselectedLabelStyle(tester).fontSize, unselectedLabelFontSize); expect(_destinationsAlign(tester).alignment, Alignment.center); expect(_labelType(tester), labelType); - expect(find.byType(NavigationIndicator), findsWidgets); - expect(_indicatorDecoration(tester)?.color, indicatorColor); }); testWidgets('NavigationRail values take priority over NavigationRailThemeData values when both properties are specified', (WidgetTester tester) async { @@ -117,8 +110,6 @@ void main() { const double unselectedLabelFontSize = 11.0; const double groupAlignment = 0.0; const NavigationRailLabelType labelType = NavigationRailLabelType.all; - const bool useIndicator = true; - const Color indicatorColor = Color(0x00000004); await tester.pumpWidget( MaterialApp( @@ -141,8 +132,6 @@ void main() { unselectedLabelTextStyle: TextStyle(fontSize: 7.0), groupAlignment: 1.0, labelType: NavigationRailLabelType.selected, - useIndicator: false, - indicatorColor: Color(0x00000096), ), child: NavigationRail( selectedIndex: 0, @@ -163,8 +152,6 @@ void main() { unselectedLabelTextStyle: const TextStyle(fontSize: unselectedLabelFontSize), groupAlignment: groupAlignment, labelType: labelType, - useIndicator: useIndicator, - indicatorColor: indicatorColor, ), ), ), @@ -183,8 +170,6 @@ void main() { expect(_unselectedLabelStyle(tester).fontSize, unselectedLabelFontSize); expect(_destinationsAlign(tester).alignment, Alignment.center); expect(_labelType(tester), labelType); - expect(find.byType(NavigationIndicator), findsWidgets); - expect(_indicatorDecoration(tester)?.color, indicatorColor); }); testWidgets('Default debugFillProperties', (WidgetTester tester) async { @@ -210,8 +195,6 @@ void main() { unselectedLabelTextStyle: TextStyle(fontSize: 7.0), groupAlignment: 1.0, labelType: NavigationRailLabelType.selected, - useIndicator: true, - indicatorColor: Color(0x00000096), ).debugFillProperties(builder); final List description = builder.properties @@ -232,8 +215,7 @@ void main() { expect(description[6], 'groupAlignment: 1.0'); expect(description[7], 'labelType: NavigationRailLabelType.selected'); - expect(description[8], 'useIndicator: true'); - expect(description[9], 'indicatorColor: Color(0x00000096)'); + }); } @@ -262,16 +244,6 @@ Material _railMaterial(WidgetTester tester) { ); } - -BoxDecoration? _indicatorDecoration(WidgetTester tester) { - return tester.firstWidget( - find.descendant( - of: find.byType(NavigationIndicator), - matching: find.byType(Container), - ), - ).decoration as BoxDecoration?; -} - IconThemeData _selectedIconTheme(WidgetTester tester) { return _iconTheme(tester, Icons.favorite); } diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index 8f1367a54361d..ef30649472d60 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -1593,85 +1593,6 @@ void main() { expect(tester.getSize(find.widgetWithText(OutlinedButton, '200x200')), const Size(200, 200)); expect(tester.getSize(find.widgetWithText(OutlinedButton, '200,200')), const Size(200, 200)); }); - - testWidgets('OutlinedButton changes mouse cursor when hovered', (WidgetTester tester) async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: OutlinedButton( - style: OutlinedButton.styleFrom( - enabledMouseCursor: SystemMouseCursors.text, - disabledMouseCursor: SystemMouseCursors.grab, - ), - onPressed: () {}, - child: const Text('button'), - ), - ), - ), - ); - - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); - await gesture.addPointer(location: Offset.zero); - addTearDown(gesture.removePointer); - - await tester.pump(); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); - - // Test cursor when disabled - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: OutlinedButton( - style: OutlinedButton.styleFrom( - enabledMouseCursor: SystemMouseCursors.text, - disabledMouseCursor: SystemMouseCursors.grab, - ), - onPressed: null, - child: const Text('button'), - ), - ), - ), - ); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab); - - // Test default cursor - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: OutlinedButton( - onPressed: () {}, - child: const Text('button'), - ), - ), - ), - ); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); - - // Test default cursor when disabled - await tester.pumpWidget( - const Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: OutlinedButton( - onPressed: null, - child: Text('button'), - ), - ), - ), - ); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); - }); } PhysicalModelLayer _findPhysicalLayer(Element element) { diff --git a/packages/flutter/test/material/paginated_data_table_test.dart b/packages/flutter/test/material/paginated_data_table_test.dart index 53649cf7a6271..ab3b89aed6b54 100644 --- a/packages/flutter/test/material/paginated_data_table_test.dart +++ b/packages/flutter/test/material/paginated_data_table_test.dart @@ -770,17 +770,13 @@ void main() { final TestDataSource source = TestDataSource(); // Note: 800 is wide enough to ensure that all of the columns fit in the - // Card. The test makes sure that the DataTable is exactly as wide - // as the Card, minus the Card's margin. + // Card. The DataTable can be larger than its containing Card, but this test + // is only concerned with ensuring the DataTable is at least as wide as the + // Card. const double _originalWidth = 800; const double _expandedWidth = 1600; const double _height = 400; - // By default, the margin of a Card is 4 in all directions, so - // the size of the DataTable (inside the Card) is horizontically - // reduced by 4 * 2; the left and right margins. - const double _cardMargin = 8; - final Size originalSize = binding.renderView.size; Widget buildWidget() => MaterialApp( @@ -804,23 +800,21 @@ void main() { await binding.setSurfaceSize(const Size(_originalWidth, _height)); await tester.pumpWidget(buildWidget()); - double cardWidth = tester.renderObject(find.byType(Card).first).size.width; - // Widths should be equal before we resize... expect( tester.renderObject(find.byType(DataTable).first).size.width, - moreOrLessEquals(cardWidth - _cardMargin), + moreOrLessEquals(tester.renderObject(find.byType(Card).first).size.width), ); await binding.setSurfaceSize(const Size(_expandedWidth, _height)); await tester.pumpWidget(buildWidget()); - cardWidth = tester.renderObject(find.byType(Card).first).size.width; + final double cardWidth = tester.renderObject(find.byType(Card).first).size.width; // ... and should still be equal after the resize. expect( tester.renderObject(find.byType(DataTable).first).size.width, - moreOrLessEquals(cardWidth - _cardMargin), + moreOrLessEquals(cardWidth), ); // Double check to ensure we actually resized the surface properly. diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 60d2cf30e2a58..1be98e78314bf 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -1471,72 +1471,6 @@ void main() { expect(tester.widget(find.widgetWithText(Container, 'Item 3')).padding, const EdgeInsets.all(20)); }); -testWidgets('PopupMenu custom padding', (WidgetTester tester) async { - final Key popupMenuButtonWithDefaultPaddingKey = UniqueKey(); - final Key popupMenuButtonWithOverriddenPaddingKey = UniqueKey(); - - const EdgeInsets padding = EdgeInsets.zero; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Column( - children: >[ - PopupMenuButton( - key: popupMenuButtonWithDefaultPaddingKey, - child: const Text('button'), - onSelected: (String result) {}, - itemBuilder: (BuildContext context) { - return >[ - const PopupMenuItem( - value: '0', - child: Text('Item 0'), - ), - ]; - }, - ), - PopupMenuButton( - menuPadding: padding, - key: popupMenuButtonWithOverriddenPaddingKey, - child: const Text('button'), - onSelected: (String result) {}, - itemBuilder: (BuildContext context) { - return >[ - const PopupMenuItem( - value: '0', - child: Text('Item 0'), - ), - ]; - }, - ) - ], - ), - ), - ), - ); - - final Finder popupFinder = find.byType(SingleChildScrollView); - // Show the menu - await tester.tap(find.byKey(popupMenuButtonWithDefaultPaddingKey)); - await tester.pumpAndSettle(); - - expect(tester.widget(popupFinder).padding, - const EdgeInsets.symmetric(vertical: 8), - reason: 'The popup without explicit paddings should utilise the default ones.',); - - // Close previous menu - await tester.tap(find.byKey(popupMenuButtonWithDefaultPaddingKey), warnIfMissed: false); - await tester.pumpAndSettle(); - - // Show the menu - await tester.tap(find.byKey(popupMenuButtonWithOverriddenPaddingKey)); - await tester.pumpAndSettle(); - - expect(tester.widget(popupFinder).padding, - padding, - reason: 'The popup should utilise explicitly set paddings.',); - }); - testWidgets('CheckedPopupMenuItem child height is a minimum, child is vertically centered', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const CheckedPopupMenuItem(child: Text('item')).runtimeType; diff --git a/packages/flutter/test/material/popup_menu_theme_test.dart b/packages/flutter/test/material/popup_menu_theme_test.dart index 6cedb7997e39f..444dabf1f806f 100644 --- a/packages/flutter/test/material/popup_menu_theme_test.dart +++ b/packages/flutter/test/material/popup_menu_theme_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -13,7 +12,6 @@ PopupMenuThemeData _popupMenuTheme() { shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12))), elevation: 12.0, textStyle: TextStyle(color: Color(0xffffffff), textBaseline: TextBaseline.alphabetic), - padding: EdgeInsets.symmetric(vertical: 6, horizontal: 6), ); } @@ -29,7 +27,6 @@ void main() { expect(popupMenuTheme.shape, null); expect(popupMenuTheme.elevation, null); expect(popupMenuTheme.textStyle, null); - expect(popupMenuTheme.mouseCursor, null); }); testWidgets('Default PopupMenuThemeData debugFillProperties', (WidgetTester tester) async { @@ -51,7 +48,6 @@ void main() { shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))), elevation: 2.0, textStyle: TextStyle(color: Color(0xffffffff)), - mouseCursor: MaterialStateMouseCursor.clickable, ).debugFillProperties(builder); final List description = builder.properties @@ -64,7 +60,6 @@ void main() { 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))', 'elevation: 2.0', 'text style: TextStyle(inherit: true, color: Color(0xffffffff))', - 'mouseCursor: MaterialStateMouseCursor(clickable)', ]); }); @@ -196,7 +191,6 @@ void main() { ); const double elevation = 7.0; const TextStyle textStyle = TextStyle(color: Color(0x00000000), textBaseline: TextBaseline.alphabetic); - const EdgeInsets menuPadding = EdgeInsets.zero; await tester.pumpWidget(MaterialApp( theme: ThemeData(popupMenuTheme: popupMenuTheme), @@ -209,7 +203,6 @@ void main() { elevation: elevation, color: color, shape: shape, - menuPadding: menuPadding, itemBuilder: (BuildContext context) { return >[ PopupMenuItem( @@ -253,21 +246,12 @@ void main() { ).last, ); expect(text.style, textStyle); - - /// PopupMenu widget is private so in order to test padding the widget - /// with the popup padding is extracted. - final SingleChildScrollView popupMenu = tester.widget - (find.byType(SingleChildScrollView)); - expect(popupMenu.padding, menuPadding); }); testWidgets('ThemeData.popupMenuTheme properties are utilized', (WidgetTester tester) async { final Key popupButtonKey = UniqueKey(); final Key popupButtonApp = UniqueKey(); - final Key enabledPopupItemKey = UniqueKey(); - final Key disabledPopupItemKey = UniqueKey(); - - const EdgeInsets themePadding = EdgeInsets.zero; + final Key popupItemKey = UniqueKey(); await tester.pumpWidget(MaterialApp( key: popupButtonApp, @@ -275,32 +259,19 @@ void main() { child: Column( children: [ PopupMenuTheme( - data: PopupMenuThemeData( + data: const PopupMenuThemeData( color: Colors.pink, - shape: const BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), + shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10))), elevation: 6.0, - textStyle: const TextStyle(color: Color(0xfffff000), textBaseline: TextBaseline.alphabetic), - mouseCursor: MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.disabled)) { - return SystemMouseCursors.contextMenu; - } - return SystemMouseCursors.alias; - }), - padding: themePadding, + textStyle: TextStyle(color: Color(0xfffff000), textBaseline: TextBaseline.alphabetic), ), child: PopupMenuButton( key: popupButtonKey, itemBuilder: (BuildContext context) { return >[ PopupMenuItem( - key: disabledPopupItemKey, - enabled: false, - child: const Text('disabled'), - ), - PopupMenuItem( - key: enabledPopupItemKey, - onTap: () { }, - child: const Text('enabled'), + key: popupItemKey, + child: const Text('Example'), ), ]; }, @@ -328,28 +299,16 @@ void main() { expect(button.shape, const BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10)))); expect(button.elevation, 6.0); + /// The last DefaultTextStyle widget under popupItemKey is the + /// [PopupMenuItem] specified above, so by finding the last descendent of + /// popupItemKey that is of type DefaultTextStyle, this code retrieves the + /// built [PopupMenuItem]. final DefaultTextStyle text = tester.widget( find.descendant( - of: find.byKey(enabledPopupItemKey), + of: find.byKey(popupItemKey), matching: find.byType(DefaultTextStyle), - ), + ).last, ); expect(text.style.color, const Color(0xfffff000)); - - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); - await gesture.addPointer(); - addTearDown(gesture.removePointer); - await gesture.moveTo(tester.getCenter(find.byKey(disabledPopupItemKey))); - await tester.pumpAndSettle(); - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.contextMenu); - await gesture.down(tester.getCenter(find.byKey(enabledPopupItemKey))); - await tester.pumpAndSettle(); - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.alias); - - /// PopupMenu widget is private so in order to test padding we extract - /// the widget which holds the padding. - final SingleChildScrollView popupMenu = tester.widget - (find.byType(SingleChildScrollView)); - expect(popupMenu.padding, themePadding); }); } diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 9ea516d6727ce..2d81980be76f1 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -822,34 +822,6 @@ void main() { }), ); - testWidgets( - 'Adaptive CircularProgressIndicator can use backgroundColor to change tick color for iOS', - (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: Scaffold( - body: Material( - child: CircularProgressIndicator.adaptive( - backgroundColor: Color(0xFF5D3FD3), - ), - ), - ), - ), - ); - - expect( - find.byType(CupertinoActivityIndicator), - paints - ..rrect(rrect: const RRect.fromLTRBXY(-1, -10 / 3, 1, -10, 1, 1), - color: const Color(0x935D3FD3)), - ); - }, - variant: const TargetPlatformVariant( { - TargetPlatform.iOS, - TargetPlatform.macOS, - }), - ); - testWidgets( 'Adaptive CircularProgressIndicator does not display CupertinoActivityIndicator in non-iOS', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/scrollbar_test.dart b/packages/flutter/test/material/scrollbar_test.dart index 5cc72d98d77bf..8910d40391dba 100644 --- a/packages/flutter/test/material/scrollbar_test.dart +++ b/packages/flutter/test/material/scrollbar_test.dart @@ -12,7 +12,6 @@ import 'dart:ui' as ui; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -1214,7 +1213,6 @@ void main() { }, variant: const TargetPlatformVariant({ TargetPlatform.fuchsia })); testWidgets('Scrollbar dragging is disabled by default on Android', (WidgetTester tester) async { - int tapCount = 0; final ScrollController scrollController = ScrollController(); await tester.pumpWidget( MaterialApp( @@ -1223,18 +1221,8 @@ void main() { child: Scrollbar( isAlwaysShown: true, controller: scrollController, - child: SingleChildScrollView( - dragStartBehavior: DragStartBehavior.down, - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - tapCount += 1; - }, - child: const SizedBox( - width: 4000.0, - height: 4000.0, - ), - ), + child: const SingleChildScrollView( + child: SizedBox(width: 4000.0, height: 4000.0), ), ), ), @@ -1262,49 +1250,30 @@ void main() { ); // Try to drag the thumb down. - const double scrollAmount = 50.0; - await tester.dragFrom( - const Offset(797.0, 45.0), - const Offset(0.0, scrollAmount), - touchSlopY: 0.0, - ); + const double scrollAmount = 10.0; + final TestGesture dragScrollbarThumbGesture = await tester.startGesture(const Offset(797.0, 45.0)); + await tester.pumpAndSettle(); + await dragScrollbarThumbGesture.moveBy(const Offset(0.0, scrollAmount)); + await tester.pumpAndSettle(); + await dragScrollbarThumbGesture.up(); await tester.pumpAndSettle(); // Dragging on the thumb does not change the offset. expect(scrollController.offset, 0.0); - expect(tapCount, 0); - - // Try to drag up in the thumb area to validate pass through to scrollable. - await tester.dragFrom( - const Offset(797.0, 45.0), - const Offset(0.0, -scrollAmount), - ); - await tester.pumpAndSettle(); - // The scroll view received the drag. - expect(scrollController.offset, scrollAmount); - expect(tapCount, 0); // Drag in the track area to validate pass through to scrollable. - await tester.dragFrom( - const Offset(797.0, 45.0), - const Offset(0.0, -scrollAmount), - touchSlopY: 0.0, - ); + final TestGesture dragPassThroughTrack = await tester.startGesture(const Offset(797.0, 250.0)); + await dragPassThroughTrack.moveBy(const Offset(0.0, -scrollAmount)); await tester.pumpAndSettle(); - // The scroll view received the drag. - expect(scrollController.offset, scrollAmount * 2); - expect(tapCount, 0); - - // Tap on the thumb to validate the scroll view receives a click. - await tester.tapAt(const Offset(797.0, 45.0)); + await dragPassThroughTrack.up(); await tester.pumpAndSettle(); - expect(tapCount, 1); + // The scroll view received the drag. + expect(scrollController.offset, scrollAmount); - // Tap on the track to validate the scroll view will not page and receives a click. - await tester.tapAt(const Offset(797.0, 400.0)); + // Tap on the track to validate the scroll view will not page. + await tester.tapAt(const Offset(797.0, 200.0)); await tester.pumpAndSettle(); // The offset should not have changed. - expect(scrollController.offset, scrollAmount * 2); - expect(tapCount, 2); + expect(scrollController.offset, scrollAmount); }); testWidgets('Simultaneous dragging and pointer scrolling does not cause a crash', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/scrollbar_theme_test.dart b/packages/flutter/test/material/scrollbar_theme_test.dart index 1032e32e40ac9..7aa97ab38093c 100644 --- a/packages/flutter/test/material/scrollbar_theme_test.dart +++ b/packages/flutter/test/material/scrollbar_theme_test.dart @@ -574,52 +574,6 @@ void main() { }), ); - testWidgets('ScrollbarThemeData.trackVisibility test', (WidgetTester tester) async { - final ScrollController scrollController = ScrollController(); - bool? _getTrackVisibility(Set states) { - return true; - } - await tester.pumpWidget( - MaterialApp( - theme: ThemeData().copyWith( - scrollbarTheme: _scrollbarTheme( - trackVisibility: MaterialStateProperty.resolveWith(_getTrackVisibility), - ), - ), - home: ScrollConfiguration( - behavior: const NoScrollbarBehavior(), - child: Scrollbar( - isAlwaysShown: true, - showTrackOnHover: true, - controller: scrollController, - child: SingleChildScrollView( - controller: scrollController, - child: const SizedBox(width: 4000.0, height: 4000.0), - ), - ), - ), - ), - ); - await tester.pumpAndSettle(); - - expect( - find.byType(Scrollbar), - paints - ..rect(color: const Color(0x08000000)) - ..line( - strokeWidth: 1.0, - color: const Color(0x1a000000), - ) - ..rrect(color: const Color(0xff4caf50)), - ); - }, variant: const TargetPlatformVariant({ - TargetPlatform.linux, - TargetPlatform.macOS, - TargetPlatform.windows, - TargetPlatform.fuchsia, - }), - ); - testWidgets('Default ScrollbarTheme debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ScrollbarThemeData().debugFillProperties(builder); @@ -682,7 +636,6 @@ class NoScrollbarBehavior extends ScrollBehavior { ScrollbarThemeData _scrollbarTheme({ MaterialStateProperty? thickness, - MaterialStateProperty? trackVisibility, bool showTrackOnHover = true, bool isAlwaysShown = true, Radius radius = const Radius.circular(6.0), @@ -695,7 +648,6 @@ ScrollbarThemeData _scrollbarTheme({ }) { return ScrollbarThemeData( thickness: thickness ?? MaterialStateProperty.resolveWith(_getThickness), - trackVisibility: trackVisibility, showTrackOnHover: showTrackOnHover, isAlwaysShown: isAlwaysShown, radius: radius, diff --git a/packages/flutter/test/material/search_test.dart b/packages/flutter/test/material/search_test.dart index a24eab7f90ca3..bb97fbef246e9 100644 --- a/packages/flutter/test/material/search_test.dart +++ b/packages/flutter/test/material/search_test.dart @@ -629,8 +629,7 @@ void main() { debugDefaultTargetPlatformOverride != TargetPlatform.macOS) SemanticsFlag.namesRoute, ], actions: [ - if (debugDefaultTargetPlatformOverride == TargetPlatform.macOS || - debugDefaultTargetPlatformOverride == TargetPlatform.windows) + if (debugDefaultTargetPlatformOverride == TargetPlatform.macOS) SemanticsAction.didGainAccessibilityFocus, SemanticsAction.tap, SemanticsAction.setSelection, @@ -1020,6 +1019,14 @@ class _TestSearchDelegate extends SearchDelegate { } class _TestEmptySearchDelegate extends SearchDelegate { + _TestEmptySearchDelegate({ + this.suggestions = 'Suggestions', + this.result = 'Result', + }) : super(); + + final String suggestions; + final String result; + @override Widget? buildLeading(BuildContext context) => null; @@ -1032,7 +1039,7 @@ class _TestEmptySearchDelegate extends SearchDelegate { onPressed: () { showResults(context); }, - child: const Text('Suggestions'), + child: Text(suggestions), ); } @@ -1049,7 +1056,7 @@ class _TestEmptySearchDelegate extends SearchDelegate { tooltip: 'Close', icon: const Icon(Icons.arrow_back), onPressed: () { - close(context, 'Result'); + close(context, result); }, ), ); diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index fc0854210009c..8897d5e3e7e5e 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -70,35 +70,6 @@ class TallSliderTickMarkShape extends SliderTickMarkShape { } } -class _StateDependentMouseCursor extends MaterialStateMouseCursor { - const _StateDependentMouseCursor({ - this.disabled = SystemMouseCursors.none, - this.dragged = SystemMouseCursors.none, - this.hovered = SystemMouseCursors.none, - }); - - final MouseCursor disabled; - final MouseCursor hovered; - final MouseCursor dragged; - - @override - MouseCursor resolve(Set states) { - if (states.contains(MaterialState.disabled)) { - return disabled; - } - if (states.contains(MaterialState.dragged)) { - return dragged; - } - if (states.contains(MaterialState.hovered)) { - return hovered; - } - return SystemMouseCursors.none; - } - - @override - String get debugDescription => '_StateDependentMouseCursor'; -} - void main() { testWidgets('Slider can move when tapped (LTR)', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); @@ -1351,16 +1322,8 @@ void main() { children: [ TestSemantics( id: 4, - flags: [ - SemanticsFlag.hasEnabledState, - SemanticsFlag.isEnabled, - SemanticsFlag.isFocusable, - SemanticsFlag.isSlider, - ], - actions: [ - SemanticsAction.increase, - SemanticsAction.decrease, - ], + flags: [SemanticsFlag.hasEnabledState, SemanticsFlag.isEnabled, SemanticsFlag.isFocusable, SemanticsFlag.isSlider], + actions: [SemanticsAction.increase, SemanticsAction.decrease], value: '50%', increasedValue: '55%', decreasedValue: '45%', @@ -1476,7 +1439,7 @@ void main() { ); semantics.dispose(); - }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux })); + }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); testWidgets('Slider Semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); @@ -1589,175 +1552,6 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Slider Semantics', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - - await tester.pumpWidget(MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: Material( - child: Slider( - value: 0.5, - onChanged: (double v) { }, - ), - ), - ), - )); - - await tester.pumpAndSettle(); - - expect( - semantics, - hasSemantics( - TestSemantics.root( - children: [ - TestSemantics( - id: 1, - textDirection: TextDirection.ltr, - children: [ - TestSemantics( - id: 2, - children: [ - TestSemantics( - id: 3, - flags: [SemanticsFlag.scopesRoute], - children: [ - TestSemantics( - id: 4, - flags: [ - SemanticsFlag.hasEnabledState, - SemanticsFlag.isEnabled, - SemanticsFlag.isFocusable, - SemanticsFlag.isSlider, - ], - actions: [ - SemanticsAction.increase, - SemanticsAction.decrease, - SemanticsAction.didGainAccessibilityFocus, - ], - value: '50%', - increasedValue: '55%', - decreasedValue: '45%', - textDirection: TextDirection.ltr, - ), - ], - ), - ], - ), - ], - ), - ], - ), - ignoreRect: true, - ignoreTransform: true, - ), - ); - - // Disable slider - await tester.pumpWidget(const MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: Material( - child: Slider( - value: 0.5, - onChanged: null, - ), - ), - ), - )); - - expect( - semantics, - hasSemantics( - TestSemantics.root( - children: [ - TestSemantics( - id: 1, - textDirection: TextDirection.ltr, - children: [ - TestSemantics( - id: 2, - children: [ - TestSemantics( - id: 3, - flags: [SemanticsFlag.scopesRoute], - children: [ - TestSemantics( - id: 4, - flags: [ - SemanticsFlag.hasEnabledState, - // isFocusable is delayed by 1 frame. - SemanticsFlag.isFocusable, - SemanticsFlag.isSlider, - ], - actions: [ - SemanticsAction.didGainAccessibilityFocus, - ], - value: '50%', - increasedValue: '55%', - decreasedValue: '45%', - textDirection: TextDirection.ltr, - ), - ], - ), - ], - ), - ], - ), - ], - ), - ignoreRect: true, - ignoreTransform: true, - ), - ); - - await tester.pump(); - expect( - semantics, - hasSemantics( - TestSemantics.root( - children: [ - TestSemantics( - id: 1, - textDirection: TextDirection.ltr, - children: [ - TestSemantics( - id: 2, - children: [ - TestSemantics( - id: 3, - flags: [SemanticsFlag.scopesRoute], - children: [ - TestSemantics( - id: 4, - flags: [ - SemanticsFlag.hasEnabledState, - SemanticsFlag.isSlider, - ], - actions: [ - SemanticsAction.didGainAccessibilityFocus, - ], - value: '50%', - increasedValue: '55%', - decreasedValue: '45%', - textDirection: TextDirection.ltr, - ), - ], - ), - ], - ), - ], - ), - ], - ), - ignoreRect: true, - ignoreTransform: true, - ), - ); - - semantics.dispose(); - }, variant: const TargetPlatformVariant({ TargetPlatform.windows })); - testWidgets('Slider semantics with custom formatter', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); @@ -2093,73 +1887,6 @@ void main() { expect(value, 0.5); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Slider gains keyboard focus when it gains semantics focus on Windows', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Slider( - value: 0.5, - onChanged: (double _) {}, - focusNode: focusNode, - ), - ), - ), - ); - - expect(semantics, hasSemantics( - TestSemantics.root( - children: [ - TestSemantics( - id: 1, - textDirection: TextDirection.ltr, - children: [ - TestSemantics( - id: 2, - children: [ - TestSemantics( - id: 3, - flags: [SemanticsFlag.scopesRoute], - children: [ - TestSemantics( - id: 4, - flags: [ - SemanticsFlag.hasEnabledState, - SemanticsFlag.isEnabled, - SemanticsFlag.isFocusable, - SemanticsFlag.isSlider, - ], - actions: [ - SemanticsAction.increase, - SemanticsAction.decrease, - SemanticsAction.didGainAccessibilityFocus, - ], - value: '50%', - increasedValue: '55%', - decreasedValue: '45%', - textDirection: TextDirection.ltr, - ), - ], - ), - ], - ), - ], - ), - ], - ), - ignoreRect: true, - ignoreTransform: true, - )); - - expect(focusNode.hasFocus, isFalse); - semanticsOwner.performAction(4, SemanticsAction.didGainAccessibilityFocus); - await tester.pumpAndSettle(); - expect(focusNode.hasFocus, isTrue); - semantics.dispose(); - }, variant: const TargetPlatformVariant({ TargetPlatform.windows })); - testWidgets('Value indicator appears when it should', (WidgetTester tester) async { final ThemeData baseTheme = ThemeData( platform: TargetPlatform.android, @@ -2411,11 +2138,11 @@ void main() { expect(find.byType(Slider), findsOneWidget); expect(find.byType(CupertinoSlider), findsOneWidget); - expect(value, 0.5, reason: 'on ${platform.name}'); + expect(value, 0.5, reason: 'on ${describeEnum(platform)}'); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(CupertinoSlider))); // Drag to the right end of the track. await gesture.moveBy(const Offset(600.0, 0.0)); - expect(value, 1.0, reason: 'on ${platform.name}'); + expect(value, 1.0, reason: 'on ${describeEnum(platform)}'); await gesture.up(); } @@ -2426,11 +2153,11 @@ void main() { expect(find.byType(Slider), findsOneWidget); expect(find.byType(CupertinoSlider), findsNothing); - expect(value, 0.5, reason: 'on ${platform.name}'); + expect(value, 0.5, reason: 'on ${describeEnum(platform)}'); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Slider))); // Drag to the right end of the track. await gesture.moveBy(const Offset(600.0, 0.0)); - expect(value, 1.0, reason: 'on ${platform.name}'); + expect(value, 1.0, reason: 'on ${describeEnum(platform)}'); await gesture.up(); } }); @@ -2550,57 +2277,6 @@ void main() { expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets('Slider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { - const MouseCursor disabledCursor = SystemMouseCursors.basic; - const MouseCursor hoveredCursor = SystemMouseCursors.grab; - const MouseCursor draggedCursor = SystemMouseCursors.move; - - Widget buildFrame({ required bool enabled }) { - return MaterialApp( - home: Directionality( - textDirection: TextDirection.ltr, - child: Material( - child: Center( - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: Slider( - mouseCursor: const _StateDependentMouseCursor( - disabled: disabledCursor, - hovered: hoveredCursor, - dragged: draggedCursor, - ), - value: 0.5, - onChanged: enabled ? (double newValue) { } : null, - ), - ), - ), - ), - ), - ); - } - - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); - await gesture.addPointer(location: Offset.zero); - addTearDown(gesture.removePointer); - - await tester.pumpWidget(buildFrame(enabled: false)); - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), disabledCursor); - - await tester.pumpWidget(buildFrame(enabled: true)); - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.none); - - await gesture.moveTo(tester.getCenter(find.byType(Slider))); // start hover - await tester.pumpAndSettle(); - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), hoveredCursor); - - await tester.timedDrag( - find.byType(Slider), - const Offset(20.0, 0.0), - const Duration(milliseconds: 100), - ); - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.move); - }); - testWidgets('Slider implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index 38e8d3337d21a..1d00f37a617e4 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -4,7 +4,6 @@ import 'dart:ui' show window; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -58,7 +57,6 @@ void main() { rangeValueIndicatorShape: PaddleRangeSliderValueIndicatorShape(), showValueIndicator: ShowValueIndicator.always, valueIndicatorTextStyle: TextStyle(color: Colors.black), - mouseCursor: MaterialStateMouseCursor.clickable, ).debugFillProperties(builder); final List description = builder.properties @@ -92,7 +90,6 @@ void main() { "rangeValueIndicatorShape: Instance of 'PaddleRangeSliderValueIndicatorShape'", 'showValueIndicator: always', 'valueIndicatorTextStyle: TextStyle(inherit: true, color: Color(0xff000000))', - 'mouseCursor: MaterialStateMouseCursor(clickable)' ]); }); @@ -1245,21 +1242,6 @@ void main() { ); }); - testWidgets('The mouse cursor is themeable', (WidgetTester tester) async { - await tester.pumpWidget(_buildApp( - ThemeData().sliderTheme.copyWith( - mouseCursor: MaterialStateProperty.all(SystemMouseCursors.text), - ) - )); - - await tester.pumpAndSettle(); - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); - await gesture.addPointer(); - addTearDown(gesture.removePointer); - await gesture.moveTo(tester.getCenter(find.byType(Slider))); - await tester.pumpAndSettle(); - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); - }); } class RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight extends RoundedRectSliderTrackShape { diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart index 47ce364cf5f67..6ce3a4aee6fb3 100644 --- a/packages/flutter/test/material/switch_list_tile_test.dart +++ b/packages/flutter/test/material/switch_list_tile_test.dart @@ -198,10 +198,10 @@ void main() { value = false; await tester.pumpWidget(buildFrame(platform)); expect(find.byType(CupertinoSwitch), findsOneWidget); - expect(value, isFalse, reason: 'on ${platform.name}'); + expect(value, isFalse, reason: 'on ${describeEnum(platform)}'); await tester.tap(find.byType(SwitchListTile)); - expect(value, isTrue, reason: 'on ${platform.name}'); + expect(value, isTrue, reason: 'on ${describeEnum(platform)}'); } for (final TargetPlatform platform in [ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows ]) { @@ -210,9 +210,9 @@ void main() { await tester.pumpAndSettle(); // Finish the theme change animation. expect(find.byType(CupertinoSwitch), findsNothing); - expect(value, isFalse, reason: 'on ${platform.name}'); + expect(value, isFalse, reason: 'on ${describeEnum(platform)}'); await tester.tap(find.byType(SwitchListTile)); - expect(value, isTrue, reason: 'on ${platform.name}'); + expect(value, isTrue, reason: 'on ${describeEnum(platform)}'); } }); diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index 73c205ae36b16..c15d1dc91e283 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -752,14 +752,14 @@ void main() { for (final TargetPlatform platform in [ TargetPlatform.iOS, TargetPlatform.macOS ]) { value = false; await tester.pumpWidget(buildFrame(platform)); - expect(find.byType(CupertinoSwitch), findsOneWidget, reason: 'on ${platform.name}'); + expect(find.byType(CupertinoSwitch), findsOneWidget, reason: 'on ${describeEnum(platform)}'); final CupertinoSwitch adaptiveSwitch = tester.widget(find.byType(CupertinoSwitch)); - expect(adaptiveSwitch.trackColor, inactiveTrackColor, reason: 'on ${platform.name}'); + expect(adaptiveSwitch.trackColor, inactiveTrackColor, reason: 'on ${describeEnum(platform)}'); - expect(value, isFalse, reason: 'on ${platform.name}'); + expect(value, isFalse, reason: 'on ${describeEnum(platform)}'); await tester.tap(find.byType(Switch)); - expect(value, isTrue, reason: 'on ${platform.name}'); + expect(value, isTrue, reason: 'on ${describeEnum(platform)}'); } for (final TargetPlatform platform in [ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows ]) { @@ -767,9 +767,9 @@ void main() { await tester.pumpWidget(buildFrame(platform)); await tester.pumpAndSettle(); // Finish the theme change animation. expect(find.byType(CupertinoSwitch), findsNothing); - expect(value, isFalse, reason: 'on ${platform.name}'); + expect(value, isFalse, reason: 'on ${describeEnum(platform)}'); await tester.tap(find.byType(Switch)); - expect(value, isTrue, reason: 'on ${platform.name}'); + expect(value, isTrue, reason: 'on ${describeEnum(platform)}'); } }); diff --git a/packages/flutter/test/material/tab_bar_theme_test.dart b/packages/flutter/test/material/tab_bar_theme_test.dart index 33fb1ab9f374e..319554c2ae61d 100644 --- a/packages/flutter/test/material/tab_bar_theme_test.dart +++ b/packages/flutter/test/material/tab_bar_theme_test.dart @@ -54,21 +54,6 @@ RenderParagraph _iconRenderObject(WidgetTester tester, IconData icon) { } void main() { - test('TabBarTheme copyWith, ==, hashCode, defaults', () { - expect(const TabBarTheme(), const TabBarTheme().copyWith()); - expect(const TabBarTheme().hashCode, const TabBarTheme().copyWith().hashCode); - - expect(const TabBarTheme().indicator, null); - expect(const TabBarTheme().indicatorSize, null); - expect(const TabBarTheme().labelColor, null); - expect(const TabBarTheme().labelPadding, null); - expect(const TabBarTheme().labelStyle, null); - expect(const TabBarTheme().unselectedLabelColor, null); - expect(const TabBarTheme().unselectedLabelStyle, null); - expect(const TabBarTheme().overlayColor, null); - expect(const TabBarTheme().splashFactory, null); - }); - testWidgets('Tab bar defaults - label style and selected/unselected label colors', (WidgetTester tester) async { // tests for the default label color and label styles when tabBarTheme and tabBar do not provide any await tester.pumpWidget(_withTheme(null)); diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index 3c98bb128110d..be68626dde837 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -109,11 +109,9 @@ Widget buildFrame({ required String value, bool isScrollable = false, Color? indicatorColor, - Duration? animationDuration, }) { return boilerplate( child: DefaultTabController( - animationDuration: animationDuration, initialIndex: tabs.indexOf(value), length: tabs.length, child: TabBar( @@ -939,262 +937,6 @@ void main() { expect(find.text('Second'), findsNothing); }); - testWidgets('TabBar animationDuration sets indicator animation duration', (WidgetTester tester) async { - const Duration animationDuration = Duration(milliseconds: 100); - final List tabs = ['A', 'B', 'C']; - - await tester.pumpWidget(buildFrame(tabs: tabs, value: 'B', animationDuration: animationDuration)); - final TabController controller = DefaultTabController.of(tester.element(find.text('A')))!; - - await tester.tap(find.text('A')); - await tester.pump(); - expect(controller.indexIsChanging, true); - await tester.pump(const Duration(milliseconds: 50)); - await tester.pump(animationDuration); - expect(controller.index, 0); - expect(controller.previousIndex, 1); - expect(controller.indexIsChanging, false); - - //Test when index diff is greater than 1 - await tester.pumpWidget(buildFrame(tabs: tabs, value: 'B', animationDuration: animationDuration)); - await tester.tap(find.text('C')); - await tester.pump(); - expect(controller.indexIsChanging, true); - await tester.pump(const Duration(milliseconds: 50)); - await tester.pump(animationDuration); - expect(controller.index, 2); - expect(controller.previousIndex, 0); - expect(controller.indexIsChanging, false); - }); - - testWidgets('TabBarView controller sets animation duration', (WidgetTester tester) async { - const Duration animationDuration = Duration(milliseconds: 100); - final List tabs = ['A', 'B', 'C']; - - final TabController tabController = TabController( - vsync: const TestVSync(), - initialIndex: 1, - length: tabs.length, - animationDuration: animationDuration, - ); - await tester.pumpWidget(boilerplate( - child: Column( - children: [ - TabBar( - tabs: tabs.map((String tab) => Tab(text: tab)).toList(), - controller: tabController, - ), - SizedBox( - width: 400.0, - height: 400.0, - child: TabBarView( - controller: tabController, - children: const [ - Center(child: Text('0')), - Center(child: Text('1')), - Center(child: Text('2')), - ], - ), - ), - ], - ), - )); - - expect(tabController.index, 1); - - final PageView pageView = tester.widget(find.byType(PageView)); - final PageController pageController = pageView.controller; - final ScrollPosition position = pageController.position; - - // The TabBarView's page width is 400, so page 0 is at scroll offset 0.0, - // page 1 is at 400.0, page 2 is at 800.0. - expect(position.pixels, 400); - await tester.tap(find.text('C')); - await tester.pump(); - expect(position.pixels, 400); - await tester.pump(const Duration(milliseconds: 50)); - await tester.pump(animationDuration); - expect(position.pixels, 800); - }); - - testWidgets('TabBar tap skips indicator animation when disabled in controller', (WidgetTester tester) async { - final List tabs = ['A', 'B']; - - const Color indicatorColor = Color(0xFFFF0000); - await tester.pumpWidget(buildFrame(tabs: tabs, value: 'A', indicatorColor: indicatorColor, animationDuration: Duration.zero)); - - final RenderBox box = tester.renderObject(find.byType(TabBar)); - final TabIndicatorRecordingCanvas canvas = TabIndicatorRecordingCanvas(indicatorColor); - final TestRecordingPaintingContext context = TestRecordingPaintingContext(canvas); - - box.paint(context, Offset.zero); - final Rect indicatorRect0 = canvas.indicatorRect; - expect(indicatorRect0.left, 0.0); - expect(indicatorRect0.width, 400.0); - expect(indicatorRect0.height, 2.0); - - await tester.tap(find.text('B')); - await tester.pump(); - box.paint(context, Offset.zero); - final Rect indicatorRect2 = canvas.indicatorRect; - expect(indicatorRect2.left, 400.0); - expect(indicatorRect2.width, 400.0); - expect(indicatorRect2.height, 2.0); - }); - - testWidgets('TabBar tap changes index instantly when animation is disabled in controller', (WidgetTester tester) async { - final List tabs = ['A', 'B', 'C']; - - await tester.pumpWidget(buildFrame(tabs: tabs, value: 'B', animationDuration: Duration.zero)); - final TabController controller = DefaultTabController.of(tester.element(find.text('A')))!; - - await tester.tap(find.text('A')); - await tester.pump(); - expect(controller.index, 0); - expect(controller.previousIndex, 1); - expect(controller.indexIsChanging, false); - - //Test when index diff is greater than 1 - await tester.pumpWidget(buildFrame(tabs: tabs, value: 'B', animationDuration: Duration.zero)); - await tester.tap(find.text('C')); - await tester.pump(); - expect(controller.index, 2); - expect(controller.previousIndex, 0); - expect(controller.indexIsChanging, false); - }); - - testWidgets('TabBarView skips animation when disabled in controller', (WidgetTester tester) async { - final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( - vsync: const TestVSync(), - initialIndex: 1, - length: tabs.length, - animationDuration: Duration.zero, - ); - await tester.pumpWidget(boilerplate( - child: Column( - children: [ - TabBar( - tabs: tabs.map((String tab) => Tab(text: tab)).toList(), - controller: tabController, - ), - SizedBox( - width: 400.0, - height: 400.0, - child: TabBarView( - controller: tabController, - children: const [ - Center(child: Text('0')), - Center(child: Text('1')), - Center(child: Text('2')), - ], - ), - ), - ], - ), - )); - - expect(tabController.index, 1); - - final PageView pageView = tester.widget(find.byType(PageView)); - final PageController pageController = pageView.controller; - final ScrollPosition position = pageController.position; - - // The TabBarView's page width is 400, so page 0 is at scroll offset 0.0, - // page 1 is at 400.0, page 2 is at 800.0. - expect(position.pixels, 400); - await tester.tap(find.text('C')); - await tester.pump(); - expect(position.pixels, 800); - }); - - testWidgets('TabBarView skips animation when disabled in controller - skip tabs', (WidgetTester tester) async { - final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( - vsync: const TestVSync(), - length: tabs.length, - animationDuration: Duration.zero, - ); - await tester.pumpWidget(boilerplate( - child: Column( - children: [ - TabBar( - tabs: tabs.map((String tab) => Tab(text: tab)).toList(), - controller: tabController, - ), - SizedBox( - width: 400.0, - height: 400.0, - child: TabBarView( - controller: tabController, - children: const [ - Center(child: Text('0')), - Center(child: Text('1')), - Center(child: Text('2')), - ], - ), - ), - ], - ), - )); - - expect(tabController.index, 0); - - final PageView pageView = tester.widget(find.byType(PageView)); - final PageController pageController = pageView.controller; - final ScrollPosition position = pageController.position; - - // The TabBarView's page width is 400, so page 0 is at scroll offset 0.0, - // page 1 is at 400.0, page 2 is at 800.0. - expect(position.pixels, 0); - await tester.tap(find.text('C')); - await tester.pump(); - expect(position.pixels, 800); - }); - - testWidgets('TabBarView skips animation when disabled in controller - two tabs', (WidgetTester tester) async { - final List tabs = ['A', 'B']; - final TabController tabController = TabController( - vsync: const TestVSync(), - length: tabs.length, - animationDuration: Duration.zero, - ); - await tester.pumpWidget(boilerplate( - child: Column( - children: [ - TabBar( - tabs: tabs.map((String tab) => Tab(text: tab)).toList(), - controller: tabController, - ), - SizedBox( - width: 400.0, - height: 400.0, - child: TabBarView( - controller: tabController, - children: const [ - Center(child: Text('0')), - Center(child: Text('1')), - ], - ), - ), - ], - ), - )); - - expect(tabController.index, 0); - - final PageView pageView = tester.widget(find.byType(PageView)); - final PageController pageController = pageView.controller; - final ScrollPosition position = pageController.position; - - // The TabBarView's page width is 400, so page 0 is at scroll offset 0.0, - // page 1 is at 400.0, page 2 is at 800.0. - expect(position.pixels, 0); - await tester.tap(find.text('B')); - await tester.pump(); - expect(position.pixels, 400); - }); - testWidgets('TabBar tap animates the selection indicator', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/7479 @@ -3136,7 +2878,6 @@ void main() { }, ); }); - testWidgets('Skipping tabs with global key does not crash', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/24660 final List tabs = [ @@ -3434,9 +3175,9 @@ void main() { title: const Text('Default TabBar Preview'), bottom: tabTextContent.isNotEmpty ? TabBar( - isScrollable: true, - tabs: tabTextContent.map((String textContent) => Tab(text: textContent)).toList(), - ) + isScrollable: true, + tabs: tabTextContent.map((String textContent) => Tab(text: textContent)).toList(), + ) : null, ), body: tabTextContent.isNotEmpty @@ -3491,96 +3232,31 @@ void main() { expect(find.text('No tabs'), findsOneWidget); }); - testWidgets('DefaultTabController should allow dynamic length of tabs', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/94504. - final List tabTitles = []; - - void _onTabAdd(StateSetter setState) { - setState(() { - tabTitles.add('Tab ${tabTitles.length + 1}'); - }); - } - - void _onTabRemove(StateSetter setState) { - setState(() { - tabTitles.removeLast(); - }); - } - - await tester.pumpWidget( - MaterialApp( - home: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DefaultTabController( - length: tabTitles.length, - child: Scaffold( - appBar: AppBar( - actions: [ - TextButton( - key: const Key('Add tab'), - child: const Text('Add tab'), - onPressed: () => _onTabAdd(setState), - ), - TextButton( - key: const Key('Remove tab'), - child: const Text('Remove tab'), - onPressed: () => _onTabRemove(setState), - ), - ], - bottom: PreferredSize( - preferredSize: const Size.fromHeight(40.0), - child: Expanded( - child: TabBar( - tabs: tabTitles - .map((String title) => Tab(text: title)) - .toList(), - ), - ), - ), - ), - ), - ); - }, - ), - ), - ); - - expect(find.text('Tab 1'), findsNothing); - expect(find.text('Tab 2'), findsNothing); - - await tester.tap(find.byKey(const Key('Add tab'))); // +1 - await tester.pumpAndSettle(); - expect(find.text('Tab 1'), findsOneWidget); - expect(find.text('Tab 2'), findsNothing); - - await tester.tap(find.byKey(const Key('Add tab'))); // +2 - await tester.pumpAndSettle(); - expect(find.text('Tab 1'), findsOneWidget); - expect(find.text('Tab 2'), findsOneWidget); - - await tester.tap(find.byKey(const Key('Remove tab'))); // -2 - await tester.tap(find.byKey(const Key('Remove tab'))); // -1 - await tester.pumpAndSettle(); - expect(find.text('Tab 1'), findsNothing); - expect(find.text('Tab 2'), findsNothing); - }); - testWidgets('TabBar - updating to and from zero tabs', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/68962. final List tabTitles = []; - TabController _tabController = TabController(length: tabTitles.length, vsync: const TestVSync()); + final List tabContents = []; + TabController _tabController = TabController(length: tabContents.length, vsync: const TestVSync()); void _onTabAdd(StateSetter setState) { setState(() { tabTitles.add('Tab ${tabTitles.length + 1}'); - _tabController = TabController(length: tabTitles.length, vsync: const TestVSync()); + tabContents.add( + Container( + color: Colors.red, + height: 200, + width: 200, + ), + ); + _tabController = TabController(length: tabContents.length, vsync: const TestVSync()); }); } void _onTabRemove(StateSetter setState) { setState(() { tabTitles.removeLast(); - _tabController = TabController(length: tabTitles.length, vsync: const TestVSync()); + tabContents.removeLast(); + _tabController = TabController(length: tabContents.length, vsync: const TestVSync()); }); } @@ -4249,135 +3925,6 @@ void main() { semantics.dispose(); }); - - testWidgets('Change the TabController should make both TabBar and TabBarView return to the initial index.', (WidgetTester tester) async { - // This is a regression test for https://github.com/flutter/flutter/issues/93237 - - Widget buildFrame(TabController controller, bool showLast) { - return boilerplate( - child: Column( - children: [ - TabBar( - controller: controller, - tabs: [ - const Tab(text: 'one'), - const Tab(text: 'two'), - if (showLast) const Tab(text: 'three'), - ], - ), - Flexible( - child: TabBarView( - controller: controller, - children: [ - const Text('PAGE1'), - const Text('PAGE2'), - if (showLast) const Text('PAGE3'), - ], - ), - ), - ], - ), - ); - } - - final TabController controller1 = TabController( - vsync: const TestVSync(), - length: 3, - ); - - final TabController controller2 = TabController( - vsync: const TestVSync(), - length: 2, - ); - - final TabController controller3 = TabController( - vsync: const TestVSync(), - length: 3, - ); - - await tester.pumpWidget(buildFrame(controller1, true)); - final PageView pageView = tester.widget(find.byType(PageView)); - final PageController pageController = pageView.controller; - - await tester.tap(find.text('three')); - await tester.pumpAndSettle(); - expect(controller1.index, 2); - expect(pageController.page, 2); - - // Change TabController from 3 items to 2. - await tester.pumpWidget(buildFrame(controller2, false)); - await tester.pumpAndSettle(); - expect(controller2.index, 0); - expect(pageController.page, 0); - - // Change TabController from 2 items to 3. - await tester.pumpWidget(buildFrame(controller3, true)); - await tester.pumpAndSettle(); - expect(controller3.index, 0); - expect(pageController.page, 0); - - await tester.tap(find.text('three')); - await tester.pumpAndSettle(); - - expect(controller3.index, 2); - expect(pageController.page, 2); - }); - - testWidgets('TabBar InkWell splashFactory and overlayColor', (WidgetTester tester) async { - const InteractiveInkFeatureFactory splashFactory = NoSplash.splashFactory; - final MaterialStateProperty overlayColor = MaterialStateProperty.resolveWith( - (Set states) => Colors.transparent, - ); - - // TabBarTheme splashFactory and overlayColor - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.light().copyWith( - tabBarTheme: TabBarTheme( - splashFactory: splashFactory, - overlayColor: overlayColor, - )), - home: DefaultTabController( - length: 1, - child: Scaffold( - appBar: AppBar( - bottom: TabBar( - tabs: [ - Container(width: 100, height: 100, color: Colors.green), - ], - ), - ), - ), - ), - ), - ); - - expect(tester.widget(find.byType(InkWell)).splashFactory, splashFactory); - expect(tester.widget(find.byType(InkWell)).overlayColor, overlayColor); - - // TabBar splashFactory and overlayColor - await tester.pumpWidget( - MaterialApp( - home: DefaultTabController( - length: 1, - child: Scaffold( - appBar: AppBar( - bottom: TabBar( - splashFactory: splashFactory, - overlayColor: overlayColor, - tabs: [ - Container(width: 100, height: 100, color: Colors.green), - ], - ), - ), - ), - ), - ), - ); - await tester.pumpAndSettle(); // theme animation - expect(tester.widget(find.byType(InkWell)).splashFactory, splashFactory); - expect(tester.widget(find.byType(InkWell)).overlayColor, overlayColor); - }); } class KeepAliveInk extends StatefulWidget { diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index c8b4b6cc18513..45a3a9c8fea12 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -1391,84 +1391,6 @@ void main() { expect(tester.getSize(find.widgetWithText(TextButton, '200,200')), const Size(200, 200)); }); - testWidgets('TextButton changes mouse cursor when hovered', (WidgetTester tester) async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: TextButton( - style: TextButton.styleFrom( - enabledMouseCursor: SystemMouseCursors.text, - disabledMouseCursor: SystemMouseCursors.grab, - ), - onPressed: () {}, - child: const Text('button'), - ), - ), - ), - ); - - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); - await gesture.addPointer(location: Offset.zero); - addTearDown(gesture.removePointer); - - await tester.pump(); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); - - // Test cursor when disabled - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: TextButton( - style: TextButton.styleFrom( - enabledMouseCursor: SystemMouseCursors.text, - disabledMouseCursor: SystemMouseCursors.grab, - ), - onPressed: null, - child: const Text('button'), - ), - ), - ), - ); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab); - - // Test default cursor - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: TextButton( - onPressed: () {}, - child: const Text('button'), - ), - ), - ), - ); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); - - // Test default cursor when disabled - await tester.pumpWidget( - const Directionality( - textDirection: TextDirection.ltr, - child: MouseRegion( - cursor: SystemMouseCursors.forbidden, - child: TextButton( - onPressed: null, - child: Text('button'), - ), - ), - ), - ); - - expect(RendererBinding.instance!.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); - }); } TextStyle? _iconStyle(WidgetTester tester, IconData icon) { diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 4656ba22d68e4..f9b58e5dda0e0 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -31,10 +31,10 @@ import 'feedback_tester.dart'; typedef FormatEditUpdateCallback = void Function(TextEditingValue, TextEditingValue); // On web, the context menu (aka toolbar) is provided by the browser. -const bool isContextMenuProvidedByPlatform = isBrowser; +final bool isContextMenuProvidedByPlatform = isBrowser; // On web, key events in text fields are handled by the browser. -const bool areKeyEventsHandledByPlatform = isBrowser; +final bool areKeyEventsHandledByPlatform = isBrowser; class MaterialLocalizationsDelegate extends LocalizationsDelegate { @override @@ -79,14 +79,16 @@ Widget overlayWithEntry(OverlayEntry entry) { MaterialLocalizationsDelegate(), ], child: DefaultTextEditingShortcuts( - child: Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(size: Size(800.0, 600.0)), - child: Overlay( - initialEntries: [ - entry, - ], + child: DefaultTextEditingActions( + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(size: Size(800.0, 600.0)), + child: Overlay( + initialEntries: [ + entry, + ], + ), ), ), ), @@ -258,14 +260,14 @@ void main() { await tester.pump(); await gesture.up(); await tester.pumpAndSettle(); - expect(controller.selection, const TextSelection.collapsed(offset: 11, affinity: TextAffinity.upstream)); + expect(controller.selection, const TextSelection(baseOffset: 11, extentOffset: 11, affinity: TextAffinity.upstream)); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsOneWidget); await tester.tap(find.text('Paste')); await tester.pumpAndSettle(); expect(controller.text, 'blah1 blah2blah1'); - expect(controller.selection, const TextSelection.collapsed(offset: 16)); + expect(controller.selection, const TextSelection(baseOffset: 16, extentOffset: 16, affinity: TextAffinity.upstream)); // Cut the first word. await gesture.down(midBlah1); @@ -286,7 +288,7 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('Activates the text field when receives semantics focus on Mac, Windows', (WidgetTester tester) async { + testWidgets('Activates the text field when receives semantics focus on Mac', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; final FocusNode focusNode = FocusNode(); @@ -337,7 +339,7 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasFocus, isTrue); semantics.dispose(); - }, variant: const TargetPlatformVariant({ TargetPlatform.macOS, TargetPlatform.windows })); + }, variant: const TargetPlatformVariant({ TargetPlatform.macOS })); testWidgets('TextField passes onEditingComplete to EditableText', (WidgetTester tester) async { void onEditingComplete() { } @@ -641,7 +643,7 @@ void main() { await expectLater( find.byKey(const ValueKey(1)), matchesGoldenFile( - 'text_field_cursor_test_${debugDefaultTargetPlatformOverride!.name.toLowerCase()}.material.1.png', + 'text_field_cursor_test_${describeEnum(debugDefaultTargetPlatformOverride!).toLowerCase()}.material.1.png', ), ); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); @@ -897,8 +899,7 @@ void main() { find.byType(MaterialApp), matchesGoldenFile('text_field_golden.TextSelectionStyle.2.png'), ); - // Text selection styles are not fully supported on web. - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/93723 + }); testWidgets( 'text field toolbar options correctly changes options', @@ -1098,33 +1099,6 @@ void main() { expect(cursorOffsetSpaces.dx, inputWidth - kCaretGap); }); - testWidgets('Overflowing a line with spaces stops the cursor at the end (rtl direction)', (WidgetTester tester) async { - await tester.pumpWidget( - overlay( - child: const TextField( - textDirection: TextDirection.rtl, - maxLines: null, - ), - ), - ); - - const String testValueOneLine = 'enough text to be exactly at the end of the line.'; - const String testValueSpaces = '$testValueOneLine '; - - // Positioning the cursor at the end of a line overflowing with spaces puts - // it inside the input still. - await tester.enterText(find.byType(TextField), testValueSpaces); - await skipPastScrollingAnimation(tester); - await tester.tapAt(textOffsetToPosition(tester, testValueSpaces.length)); - await tester.pump(); - - final Offset cursorOffsetSpaces = findRenderEditable(tester).getLocalRectForCaret( - const TextPosition(offset: testValueSpaces.length), - ).topLeft; - - expect(cursorOffsetSpaces.dx >= 0, isTrue); - }); - testWidgets('mobile obscureText control test', (WidgetTester tester) async { await tester.pumpWidget( overlay( @@ -1552,7 +1526,7 @@ void main() { expect(container.size, Size.zero); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); - testWidgets('Swapping controllers should update selection', (WidgetTester tester) async { + testWidgets('Sawping controllers should update selection', (WidgetTester tester) async { TextEditingController controller = TextEditingController(text: 'readonly'); final OverlayEntry entry = OverlayEntry( builder: (BuildContext context) { @@ -2454,34 +2428,6 @@ void main() { expect(controller.selection.isCollapsed, true); }); - testWidgets('An obscured TextField is not selectable when read-only', (WidgetTester tester) async { - // This is a regression test for - // https://github.com/flutter/flutter/issues/32845 - - final TextEditingController controller = TextEditingController(); - Widget buildFrame(bool obscureText, bool readOnly) { - return overlay( - child: TextField( - controller: controller, - obscureText: obscureText, - readOnly: readOnly, - ), - ); - } - - // Explicitly disabled selection on obscured text that is read-only. - await tester.pumpWidget(buildFrame(true, true)); - await tester.enterText(find.byType(TextField), 'abcdefghi'); - await skipPastScrollingAnimation(tester); - expect(controller.selection.isCollapsed, true); - - // Long press doesn't select text. - final Offset ePos2 = textOffsetToPosition(tester, 1); - await tester.longPressAt(ePos2, pointer: 7); - await tester.pump(); - expect(controller.selection.isCollapsed, true); - }); - testWidgets('An obscured TextField is selected as one word', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(); @@ -4998,6 +4944,82 @@ void main() { variant: KeySimulatorTransitModeVariant.all() ); + testWidgets('Copy paste obscured text test', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + final TextEditingController controller = TextEditingController(); + final TextField textField = + TextField( + controller: controller, + obscureText: true, + ); + + String clipboardContent = ''; + tester.binding.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'Clipboard.setData') + // ignore: avoid_dynamic_calls + clipboardContent = methodCall.arguments['text'] as String; + else if (methodCall.method == 'Clipboard.getData') + return {'text': clipboardContent}; + return null; + }); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: RawKeyboardListener( + focusNode: focusNode, + child: textField, + ), + ), + ), + ); + focusNode.requestFocus(); + await tester.pump(); + + const String testValue = 'a big house jumped over a mouse'; + await tester.enterText(find.byType(TextField), testValue); + + await tester.idle(); + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + + // Select the first 5 characters + await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); + for (int i = 0; i < 5; i += 1) { + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pumpAndSettle(); + } + await tester.sendKeyUpEvent(LogicalKeyboardKey.shift); + + // Copy them + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight); + await tester.sendKeyEvent(LogicalKeyboardKey.keyC); + await tester.pumpAndSettle(); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlRight); + await tester.pumpAndSettle(); + + expect(clipboardContent, 'a big'); + + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pumpAndSettle(); + + // Paste them + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight); + await tester.sendKeyDownEvent(LogicalKeyboardKey.keyV); + await tester.pumpAndSettle(); + await tester.pump(const Duration(milliseconds: 200)); + await tester.sendKeyUpEvent(LogicalKeyboardKey.keyV); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlRight); + await tester.pumpAndSettle(); + + const String expected = 'a biga big house jumped over a mouse'; + expect(find.text(expected), findsOneWidget, reason: 'Because text contains ${controller.text}'); + }, + skip: areKeyEventsHandledByPlatform, // [intended] only applies to platforms where we handle key events. + variant: KeySimulatorTransitModeVariant.all() + ); + // Regressing test for https://github.com/flutter/flutter/issues/78219 testWidgets('Paste does not crash when the section is inValid', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); @@ -5126,6 +5148,83 @@ void main() { variant: KeySimulatorTransitModeVariant.all() ); + testWidgets('Cut obscured text test', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + final TextEditingController controller = TextEditingController(); + final TextField textField = TextField( + controller: controller, + obscureText: true, + ); + String clipboardContent = ''; + tester.binding.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'Clipboard.setData') + // ignore: avoid_dynamic_calls + clipboardContent = methodCall.arguments['text'] as String; + else if (methodCall.method == 'Clipboard.getData') + return {'text': clipboardContent}; + return null; + }); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: RawKeyboardListener( + focusNode: focusNode, + child: textField, + ), + ), + ), + ); + focusNode.requestFocus(); + await tester.pump(); + + const String testValue = 'a big house jumped over a mouse'; + await tester.enterText(find.byType(TextField), testValue); + + await tester.idle(); + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + + // Select the first 5 characters + for (int i = 0; i < 5; i += 1) { + await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pumpAndSettle(); + await tester.sendKeyUpEvent(LogicalKeyboardKey.shift); + await tester.pumpAndSettle(); + } + + // Cut them + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight); + await tester.sendKeyEvent(LogicalKeyboardKey.keyX); + await tester.pumpAndSettle(); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlRight); + await tester.pumpAndSettle(); + + expect(clipboardContent, 'a big'); + + for (int i = 0; i < 5; i += 1) { + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pumpAndSettle(); + } + + // Paste them + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight); + await tester.sendKeyDownEvent(LogicalKeyboardKey.keyV); + await tester.pumpAndSettle(); + await tester.pump(const Duration(milliseconds: 200)); + await tester.sendKeyUpEvent(LogicalKeyboardKey.keyV); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlRight); + await tester.pumpAndSettle(); + + const String expected = ' housa bige jumped over a mouse'; + expect(find.text(expected), findsOneWidget); + }, + skip: areKeyEventsHandledByPlatform, // [intended] only applies to platforms where we handle key events. + variant: KeySimulatorTransitModeVariant.all() + ); + testWidgets('Select all test', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final TextEditingController controller = TextEditingController(); @@ -7000,55 +7099,6 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( - 'double tap does not select word on read-only obscured field', - (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextField( - obscureText: true, - readOnly: true, - controller: controller, - ), - ), - ), - ), - ); - - final Offset textfieldStart = tester.getTopLeft(find.byType(TextField)); - - // This tap just puts the cursor somewhere different than where the double - // tap will occur to test that the double tap moves the existing cursor first. - await tester.tapAt(textfieldStart + const Offset(50.0, 9.0)); - await tester.pump(const Duration(milliseconds: 500)); - - await tester.tapAt(textfieldStart + const Offset(150.0, 9.0)); - await tester.pump(const Duration(milliseconds: 50)); - // First tap moved the cursor. - expect( - controller.selection, - const TextSelection.collapsed(offset: 35), - ); - await tester.tapAt(textfieldStart + const Offset(150.0, 9.0)); - await tester.pumpAndSettle(); - - // Second tap doesn't select anything. - expect( - controller.selection, - const TextSelection.collapsed(offset: 35), - ); - - // Selected text shows nothing. - expect(find.byType(CupertinoButton), findsNothing); - }, - variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), - ); - testWidgets( 'double tap selects word and first tap of double tap moves cursor and shows toolbar', (WidgetTester tester) async { @@ -7718,379 +7768,9 @@ void main() { ); expect(firstCharEndpoint.length, 1); // The first character is now offscreen to the left. - expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-257.0, epsilon: 1)); + expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-257, epsilon: 1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('mouse click and drag can edge scroll', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextField( - controller: controller, - ), - ), - ), - ), - ); - - // Just testing the test and making sure that the last character is off - // the right side of the screen. - expect(textOffsetToPosition(tester, 66).dx, 1056); - - final TestGesture gesture = - await tester.startGesture( - textOffsetToPosition(tester, 19), - pointer: 7, - kind: PointerDeviceKind.mouse, - ); - addTearDown(gesture.removePointer); - - await gesture.moveTo(textOffsetToPosition(tester, 56)); - // To the edge of the screen basically. - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection(baseOffset: 19, extentOffset: 56), - ); - - // Keep moving out. - await gesture.moveTo(textOffsetToPosition(tester, 62)); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection(baseOffset: 19, extentOffset: 62), - ); - await gesture.moveTo(textOffsetToPosition(tester, 66)); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection(baseOffset: 19, extentOffset: 66), - ); // We're at the edge now. - expect(find.byType(CupertinoButton), findsNothing); - - await gesture.up(); - await tester.pumpAndSettle(); - - // The selection isn't affected by the gesture lift. - expect( - controller.selection, - const TextSelection(baseOffset: 19, extentOffset: 66), - ); - - // The last character is now on screen near the right edge. - expect( - textOffsetToPosition(tester, 66).dx, - moreOrLessEquals(TestSemantics.fullScreen.width, epsilon: 2.0), - ); - - // The first character is now offscreen to the left. - expect(textOffsetToPosition(tester, 0).dx, moreOrLessEquals(-257.0, epsilon: 1)); - }, variant: TargetPlatformVariant.all()); - - testWidgets('keyboard selection change scrolls the field', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextField( - controller: controller, - ), - ), - ), - ), - ); - - // Just testing the test and making sure that the last character is off - // the right side of the screen. - expect(textOffsetToPosition(tester, 66).dx, 1056); - - await tester.tapAt(textOffsetToPosition(tester, 13)); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 13), - ); - - // Move to position 56 with the right arrow (near the edge of the screen). - for (int i = 0; i < (56 - 13); i += 1) { - await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); - } - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 56), - ); - - // Keep moving out. - for (int i = 0; i < (62 - 56); i += 1) { - await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); - } - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 62), - ); - for (int i = 0; i < (66 - 62); i += 1) { - await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); - } - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 66), - ); // We're at the edge now. - - await tester.pumpAndSettle(); - - // The last character is now on screen near the right edge. - expect( - textOffsetToPosition(tester, 66).dx, - moreOrLessEquals(TestSemantics.fullScreen.width, epsilon: 2.0), - ); - - // The first character is now offscreen to the left. - expect(textOffsetToPosition(tester, 0).dx, moreOrLessEquals(-257.0, epsilon: 1)); - }, variant: TargetPlatformVariant.all(), - skip: isBrowser, // [intended] Browser handles arrow keys differently. - ); - - testWidgets('long press drag can edge scroll vertically', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neigse Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextField( - maxLines: 2, - controller: controller, - ), - ), - ), - ), - ); - - // Just testing the test and making sure that the last character is outside - // the bottom of the field. - final int textLength = controller.text.length; - final double lineHeight = findRenderEditable(tester).preferredLineHeight; - final double firstCharY = textOffsetToPosition(tester, 0).dy; - expect( - textOffsetToPosition(tester, textLength).dy, - moreOrLessEquals(firstCharY + lineHeight * 2, epsilon: 1), - ); - - // Start long pressing on the first line. - final TestGesture gesture = - await tester.startGesture(textOffsetToPosition(tester, 19)); - // TODO(justinmc): Make sure you've got all things torn down. - addTearDown(gesture.removePointer); - await tester.pump(const Duration(milliseconds: 500)); - expect( - controller.selection, - const TextSelection.collapsed(offset: 19), - ); - await tester.pumpAndSettle(); - - // Move down to the second line. - await gesture.moveBy(Offset(0.0, lineHeight)); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 65), - ); - - // Still hasn't scrolled. - expect( - textOffsetToPosition(tester, 65).dy, - moreOrLessEquals(firstCharY + lineHeight, epsilon: 1), - ); - - // Keep selecting down to the third and final line. - await gesture.moveBy(Offset(0.0, lineHeight)); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 110), - ); - - // The last character is no longer three line heights down from the top of - // the field, it's now only two line heights down, because it has scrolled - // down by one line. - expect( - textOffsetToPosition(tester, 110).dy, - moreOrLessEquals(firstCharY + lineHeight, epsilon: 1), - ); - - // Likewise, the first character is now scrolled out of the top of the field - // by one line. - expect( - textOffsetToPosition(tester, 0).dy, - moreOrLessEquals(firstCharY - lineHeight, epsilon: 1), - ); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - - testWidgets('keyboard selection change scrolls the field vertically', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextField( - maxLines: 2, - controller: controller, - ), - ), - ), - ), - ); - - // Just testing the test and making sure that the last character is outside - // the bottom of the field. - final int textLength = controller.text.length; - final double lineHeight = findRenderEditable(tester).preferredLineHeight; - final double firstCharY = textOffsetToPosition(tester, 0).dy; - expect( - textOffsetToPosition(tester, textLength).dy, - moreOrLessEquals(firstCharY + lineHeight * 2, epsilon: 1), - ); - - await tester.tapAt(textOffsetToPosition(tester, 13)); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 13), - ); - - // Move down to the second line. - await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 59), - ); - - // Still hasn't scrolled. - expect( - textOffsetToPosition(tester, 66).dy, - moreOrLessEquals(firstCharY + lineHeight, epsilon: 1), - ); - - // Move down to the third and final line. - await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection.collapsed(offset: 104), - ); - - // The last character is no longer three line heights down from the top of - // the field, it's now only two line heights down, because it has scrolled - // down by one line. - expect( - textOffsetToPosition(tester, textLength).dy, - moreOrLessEquals(firstCharY + lineHeight, epsilon: 1), - ); - - // Likewise, the first character is now scrolled out of the top of the field - // by one line. - expect( - textOffsetToPosition(tester, 0).dy, - moreOrLessEquals(firstCharY - lineHeight, epsilon: 1), - ); - }, variant: TargetPlatformVariant.all(), - skip: isBrowser, // [intended] Browser handles arrow keys differently. - ); - - testWidgets('mouse click and drag can edge scroll vertically', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextField( - maxLines: 2, - controller: controller, - ), - ), - ), - ), - ); - - // Just testing the test and making sure that the last character is outside - // the bottom of the field. - final int textLength = controller.text.length; - final double lineHeight = findRenderEditable(tester).preferredLineHeight; - final double firstCharY = textOffsetToPosition(tester, 0).dy; - expect( - textOffsetToPosition(tester, textLength).dy, - moreOrLessEquals(firstCharY + lineHeight * 2, epsilon: 1), - ); - - // Start selecting on the first line. - final TestGesture gesture = - await tester.startGesture( - textOffsetToPosition(tester, 19), - pointer: 7, - kind: PointerDeviceKind.mouse, - ); - addTearDown(gesture.removePointer); - - // Still hasn't scrolled. - expect( - textOffsetToPosition(tester, 60).dy, - moreOrLessEquals(firstCharY + lineHeight, epsilon: 1), - ); - - // Select down to the second line. - await gesture.moveBy(Offset(0.0, lineHeight)); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection(baseOffset: 19, extentOffset: 65), - ); - - // Still hasn't scrolled. - expect( - textOffsetToPosition(tester, 60).dy, - moreOrLessEquals(firstCharY + lineHeight, epsilon: 1), - ); - - // Keep selecting down to the third and final line. - await gesture.moveBy(Offset(0.0, lineHeight)); - await tester.pumpAndSettle(); - expect( - controller.selection, - const TextSelection(baseOffset: 19, extentOffset: 110), - ); - - // The last character is no longer three line heights down from the top of - // the field, it's now only two line heights down, because it has scrolled - // down by one line. - expect( - textOffsetToPosition(tester, textLength).dy, - moreOrLessEquals(firstCharY + lineHeight, epsilon: 1), - ); - - // Likewise, the first character is now scrolled out of the top of the field - // by one line. - expect( - textOffsetToPosition(tester, 0).dy, - moreOrLessEquals(firstCharY - lineHeight, epsilon: 1), - ); - }, variant: TargetPlatformVariant.all()); - testWidgets( 'long tap after a double tap select is not affected', (WidgetTester tester) async { @@ -9765,7 +9445,6 @@ void main() { actions: >{ ScrollIntent: CallbackAction(onInvoke: (Intent intent) { scrollInvoked = true; - return null; }), }, child: Material( @@ -10437,92 +10116,4 @@ void main() { await tester.pump(state.cursorBlinkInterval); expect(editable.showCursor.value, isTrue); }); - - testWidgets('can shift + tap to select with a keyboard (Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextField(controller: controller), - ), - ), - ), - ); - - await tester.tapAt(textOffsetToPosition(tester, 13)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 13); - - await tester.pump(kDoubleTapTimeout); - await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); - await tester.tapAt(textOffsetToPosition(tester, 20)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 20); - - await tester.pump(kDoubleTapTimeout); - await tester.tapAt(textOffsetToPosition(tester, 23)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 23); - - await tester.pump(kDoubleTapTimeout); - await tester.tapAt(textOffsetToPosition(tester, 4)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 23); - expect(controller.selection.extentOffset, 4); - - await tester.sendKeyUpEvent(LogicalKeyboardKey.shift); - expect(controller.selection.baseOffset, 23); - expect(controller.selection.extentOffset, 4); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - - testWidgets('can shift + tap to select with a keyboard (non-Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'Atwater Peel Sherbrooke Bonaventure', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextField(controller: controller), - ), - ), - ), - ); - - await tester.tapAt(textOffsetToPosition(tester, 13)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 13); - - await tester.pump(kDoubleTapTimeout); - await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); - await tester.tapAt(textOffsetToPosition(tester, 20)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 20); - - await tester.pump(kDoubleTapTimeout); - await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); - await tester.tapAt(textOffsetToPosition(tester, 23)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 23); - - await tester.pump(kDoubleTapTimeout); - await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); - await tester.tapAt(textOffsetToPosition(tester, 4)); - await tester.pumpAndSettle(); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 4); - - await tester.sendKeyUpEvent(LogicalKeyboardKey.shift); - expect(controller.selection.baseOffset, 13); - expect(controller.selection.extentOffset, 4); - }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); } diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index b4f2a1e136825..b567baffce8ae 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -74,14 +74,14 @@ void main() { await tester.pump(); await gesture.up(); await tester.pumpAndSettle(); - expect(controller.selection, const TextSelection.collapsed(offset: 11, affinity: TextAffinity.upstream)); + expect(controller.selection, const TextSelection(baseOffset: 11, extentOffset: 11, affinity: TextAffinity.upstream)); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsOneWidget); await tester.tap(find.text('Paste')); await tester.pumpAndSettle(); expect(controller.text, 'blah1 blah2blah1'); - expect(controller.selection, const TextSelection.collapsed(offset: 16)); + expect(controller.selection, const TextSelection(baseOffset: 16, extentOffset: 16, affinity: TextAffinity.upstream)); // Cut the first word. await gesture.down(midBlah1); @@ -102,94 +102,6 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'blah1 blah2', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextFormField( - readOnly: true, - obscureText: true, - controller: controller, - ), - ), - ), - ), - ); - - // Initially, the menu is not shown and there is no selection. - expect(find.byType(CupertinoButton), findsNothing); - const TextSelection invalidSelection = TextSelection(baseOffset: -1, extentOffset: -1); - expect(controller.selection, invalidSelection); - - final Offset midBlah1 = textOffsetToPosition(tester, 2); - - // Right clicking shows the menu. - final TestGesture gesture = await tester.startGesture( - midBlah1, - kind: PointerDeviceKind.mouse, - buttons: kSecondaryMouseButton, - ); - addTearDown(gesture.removePointer); - await tester.pump(); - await gesture.up(); - await tester.pumpAndSettle(); - expect(controller.selection, invalidSelection); - expect(find.text('Copy'), findsNothing); - expect(find.text('Cut'), findsNothing); - expect(find.text('Paste'), findsNothing); - expect(find.byType(CupertinoButton), findsNothing); - }, - variant: TargetPlatformVariant.desktop(), - skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. - ); - - testWidgets('the desktop cut/copy buttons are disabled for obscured form fields', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'blah1 blah2', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: TextFormField( - obscureText: true, - controller: controller, - ), - ), - ), - ), - ); - - // Initially, the menu is not shown and there is no selection. - expect(find.byType(CupertinoButton), findsNothing); - const TextSelection invalidSelection = TextSelection(baseOffset: -1, extentOffset: -1); - expect(controller.selection, invalidSelection); - - final Offset midBlah1 = textOffsetToPosition(tester, 2); - - // Right clicking shows the menu. - final TestGesture gesture = await tester.startGesture( - midBlah1, - kind: PointerDeviceKind.mouse, - buttons: kSecondaryMouseButton, - ); - addTearDown(gesture.removePointer); - await tester.pump(); - await gesture.up(); - await tester.pumpAndSettle(); - expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 11)); - expect(find.text('Copy'), findsNothing); - expect(find.text('Cut'), findsNothing); - expect(find.text('Paste'), findsOneWidget); - }, - variant: TargetPlatformVariant.desktop(), - skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. - ); - testWidgets('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { bool asserted; try { diff --git a/packages/flutter/test/material/text_theme_test.dart b/packages/flutter/test/material/text_theme_test.dart index e6e82185aa81d..9a89a6b972708 100644 --- a/packages/flutter/test/material/text_theme_test.dart +++ b/packages/flutter/test/material/text_theme_test.dart @@ -29,21 +29,19 @@ void main() { test('TextTheme copyWith', () { final Typography typography = Typography.material2018(); final TextTheme whiteCopy = typography.black.copyWith( - displayLarge: typography.white.displayLarge, - displayMedium: typography.white.displayMedium, - displaySmall: typography.white.displaySmall, - headlineLarge: typography.white.headlineLarge, - headlineMedium: typography.white.headlineMedium, - headlineSmall: typography.white.headlineSmall, - titleLarge: typography.white.titleLarge, - titleMedium: typography.white.titleMedium, - titleSmall: typography.white.titleSmall, - bodyLarge: typography.white.bodyLarge, - bodyMedium: typography.white.bodyMedium, - bodySmall: typography.white.bodySmall, - labelLarge: typography.white.labelLarge, - labelMedium: typography.white.labelMedium, - labelSmall: typography.white.labelSmall, + headline1: typography.white.headline1, + headline2: typography.white.headline2, + headline3: typography.white.headline3, + headline4: typography.white.headline4, + headline5: typography.white.headline5, + headline6: typography.white.headline6, + subtitle1: typography.white.subtitle1, + bodyText1: typography.white.bodyText1, + bodyText2: typography.white.bodyText2, + caption: typography.white.caption, + button: typography.white.button, + subtitle2: typography.white.subtitle2, + overline: typography.white.overline, ); expect(typography.white, equals(whiteCopy)); }); @@ -54,28 +52,28 @@ void main() { final TextTheme fullTheme = ThemeData.fallback().textTheme.merge(partialTheme); expect(fullTheme.headline6!.color, equals(partialTheme.headline6!.color)); - const TextTheme onlyHeadlineSmallAndTitleLarge = TextTheme( - headlineSmall: TextStyle(color: Color(0xcafefeed)), - titleLarge: TextStyle(color: Color(0xbeefcafe)), + const TextTheme onlyHeadlineAndTitle = TextTheme( + headline5: TextStyle(color: Color(0xcafefeed)), + headline6: TextStyle(color: Color(0xbeefcafe)), ); - const TextTheme onlyBodyMediumAndTitleLarge = TextTheme( - bodyMedium: TextStyle(color: Color(0xfeedfeed)), - titleLarge: TextStyle(color: Color(0xdeadcafe)), + const TextTheme onlyBody1AndTitle = TextTheme( + bodyText2: TextStyle(color: Color(0xfeedfeed)), + headline6: TextStyle(color: Color(0xdeadcafe)), ); - TextTheme merged = onlyHeadlineSmallAndTitleLarge.merge(onlyBodyMediumAndTitleLarge); - expect(merged.bodyLarge, isNull); - expect(merged.bodyMedium!.color, equals(onlyBodyMediumAndTitleLarge.bodyMedium!.color)); - expect(merged.headlineSmall!.color, equals(onlyHeadlineSmallAndTitleLarge.headlineSmall!.color)); - expect(merged.titleLarge!.color, equals(onlyBodyMediumAndTitleLarge.titleLarge!.color)); - - merged = onlyHeadlineSmallAndTitleLarge.merge(null); - expect(merged, equals(onlyHeadlineSmallAndTitleLarge)); + TextTheme merged = onlyHeadlineAndTitle.merge(onlyBody1AndTitle); + expect(merged.bodyText1, isNull); + expect(merged.bodyText2!.color, equals(onlyBody1AndTitle.bodyText2!.color)); + expect(merged.headline5!.color, equals(onlyHeadlineAndTitle.headline5!.color)); + expect(merged.headline6!.color, equals(onlyBody1AndTitle.headline6!.color)); + + merged = onlyHeadlineAndTitle.merge(null); + expect(merged, equals(onlyHeadlineAndTitle)); }); test('TextTheme apply', () { - // The `displayColor` is applied to [displayLarge], [displayMedium], - // [displaySmall], [headlineLarge], [headlineMedium], and [bodySmall]. The - // `bodyColor` is applied to the remaining text styles. + // The `displayColor` is applied to [headline1], [headline2], [headline3], + // [headline4], and [caption]. The `bodyColor` is applied to the remaining + // text styles. const Color displayColor = Color(0x00000001); const Color bodyColor = Color(0x00000002); const String fontFamily = 'fontFamily'; @@ -96,38 +94,34 @@ void main() { decorationStyle: decorationStyle, ); - expect(theme.displayLarge!.color, displayColor); - expect(theme.displayMedium!.color, displayColor); - expect(theme.displaySmall!.color, displayColor); - expect(theme.headlineLarge!.color, displayColor); - expect(theme.headlineMedium!.color, displayColor); - expect(theme.headlineSmall!.color, bodyColor); - expect(theme.titleLarge!.color, bodyColor); - expect(theme.titleMedium!.color, bodyColor); - expect(theme.titleSmall!.color, bodyColor); - expect(theme.bodyLarge!.color, bodyColor); - expect(theme.bodyMedium!.color, bodyColor); - expect(theme.bodySmall!.color, displayColor); - expect(theme.labelLarge!.color, bodyColor); - expect(theme.labelMedium!.color, bodyColor); - expect(theme.labelSmall!.color, bodyColor); + expect(theme.headline1!.color, displayColor); + expect(theme.headline2!.color, displayColor); + expect(theme.headline3!.color, displayColor); + expect(theme.headline4!.color, displayColor); + expect(theme.caption!.color, displayColor); + expect(theme.headline5!.color, bodyColor); + expect(theme.headline6!.color, bodyColor); + expect(theme.subtitle1!.color, bodyColor); + expect(theme.bodyText1!.color, bodyColor); + expect(theme.bodyText2!.color, bodyColor); + expect(theme.button!.color, bodyColor); + expect(theme.subtitle2!.color, bodyColor); + expect(theme.overline!.color, bodyColor); final List themeStyles = [ - theme.displayLarge!, - theme.displayMedium!, - theme.displaySmall!, - theme.headlineLarge!, - theme.headlineMedium!, - theme.headlineSmall!, - theme.titleLarge!, - theme.titleMedium!, - theme.titleSmall!, - theme.bodyLarge!, - theme.bodyMedium!, - theme.bodySmall!, - theme.labelLarge!, - theme.labelMedium!, - theme.labelSmall!, + theme.headline1!, + theme.headline2!, + theme.headline3!, + theme.headline4!, + theme.caption!, + theme.headline5!, + theme.headline6!, + theme.subtitle1!, + theme.bodyText1!, + theme.bodyText2!, + theme.button!, + theme.subtitle2!, + theme.overline!, ]; expect(themeStyles.every((TextStyle style) => style.fontFamily == fontFamily), true); expect(themeStyles.every((TextStyle style) => style.decorationColor == decorationColor), true); @@ -143,81 +137,73 @@ void main() { fontSizeDelta: 5.0, ); - expect(sizeTheme.displayLarge!.fontSize, baseTheme.displayLarge!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.displayMedium!.fontSize, baseTheme.displayMedium!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.displaySmall!.fontSize, baseTheme.displaySmall!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.headlineLarge!.fontSize, baseTheme.headlineLarge!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.headlineMedium!.fontSize, baseTheme.headlineMedium!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.headlineSmall!.fontSize, baseTheme.headlineSmall!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.titleLarge!.fontSize, baseTheme.titleLarge!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.titleMedium!.fontSize, baseTheme.titleMedium!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.titleSmall!.fontSize, baseTheme.titleSmall!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.bodyLarge!.fontSize, baseTheme.bodyLarge!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.bodyMedium!.fontSize, baseTheme.bodyMedium!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.bodySmall!.fontSize, baseTheme.bodySmall!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.labelLarge!.fontSize, baseTheme.labelLarge!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.labelMedium!.fontSize, baseTheme.labelMedium!.fontSize! * 2.0 + 5.0); - expect(sizeTheme.labelSmall!.fontSize, baseTheme.labelSmall!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.headline1!.fontSize, baseTheme.headline1!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.headline2!.fontSize, baseTheme.headline2!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.headline3!.fontSize, baseTheme.headline3!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.headline4!.fontSize, baseTheme.headline4!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.caption!.fontSize, baseTheme.caption!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.headline5!.fontSize, baseTheme.headline5!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.headline6!.fontSize, baseTheme.headline6!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.subtitle1!.fontSize, baseTheme.subtitle1!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.bodyText1!.fontSize, baseTheme.bodyText1!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.bodyText2!.fontSize, baseTheme.bodyText2!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.button!.fontSize, baseTheme.button!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.subtitle2!.fontSize, baseTheme.subtitle2!.fontSize! * 2.0 + 5.0); + expect(sizeTheme.overline!.fontSize, baseTheme.overline!.fontSize! * 2.0 + 5.0); }); test('TextTheme lerp with second parameter null', () { final TextTheme theme = Typography.material2018().black; final TextTheme lerped = TextTheme.lerp(theme, null, 0.25); - expect(lerped.displayLarge, TextStyle.lerp(theme.displayLarge, null, 0.25)); - expect(lerped.displayMedium, TextStyle.lerp(theme.displayMedium, null, 0.25)); - expect(lerped.displaySmall, TextStyle.lerp(theme.displaySmall, null, 0.25)); - expect(lerped.headlineLarge, TextStyle.lerp(theme.headlineLarge, null, 0.25)); - expect(lerped.headlineMedium, TextStyle.lerp(theme.headlineMedium, null, 0.25)); - expect(lerped.headlineSmall, TextStyle.lerp(theme.headlineSmall, null, 0.25)); - expect(lerped.titleLarge, TextStyle.lerp(theme.titleLarge, null, 0.25)); - expect(lerped.titleMedium, TextStyle.lerp(theme.titleMedium, null, 0.25)); - expect(lerped.titleSmall, TextStyle.lerp(theme.titleSmall, null, 0.25)); - expect(lerped.bodyLarge, TextStyle.lerp(theme.bodyLarge, null, 0.25)); - expect(lerped.bodyMedium, TextStyle.lerp(theme.bodyMedium, null, 0.25)); - expect(lerped.bodySmall, TextStyle.lerp(theme.bodySmall, null, 0.25)); - expect(lerped.labelLarge, TextStyle.lerp(theme.labelLarge, null, 0.25)); - expect(lerped.labelMedium, TextStyle.lerp(theme.labelMedium, null, 0.25)); - expect(lerped.labelSmall, TextStyle.lerp(theme.labelSmall, null, 0.25)); + expect(lerped.headline1, TextStyle.lerp(theme.headline1, null, 0.25)); + expect(lerped.headline2, TextStyle.lerp(theme.headline2, null, 0.25)); + expect(lerped.headline3, TextStyle.lerp(theme.headline3, null, 0.25)); + expect(lerped.headline4, TextStyle.lerp(theme.headline4, null, 0.25)); + expect(lerped.caption, TextStyle.lerp(theme.caption, null, 0.25)); + expect(lerped.headline5, TextStyle.lerp(theme.headline5, null, 0.25)); + expect(lerped.headline6, TextStyle.lerp(theme.headline6, null, 0.25)); + expect(lerped.subtitle1, TextStyle.lerp(theme.subtitle1, null, 0.25)); + expect(lerped.bodyText1, TextStyle.lerp(theme.bodyText1, null, 0.25)); + expect(lerped.bodyText2, TextStyle.lerp(theme.bodyText2, null, 0.25)); + expect(lerped.button, TextStyle.lerp(theme.button, null, 0.25)); + expect(lerped.subtitle2, TextStyle.lerp(theme.subtitle2, null, 0.25)); + expect(lerped.overline, TextStyle.lerp(theme.overline, null, 0.25)); }); test('TextTheme lerp with first parameter null', () { final TextTheme theme = Typography.material2018().black; final TextTheme lerped = TextTheme.lerp(null, theme, 0.25); - expect(lerped.displayLarge, TextStyle.lerp(null, theme.displayLarge, 0.25)); - expect(lerped.displayMedium, TextStyle.lerp(null, theme.displayMedium, 0.25)); - expect(lerped.displaySmall, TextStyle.lerp(null, theme.displaySmall, 0.25)); - expect(lerped.headlineLarge, TextStyle.lerp(null, theme.headlineLarge, 0.25)); - expect(lerped.headlineMedium, TextStyle.lerp(null, theme.headlineMedium, 0.25)); - expect(lerped.headlineSmall, TextStyle.lerp(null, theme.headlineSmall, 0.25)); - expect(lerped.titleLarge, TextStyle.lerp(null, theme.titleLarge, 0.25)); - expect(lerped.titleMedium, TextStyle.lerp(null, theme.titleMedium, 0.25)); - expect(lerped.titleSmall, TextStyle.lerp(null, theme.titleSmall, 0.25)); - expect(lerped.bodyLarge, TextStyle.lerp(null, theme.bodyLarge, 0.25)); - expect(lerped.bodyMedium, TextStyle.lerp(null, theme.bodyMedium, 0.25)); - expect(lerped.bodySmall, TextStyle.lerp(null, theme.bodySmall, 0.25)); - expect(lerped.labelLarge, TextStyle.lerp(null, theme.labelLarge, 0.25)); - expect(lerped.labelMedium, TextStyle.lerp(null, theme.labelMedium, 0.25)); - expect(lerped.labelSmall, TextStyle.lerp(null, theme.labelSmall, 0.25)); + expect(lerped.headline1, TextStyle.lerp(null, theme.headline1, 0.25)); + expect(lerped.headline2, TextStyle.lerp(null, theme.headline2, 0.25)); + expect(lerped.headline3, TextStyle.lerp(null, theme.headline3, 0.25)); + expect(lerped.headline4, TextStyle.lerp(null, theme.headline4, 0.25)); + expect(lerped.caption, TextStyle.lerp(null, theme.caption, 0.25)); + expect(lerped.headline5, TextStyle.lerp(null, theme.headline5, 0.25)); + expect(lerped.headline6, TextStyle.lerp(null, theme.headline6, 0.25)); + expect(lerped.subtitle1, TextStyle.lerp(null, theme.subtitle1, 0.25)); + expect(lerped.bodyText1, TextStyle.lerp(null, theme.bodyText1, 0.25)); + expect(lerped.bodyText2, TextStyle.lerp(null, theme.bodyText2, 0.25)); + expect(lerped.button, TextStyle.lerp(null, theme.button, 0.25)); + expect(lerped.subtitle2, TextStyle.lerp(null, theme.subtitle2, 0.25)); + expect(lerped.overline, TextStyle.lerp(null, theme.overline, 0.25)); }); test('TextTheme lerp with null parameters', () { final TextTheme lerped = TextTheme.lerp(null, null, 0.25); - expect(lerped.displayLarge, null); - expect(lerped.displayMedium, null); - expect(lerped.displaySmall, null); - expect(lerped.headlineLarge, null); - expect(lerped.headlineMedium, null); - expect(lerped.headlineSmall, null); - expect(lerped.titleLarge, null); - expect(lerped.titleMedium, null); - expect(lerped.titleSmall, null); - expect(lerped.bodyLarge, null); - expect(lerped.bodyMedium, null); - expect(lerped.bodySmall, null); - expect(lerped.labelLarge, null); - expect(lerped.labelMedium, null); - expect(lerped.labelSmall, null); + expect(lerped.headline1, null); + expect(lerped.headline2, null); + expect(lerped.headline3, null); + expect(lerped.headline4, null); + expect(lerped.caption, null); + expect(lerped.headline5, null); + expect(lerped.headline6, null); + expect(lerped.subtitle1, null); + expect(lerped.bodyText1, null); + expect(lerped.bodyText2, null); + expect(lerped.button, null); + expect(lerped.subtitle2, null); + expect(lerped.overline, null); }); } diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart index 8899744d8dc87..758b7d35d6e81 100644 --- a/packages/flutter/test/material/theme_data_test.dart +++ b/packages/flutter/test/material/theme_data_test.dart @@ -43,14 +43,24 @@ void main() { }); test('Default primary text theme contrasts with primary brightness', () { - final ThemeData lightTheme = ThemeData(primaryColor: Colors.white); - final ThemeData darkTheme = ThemeData(primaryColor: Colors.black); + final ThemeData lightTheme = ThemeData(primaryColorBrightness: Brightness.light); + final ThemeData darkTheme = ThemeData(primaryColorBrightness: Brightness.dark); final Typography typography = Typography.material2018(platform: lightTheme.platform); expect(lightTheme.primaryTextTheme.headline6!.color, typography.black.headline6!.color); expect(darkTheme.primaryTextTheme.headline6!.color, typography.white.headline6!.color); }); + test('Default chip label style gets a default bodyText1 if textTheme.bodyText1 is null', () { + const TextTheme noBodyText1TextTheme = TextTheme(); + final ThemeData lightTheme = ThemeData(brightness: Brightness.light, textTheme: noBodyText1TextTheme); + final ThemeData darkTheme = ThemeData(brightness: Brightness.dark, textTheme: noBodyText1TextTheme); + final Typography typography = Typography.material2018(platform: lightTheme.platform); + + expect(lightTheme.chipTheme.labelStyle.color, equals(typography.black.bodyText1!.color!.withAlpha(0xde))); + expect(darkTheme.chipTheme.labelStyle.color, equals(typography.white.bodyText1!.color!.withAlpha(0xde))); + }); + test('Default icon theme contrasts with brightness', () { final ThemeData lightTheme = ThemeData(brightness: Brightness.light); final ThemeData darkTheme = ThemeData(brightness: Brightness.dark); @@ -61,8 +71,8 @@ void main() { }); test('Default primary icon theme contrasts with primary brightness', () { - final ThemeData lightTheme = ThemeData(primaryColor: Colors.white); - final ThemeData darkTheme = ThemeData(primaryColor: Colors.black); + final ThemeData lightTheme = ThemeData(primaryColorBrightness: Brightness.light); + final ThemeData darkTheme = ThemeData(primaryColorBrightness: Brightness.dark); final Typography typography = Typography.material2018(platform: lightTheme.platform); expect(lightTheme.primaryTextTheme.headline6!.color, typography.black.headline6!.color); @@ -130,111 +140,6 @@ void main() { expect(const TextSelectionThemeData(cursorColor: Colors.red).cursorColor, Colors.red); }); - test('If colorSchemeSeed is used colorScheme, primaryColor and primarySwatch should not be.', () { - expect(() => ThemeData(colorSchemeSeed: Colors.blue, colorScheme: const ColorScheme.light()), throwsAssertionError); - expect(() => ThemeData(colorSchemeSeed: Colors.blue, primaryColor: Colors.green), throwsAssertionError); - expect(() => ThemeData(colorSchemeSeed: Colors.blue, primarySwatch: Colors.green), throwsAssertionError); - }); - - test('ThemeData can generate a light colorScheme from colorSchemeSeed', () { - final ThemeData theme = ThemeData(colorSchemeSeed: Colors.blue); - - expect(theme.colorScheme.primary, const Color(0xff0061a6)); - expect(theme.colorScheme.onPrimary, const Color(0xffffffff)); - expect(theme.colorScheme.primaryContainer, const Color(0xffd0e4ff)); - expect(theme.colorScheme.onPrimaryContainer, const Color(0xff001d36)); - expect(theme.colorScheme.secondary, const Color(0xff535f70)); - expect(theme.colorScheme.onSecondary, const Color(0xffffffff)); - expect(theme.colorScheme.secondaryContainer, const Color(0xffd6e3f7)); - expect(theme.colorScheme.onSecondaryContainer, const Color(0xff101c2b)); - expect(theme.colorScheme.tertiary, const Color(0xff6b5778)); - expect(theme.colorScheme.onTertiary, const Color(0xffffffff)); - expect(theme.colorScheme.tertiaryContainer, const Color(0xfff3daff)); - expect(theme.colorScheme.onTertiaryContainer, const Color(0xff251432)); - expect(theme.colorScheme.error, const Color(0xffba1b1b)); - expect(theme.colorScheme.onError, const Color(0xffffffff)); - expect(theme.colorScheme.errorContainer, const Color(0xffffdad4)); - expect(theme.colorScheme.onErrorContainer, const Color(0xff410001)); - expect(theme.colorScheme.outline, const Color(0xff73777f)); - expect(theme.colorScheme.background, const Color(0xfffdfcff)); - expect(theme.colorScheme.onBackground, const Color(0xff1b1b1b)); - expect(theme.colorScheme.surface, const Color(0xfffdfcff)); - expect(theme.colorScheme.onSurface, const Color(0xff1b1b1b)); - expect(theme.colorScheme.surfaceVariant, const Color(0xffdfe2eb)); - expect(theme.colorScheme.onSurfaceVariant, const Color(0xff42474e)); - expect(theme.colorScheme.inverseSurface, const Color(0xff2f3033)); - expect(theme.colorScheme.onInverseSurface, const Color(0xfff1f0f4)); - expect(theme.colorScheme.inversePrimary, const Color(0xff9ccaff)); - expect(theme.colorScheme.shadow, const Color(0xff000000)); - expect(theme.colorScheme.brightness, Brightness.light); - - expect(theme.primaryColor, theme.colorScheme.primary); - expect(theme.primaryColorBrightness, Brightness.dark); - expect(theme.canvasColor, theme.colorScheme.background); - expect(theme.accentColor, theme.colorScheme.secondary); - expect(theme.accentColorBrightness, Brightness.dark); - expect(theme.scaffoldBackgroundColor, theme.colorScheme.background); - expect(theme.bottomAppBarColor, theme.colorScheme.surface); - expect(theme.cardColor, theme.colorScheme.surface); - expect(theme.dividerColor, theme.colorScheme.outline); - expect(theme.backgroundColor, theme.colorScheme.background); - expect(theme.dialogBackgroundColor, theme.colorScheme.background); - expect(theme.indicatorColor, theme.colorScheme.onPrimary); - expect(theme.errorColor, theme.colorScheme.error); - expect(theme.applyElevationOverlayColor, false); - }); - - test('ThemeData can generate a dark colorScheme from colorSchemeSeed', () { - final ThemeData theme = ThemeData( - colorSchemeSeed: Colors.blue, - brightness: Brightness.dark, - ); - - expect(theme.colorScheme.primary, const Color(0xff9ccaff)); - expect(theme.colorScheme.onPrimary, const Color(0xff00325a)); - expect(theme.colorScheme.primaryContainer, const Color(0xff00497f)); - expect(theme.colorScheme.onPrimaryContainer, const Color(0xffd0e4ff)); - expect(theme.colorScheme.secondary, const Color(0xffbbc8db)); - expect(theme.colorScheme.onSecondary, const Color(0xff253140)); - expect(theme.colorScheme.secondaryContainer, const Color(0xff3c4858)); - expect(theme.colorScheme.onSecondaryContainer, const Color(0xffd6e3f7)); - expect(theme.colorScheme.tertiary, const Color(0xffd6bee4)); - expect(theme.colorScheme.onTertiary, const Color(0xff3b2948)); - expect(theme.colorScheme.tertiaryContainer, const Color(0xff523f5f)); - expect(theme.colorScheme.onTertiaryContainer, const Color(0xfff3daff)); - expect(theme.colorScheme.error, const Color(0xffffb4a9)); - expect(theme.colorScheme.onError, const Color(0xff680003)); - expect(theme.colorScheme.errorContainer, const Color(0xff930006)); - expect(theme.colorScheme.onErrorContainer, const Color(0xffffb4a9)); - expect(theme.colorScheme.outline, const Color(0xff8d9199)); - expect(theme.colorScheme.background, const Color(0xff1b1b1b)); - expect(theme.colorScheme.onBackground, const Color(0xffe2e2e6)); - expect(theme.colorScheme.surface, const Color(0xff1b1b1b)); - expect(theme.colorScheme.onSurface, const Color(0xffe2e2e6)); - expect(theme.colorScheme.surfaceVariant, const Color(0xff42474e)); - expect(theme.colorScheme.onSurfaceVariant, const Color(0xffc3c7d0)); - expect(theme.colorScheme.inverseSurface, const Color(0xffe2e2e6)); - expect(theme.colorScheme.onInverseSurface, const Color(0xff2f3033)); - expect(theme.colorScheme.inversePrimary, const Color(0xff0061a6)); - expect(theme.colorScheme.shadow, const Color(0xff000000)); - expect(theme.colorScheme.brightness, Brightness.dark); - - expect(theme.primaryColor, theme.colorScheme.surface); - expect(theme.primaryColorBrightness, Brightness.dark); - expect(theme.canvasColor, theme.colorScheme.background); - expect(theme.accentColor, theme.colorScheme.secondary); - expect(theme.accentColorBrightness, Brightness.light); - expect(theme.scaffoldBackgroundColor, theme.colorScheme.background); - expect(theme.bottomAppBarColor, theme.colorScheme.surface); - expect(theme.cardColor, theme.colorScheme.surface); - expect(theme.dividerColor, theme.colorScheme.outline); - expect(theme.backgroundColor, theme.colorScheme.background); - expect(theme.dialogBackgroundColor, theme.colorScheme.background); - expect(theme.indicatorColor, theme.colorScheme.onSurface); - expect(theme.errorColor, theme.colorScheme.error); - expect(theme.applyElevationOverlayColor, true); - }); - testWidgets('ThemeData.from a light color scheme sets appropriate values', (WidgetTester tester) async { const ColorScheme lightColors = ColorScheme.light(); final ThemeData theme = ThemeData.from(colorScheme: lightColors); @@ -403,7 +308,6 @@ void main() { highlightColor: Colors.black, splashColor: Colors.black, splashFactory: InkRipple.splashFactory, - useMaterial3: false, selectedRowColor: Colors.black, unselectedWidgetColor: Colors.black, disabledColor: Colors.black, @@ -502,7 +406,6 @@ void main() { highlightColor: Colors.white, splashColor: Colors.white, splashFactory: InkRipple.splashFactory, - useMaterial3: true, selectedRowColor: Colors.white, unselectedWidgetColor: Colors.white, disabledColor: Colors.white, @@ -585,7 +488,6 @@ void main() { highlightColor: otherTheme.highlightColor, splashColor: otherTheme.splashColor, splashFactory: otherTheme.splashFactory, - useMaterial3: otherTheme.useMaterial3, selectedRowColor: otherTheme.selectedRowColor, unselectedWidgetColor: otherTheme.unselectedWidgetColor, disabledColor: otherTheme.disabledColor, @@ -664,7 +566,6 @@ void main() { expect(themeDataCopy.highlightColor, equals(otherTheme.highlightColor)); expect(themeDataCopy.splashColor, equals(otherTheme.splashColor)); expect(themeDataCopy.splashFactory, equals(otherTheme.splashFactory)); - expect(themeDataCopy.useMaterial3, equals(otherTheme.useMaterial3)); expect(themeDataCopy.selectedRowColor, equals(otherTheme.selectedRowColor)); expect(themeDataCopy.unselectedWidgetColor, equals(otherTheme.unselectedWidgetColor)); expect(themeDataCopy.disabledColor, equals(otherTheme.disabledColor)); @@ -765,94 +666,88 @@ void main() { test('ThemeData diagnostics include all properties', () { // List of properties must match the properties in ThemeData.hashCode() final Set expectedPropertyNames = { - // GENERAL CONFIGURATION - 'androidOverscrollIndicator', - 'applyElevationOverlayColor', - 'cupertinoOverrideTheme', - 'inputDecorationTheme', - 'materialTapTargetSize', - 'pageTransitionsTheme', - 'platform', - 'scrollbarTheme', - 'splashFactory', 'visualDensity', - 'useMaterial3', - // COLOR - 'colorScheme', 'primaryColor', + 'primaryColorBrightness', 'primaryColorLight', 'primaryColorDark', - 'focusColor', - 'hoverColor', - 'shadowColor', 'canvasColor', + 'shadowColor', + 'accentColor', + 'accentColorBrightness', 'scaffoldBackgroundColor', 'bottomAppBarColor', 'cardColor', 'dividerColor', + 'focusColor', + 'hoverColor', 'highlightColor', 'splashColor', + 'splashFactory', 'selectedRowColor', 'unselectedWidgetColor', 'disabledColor', + 'buttonTheme', + 'buttonColor', + 'toggleButtonsTheme', 'secondaryHeaderColor', + 'textSelectionColor', + 'cursorColor', + 'textSelectionHandleColor', 'backgroundColor', 'dialogBackgroundColor', 'indicatorColor', 'hintColor', 'errorColor', 'toggleableActiveColor', - // TYPOGRAPHY & ICONOGRAPHY - 'typography', 'textTheme', 'primaryTextTheme', + 'accentTextTheme', + 'inputDecorationTheme', 'iconTheme', 'primaryIconTheme', - // COMPONENT THEMES - 'appBarTheme', - 'bannerTheme', - 'bottomAppBarTheme', - 'bottomNavigationBarTheme', - 'bottomSheetTheme', - 'buttonBarTheme', - 'buttonTheme', + 'accentIconTheme', + 'sliderTheme', + 'tabBarTheme', + 'tooltipTheme', 'cardTheme', - 'checkboxTheme', 'chipTheme', - 'dataTableTheme', + 'platform', + 'materialTapTargetSize', + 'applyElevationOverlayColor', + 'pageTransitionsTheme', + 'appBarTheme', + 'scrollbarTheme', + 'bottomAppBarTheme', + 'colorScheme', 'dialogTheme', - 'dividerTheme', - 'drawerTheme', - 'elevatedButtonTheme', 'floatingActionButtonTheme', - 'listTileTheme', 'navigationBarTheme', 'navigationRailTheme', - 'outlinedButtonTheme', - 'popupMenuTheme', - 'progressIndicatorTheme', - 'radioTheme', - 'sliderTheme', + 'typography', + 'cupertinoOverrideTheme', 'snackBarTheme', - 'switchTheme', - 'tabBarTheme', + 'bottomSheetTheme', + 'popupMenuTheme', + 'bannerTheme', + 'dividerTheme', + 'buttonBarTheme', + 'bottomNavigationBarTheme', + 'timePickerTheme', 'textButtonTheme', + 'elevatedButtonTheme', + 'outlinedButtonTheme', 'textSelectionTheme', - 'timePickerTheme', - 'toggleButtonsTheme', - 'tooltipTheme', - // DEPRECATED (newest deprecations at the bottom) - 'useTextSelectionTheme', - 'textSelectionColor', - 'cursorColor', - 'textSelectionHandleColor', - 'accentColor', - 'accentColorBrightness', - 'accentTextTheme', - 'accentIconTheme', - 'buttonColor', + 'dataTableTheme', + 'checkboxTheme', + 'radioTheme', + 'switchTheme', + 'progressIndicatorTheme', + 'drawerTheme', + 'listTileTheme', 'fixTextFieldOutlineLabel', - 'primaryColorBrightness', + 'useTextSelectionTheme', + 'androidOverscrollIndicator', }; final DiagnosticPropertiesBuilder properties = DiagnosticPropertiesBuilder(); diff --git a/packages/flutter/test/material/theme_test.dart b/packages/flutter/test/material/theme_test.dart index 03aa0e4bfbec5..f477b9dabc2c8 100644 --- a/packages/flutter/test/material/theme_test.dart +++ b/packages/flutter/test/material/theme_test.dart @@ -373,19 +373,17 @@ void main() { List extractStyles(TextTheme textTheme) { return [ - textTheme.displayLarge!, - textTheme.displayMedium!, - textTheme.displaySmall!, - textTheme.headlineLarge!, - textTheme.headlineMedium!, - textTheme.headlineSmall!, - textTheme.titleLarge!, - textTheme.titleMedium!, - textTheme.bodyLarge!, - textTheme.bodyMedium!, - textTheme.bodySmall!, - textTheme.labelLarge!, - textTheme.labelMedium!, + textTheme.headline1!, + textTheme.headline2!, + textTheme.headline3!, + textTheme.headline4!, + textTheme.headline5!, + textTheme.headline6!, + textTheme.subtitle1!, + textTheme.bodyText1!, + textTheme.bodyText2!, + textTheme.caption!, + textTheme.button!, ]; } @@ -410,7 +408,7 @@ void main() { } } - expect(theme.textTheme.displayLarge!.debugLabel, '(englishLike displayLarge 2014).merge(blackMountainView displayLarge)'); + expect(theme.textTheme.headline1!.debugLabel, '(englishLike display4 2014).merge(blackMountainView headline1)'); }); group('Cupertino theme', () { diff --git a/packages/flutter/test/material/toggle_buttons_test.dart b/packages/flutter/test/material/toggle_buttons_test.dart index a414e31665572..3e01b4708336d 100644 --- a/packages/flutter/test/material/toggle_buttons_test.dart +++ b/packages/flutter/test/material/toggle_buttons_test.dart @@ -1591,96 +1591,6 @@ void main() { }, ); - testWidgets('Tap target size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { - Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) { - return Theme( - data: ThemeData(materialTapTargetSize: tapTargetSize), - child: Material( - child: boilerplate( - child: ToggleButtons( - key: key, - constraints: const BoxConstraints(minWidth: 32.0, minHeight: 32.0), - isSelected: const [false, true, false], - onPressed: (int index) {}, - children: const [ - Text('First'), - Text('Second'), - Text('Third'), - ], - ), - ), - ), - ); - } - - final Key key1 = UniqueKey(); - await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); - expect(tester.getSize(find.byKey(key1)), const Size(228.0, 48.0)); - - final Key key2 = UniqueKey(); - await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); - expect(tester.getSize(find.byKey(key2)), const Size(228.0, 34.0)); - }); - - testWidgets('Tap target size is configurable', (WidgetTester tester) async { - Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) { - return Material( - child: boilerplate( - child: ToggleButtons( - key: key, - tapTargetSize: tapTargetSize, - constraints: const BoxConstraints(minWidth: 32.0, minHeight: 32.0), - isSelected: const [false, true, false], - onPressed: (int index) {}, - children: const [ - Text('First'), - Text('Second'), - Text('Third'), - ], - ), - ), - ); - } - - final Key key1 = UniqueKey(); - await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); - expect(tester.getSize(find.byKey(key1)), const Size(228.0, 48.0)); - - final Key key2 = UniqueKey(); - await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); - expect(tester.getSize(find.byKey(key2)), const Size(228.0, 34.0)); - }); - - testWidgets('Tap target size is configurable for vertical axis', (WidgetTester tester) async { - Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) { - return Material( - child: boilerplate( - child: ToggleButtons( - key: key, - tapTargetSize: tapTargetSize, - constraints: const BoxConstraints(minWidth: 32.0, minHeight: 32.0), - direction: Axis.vertical, - isSelected: const [false, true, false], - onPressed: (int index) {}, - children: const [ - Text('1'), - Text('2'), - Text('3'), - ], - ), - ), - ); - } - - final Key key1 = UniqueKey(); - await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); - expect(tester.getSize(find.byKey(key1)), const Size(48.0, 100.0)); - - final Key key2 = UniqueKey(); - await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); - expect(tester.getSize(find.byKey(key2)), const Size(34.0, 100.0)); - }); - // Regression test for https://github.com/flutter/flutter/issues/73725 testWidgets('Border radius paint test when there is only one button', (WidgetTester tester) async { final ThemeData theme = ThemeData(); diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 3af33ce496e24..4e8560b37cb1b 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -584,7 +584,7 @@ void main() { expect(textStyle.color, Colors.white); expect(textStyle.fontFamily, 'Roboto'); expect(textStyle.decoration, TextDecoration.none); - expect(textStyle.debugLabel, '((englishLike bodyMedium 2014).merge(blackMountainView bodyMedium)).copyWith'); + expect(textStyle.debugLabel, '((englishLike body1 2014).merge(blackMountainView bodyText2)).copyWith'); }); testWidgets('Default tooltip message textStyle - dark', (WidgetTester tester) async { @@ -610,7 +610,7 @@ void main() { expect(textStyle.color, Colors.black); expect(textStyle.fontFamily, 'Roboto'); expect(textStyle.decoration, TextDecoration.none); - expect(textStyle.debugLabel, '((englishLike bodyMedium 2014).merge(whiteMountainView bodyMedium)).copyWith'); + expect(textStyle.debugLabel, '((englishLike body1 2014).merge(whiteMountainView bodyText2)).copyWith'); }); testWidgets('Custom tooltip message textStyle', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/typography_test.dart b/packages/flutter/test/material/typography_test.dart index 703e67bf95aa5..cdee39affe98c 100644 --- a/packages/flutter/test/material/typography_test.dart +++ b/packages/flutter/test/material/typography_test.dart @@ -17,16 +17,16 @@ void main() { }); test('Typography on non-Apple platforms defaults to the correct font', () { - expect(Typography.material2018().black.titleLarge!.fontFamily, 'Roboto'); - expect(Typography.material2018(platform: TargetPlatform.fuchsia).black.titleLarge!.fontFamily, 'Roboto'); - expect(Typography.material2018(platform: TargetPlatform.linux).black.titleLarge!.fontFamily, 'Roboto'); - expect(Typography.material2018(platform: TargetPlatform.linux).black.titleLarge!.fontFamilyFallback, ['Ubuntu', 'Cantarell', 'DejaVu Sans', 'Liberation Sans', 'Arial']); - expect(Typography.material2018(platform: TargetPlatform.windows).black.titleLarge!.fontFamily, 'Segoe UI'); - expect(Typography.material2018().white.titleLarge!.fontFamily, 'Roboto'); - expect(Typography.material2018(platform: TargetPlatform.fuchsia).white.titleLarge!.fontFamily, 'Roboto'); - expect(Typography.material2018(platform: TargetPlatform.linux).white.titleLarge!.fontFamily, 'Roboto'); - expect(Typography.material2018(platform: TargetPlatform.linux).white.titleLarge!.fontFamilyFallback, ['Ubuntu', 'Cantarell', 'DejaVu Sans', 'Liberation Sans', 'Arial']); - expect(Typography.material2018(platform: TargetPlatform.windows).white.titleLarge!.fontFamily, 'Segoe UI'); + expect(Typography.material2018().black.headline6!.fontFamily, 'Roboto'); + expect(Typography.material2018(platform: TargetPlatform.fuchsia).black.headline6!.fontFamily, 'Roboto'); + expect(Typography.material2018(platform: TargetPlatform.linux).black.headline6!.fontFamily, 'Roboto'); + expect(Typography.material2018(platform: TargetPlatform.linux).black.headline6!.fontFamilyFallback, ['Ubuntu', 'Cantarell', 'DejaVu Sans', 'Liberation Sans', 'Arial']); + expect(Typography.material2018(platform: TargetPlatform.windows).black.headline6!.fontFamily, 'Segoe UI'); + expect(Typography.material2018().white.headline6!.fontFamily, 'Roboto'); + expect(Typography.material2018(platform: TargetPlatform.fuchsia).white.headline6!.fontFamily, 'Roboto'); + expect(Typography.material2018(platform: TargetPlatform.linux).white.headline6!.fontFamily, 'Roboto'); + expect(Typography.material2018(platform: TargetPlatform.linux).white.headline6!.fontFamilyFallback, ['Ubuntu', 'Cantarell', 'DejaVu Sans', 'Liberation Sans', 'Arial']); + expect(Typography.material2018(platform: TargetPlatform.windows).white.headline6!.fontFamily, 'Segoe UI'); }); // Ref: https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/ @@ -45,42 +45,38 @@ void main() { test('Typography on iOS defaults to the correct SF font family based on size', () { final Typography typography = Typography.material2018(platform: TargetPlatform.iOS); for (final TextTheme textTheme in [typography.black, typography.white]) { - expect(textTheme.displayLarge, isSanFranciscoDisplayFont); - expect(textTheme.displayMedium, isSanFranciscoDisplayFont); - expect(textTheme.displaySmall, isSanFranciscoDisplayFont); - expect(textTheme.headlineLarge, isSanFranciscoDisplayFont); - expect(textTheme.headlineMedium, isSanFranciscoDisplayFont); - expect(textTheme.headlineSmall, isSanFranciscoDisplayFont); - expect(textTheme.titleLarge, isSanFranciscoDisplayFont); - expect(textTheme.titleMedium, isSanFranciscoTextFont); - expect(textTheme.titleSmall, isSanFranciscoTextFont); - expect(textTheme.bodyLarge, isSanFranciscoTextFont); - expect(textTheme.bodyMedium, isSanFranciscoTextFont); - expect(textTheme.bodySmall, isSanFranciscoTextFont); - expect(textTheme.labelLarge, isSanFranciscoTextFont); - expect(textTheme.labelMedium, isSanFranciscoTextFont); - expect(textTheme.labelSmall, isSanFranciscoTextFont); + expect(textTheme.headline1, isSanFranciscoDisplayFont); + expect(textTheme.headline2, isSanFranciscoDisplayFont); + expect(textTheme.headline3, isSanFranciscoDisplayFont); + expect(textTheme.headline4, isSanFranciscoDisplayFont); + expect(textTheme.headline5, isSanFranciscoDisplayFont); + expect(textTheme.headline6, isSanFranciscoDisplayFont); + expect(textTheme.subtitle1, isSanFranciscoTextFont); + expect(textTheme.bodyText1, isSanFranciscoTextFont); + expect(textTheme.bodyText2, isSanFranciscoTextFont); + expect(textTheme.caption, isSanFranciscoTextFont); + expect(textTheme.button, isSanFranciscoTextFont); + expect(textTheme.subtitle2, isSanFranciscoTextFont); + expect(textTheme.overline, isSanFranciscoTextFont); } }); test('Typography on macOS defaults to the system UI meta-font', () { final Typography typography = Typography.material2018(platform: TargetPlatform.macOS); for (final TextTheme textTheme in [typography.black, typography.white]) { - expect(textTheme.displayLarge, isMacOSSanFranciscoMetaFont); - expect(textTheme.displayMedium, isMacOSSanFranciscoMetaFont); - expect(textTheme.displaySmall, isMacOSSanFranciscoMetaFont); - expect(textTheme.headlineLarge, isMacOSSanFranciscoMetaFont); - expect(textTheme.headlineMedium, isMacOSSanFranciscoMetaFont); - expect(textTheme.headlineSmall, isMacOSSanFranciscoMetaFont); - expect(textTheme.titleLarge, isMacOSSanFranciscoMetaFont); - expect(textTheme.titleMedium, isMacOSSanFranciscoMetaFont); - expect(textTheme.titleSmall, isMacOSSanFranciscoMetaFont); - expect(textTheme.bodyLarge, isMacOSSanFranciscoMetaFont); - expect(textTheme.bodyMedium, isMacOSSanFranciscoMetaFont); - expect(textTheme.bodySmall, isMacOSSanFranciscoMetaFont); - expect(textTheme.labelLarge, isMacOSSanFranciscoMetaFont); - expect(textTheme.labelMedium, isMacOSSanFranciscoMetaFont); - expect(textTheme.labelSmall, isMacOSSanFranciscoMetaFont); + expect(textTheme.headline1, isMacOSSanFranciscoMetaFont); + expect(textTheme.headline2, isMacOSSanFranciscoMetaFont); + expect(textTheme.headline3, isMacOSSanFranciscoMetaFont); + expect(textTheme.headline4, isMacOSSanFranciscoMetaFont); + expect(textTheme.headline5, isMacOSSanFranciscoMetaFont); + expect(textTheme.headline6, isMacOSSanFranciscoMetaFont); + expect(textTheme.subtitle1, isMacOSSanFranciscoMetaFont); + expect(textTheme.bodyText1, isMacOSSanFranciscoMetaFont); + expect(textTheme.bodyText2, isMacOSSanFranciscoMetaFont); + expect(textTheme.caption, isMacOSSanFranciscoMetaFont); + expect(textTheme.button, isMacOSSanFranciscoMetaFont); + expect(textTheme.subtitle2, isMacOSSanFranciscoMetaFont); + expect(textTheme.overline, isMacOSSanFranciscoMetaFont); } }); @@ -111,93 +107,81 @@ void main() { const FontWeight medium = FontWeight.w500; // H1 Roboto light 96 -1.5 - expect(theme.displayLarge!.fontFamily, 'Roboto'); - expect(theme.displayLarge!.fontWeight, light); - expect(theme.displayLarge!.fontSize, 96); - expect(theme.displayLarge!.letterSpacing, -1.5); + expect(theme.headline1!.fontFamily, 'Roboto'); + expect(theme.headline1!.fontWeight, light); + expect(theme.headline1!.fontSize, 96); + expect(theme.headline1!.letterSpacing, -1.5); // H2 Roboto light 60 -0.5 - expect(theme.displayMedium!.fontFamily, 'Roboto'); - expect(theme.displayMedium!.fontWeight, light); - expect(theme.displayMedium!.fontSize, 60); - expect(theme.displayMedium!.letterSpacing, -0.5); + expect(theme.headline2!.fontFamily, 'Roboto'); + expect(theme.headline2!.fontWeight, light); + expect(theme.headline2!.fontSize, 60); + expect(theme.headline2!.letterSpacing, -0.5); // H3 Roboto regular 48 0 - expect(theme.displaySmall!.fontFamily, 'Roboto'); - expect(theme.displaySmall!.fontWeight, regular); - expect(theme.displaySmall!.fontSize, 48); - expect(theme.displaySmall!.letterSpacing, 0); - - // Headline Large (from Material 3 for backwards compatibility) Roboto regular 40 0.25 - expect(theme.headlineLarge!.fontFamily, 'Roboto'); - expect(theme.headlineLarge!.fontWeight, regular); - expect(theme.headlineLarge!.fontSize, 40); - expect(theme.headlineLarge!.letterSpacing, 0.25); + expect(theme.headline3!.fontFamily, 'Roboto'); + expect(theme.headline3!.fontWeight, regular); + expect(theme.headline3!.fontSize, 48); + expect(theme.headline3!.letterSpacing, 0); // H4 Roboto regular 34 0.25 - expect(theme.headlineMedium!.fontFamily, 'Roboto'); - expect(theme.headlineMedium!.fontWeight, regular); - expect(theme.headlineMedium!.fontSize, 34); - expect(theme.headlineMedium!.letterSpacing, 0.25); + expect(theme.headline4!.fontFamily, 'Roboto'); + expect(theme.headline4!.fontWeight, regular); + expect(theme.headline4!.fontSize, 34); + expect(theme.headline4!.letterSpacing, 0.25); // H5 Roboto regular 24 0 - expect(theme.headlineSmall!.fontFamily, 'Roboto'); - expect(theme.headlineSmall!.fontWeight, regular); - expect(theme.headlineSmall!.fontSize, 24); - expect(theme.headlineSmall!.letterSpacing, 0); + expect(theme.headline5!.fontFamily, 'Roboto'); + expect(theme.headline5!.fontWeight, regular); + expect(theme.headline5!.fontSize, 24); + expect(theme.headline5!.letterSpacing, 0); // H6 Roboto medium 20 0.15 - expect(theme.titleLarge!.fontFamily, 'Roboto'); - expect(theme.titleLarge!.fontWeight, medium); - expect(theme.titleLarge!.fontSize, 20); - expect(theme.titleLarge!.letterSpacing, 0.15); + expect(theme.headline6!.fontFamily, 'Roboto'); + expect(theme.headline6!.fontWeight, medium); + expect(theme.headline6!.fontSize, 20); + expect(theme.headline6!.letterSpacing, 0.15); // Subtitle1 Roboto regular 16 0.15 - expect(theme.titleMedium!.fontFamily, 'Roboto'); - expect(theme.titleMedium!.fontWeight, regular); - expect(theme.titleMedium!.fontSize, 16); - expect(theme.titleMedium!.letterSpacing, 0.15); + expect(theme.subtitle1!.fontFamily, 'Roboto'); + expect(theme.subtitle1!.fontWeight, regular); + expect(theme.subtitle1!.fontSize, 16); + expect(theme.subtitle1!.letterSpacing, 0.15); // Subtitle2 Roboto medium 14 0.1 - expect(theme.titleSmall!.fontFamily, 'Roboto'); - expect(theme.titleSmall!.fontWeight, medium); - expect(theme.titleSmall!.fontSize, 14); - expect(theme.titleSmall!.letterSpacing, 0.1); + expect(theme.subtitle2!.fontFamily, 'Roboto'); + expect(theme.subtitle2!.fontWeight, medium); + expect(theme.subtitle2!.fontSize, 14); + expect(theme.subtitle2!.letterSpacing, 0.1); // Body1 Roboto regular 16 0.5 - expect(theme.bodyLarge!.fontFamily, 'Roboto'); - expect(theme.bodyLarge!.fontWeight, regular); - expect(theme.bodyLarge!.fontSize, 16); - expect(theme.bodyLarge!.letterSpacing, 0.5); + expect(theme.bodyText1!.fontFamily, 'Roboto'); + expect(theme.bodyText1!.fontWeight, regular); + expect(theme.bodyText1!.fontSize, 16); + expect(theme.bodyText1!.letterSpacing, 0.5); // Body2 Roboto regular 14 0.25 - expect(theme.bodyMedium!.fontFamily, 'Roboto'); - expect(theme.bodyMedium!.fontWeight, regular); - expect(theme.bodyMedium!.fontSize, 14); - expect(theme.bodyMedium!.letterSpacing, 0.25); - - // Caption Roboto regular 12 0.4 - expect(theme.bodySmall!.fontFamily, 'Roboto'); - expect(theme.bodySmall!.fontWeight, regular); - expect(theme.bodySmall!.fontSize, 12); - expect(theme.bodySmall!.letterSpacing, 0.4); + expect(theme.bodyText2!.fontFamily, 'Roboto'); + expect(theme.bodyText2!.fontWeight, regular); + expect(theme.bodyText2!.fontSize, 14); + expect(theme.bodyText2!.letterSpacing, 0.25); // BUTTON Roboto medium 14 1.25 - expect(theme.labelLarge!.fontFamily, 'Roboto'); - expect(theme.labelLarge!.fontWeight, medium); - expect(theme.labelLarge!.fontSize, 14); - expect(theme.labelLarge!.letterSpacing, 1.25); + expect(theme.button!.fontFamily, 'Roboto'); + expect(theme.button!.fontWeight, medium); + expect(theme.button!.fontSize, 14); + expect(theme.button!.letterSpacing, 1.25); - // Label Medium (from Material 3 for backwards compatibility) Roboto regular 11 1.5 - expect(theme.labelMedium!.fontFamily, 'Roboto'); - expect(theme.labelMedium!.fontWeight, regular); - expect(theme.labelMedium!.fontSize, 11); - expect(theme.labelMedium!.letterSpacing, 1.5); + // Caption Roboto regular 12 0.4 + expect(theme.caption!.fontFamily, 'Roboto'); + expect(theme.caption!.fontWeight, regular); + expect(theme.caption!.fontSize, 12); + expect(theme.caption!.letterSpacing, 0.4); // OVERLINE Roboto regular 10 1.5 - expect(theme.labelSmall!.fontFamily, 'Roboto'); - expect(theme.labelSmall!.fontWeight, regular); - expect(theme.labelSmall!.fontSize, 10); - expect(theme.labelSmall!.letterSpacing, 1.5); + expect(theme.overline!.fontFamily, 'Roboto'); + expect(theme.overline!.fontWeight, regular); + expect(theme.overline!.fontSize, 10); + expect(theme.overline!.letterSpacing, 1.5); }); } diff --git a/packages/flutter/test/material/will_pop_test.dart b/packages/flutter/test/material/will_pop_test.dart index 3fca53ac7f62e..63c60caa50f69 100644 --- a/packages/flutter/test/material/will_pop_test.dart +++ b/packages/flutter/test/material/will_pop_test.dart @@ -65,35 +65,13 @@ class SampleForm extends StatelessWidget { } // Expose the protected hasScopedWillPopCallback getter -class _TestPageRoute extends MaterialPageRoute { - _TestPageRoute({ - RouteSettings? settings, - required WidgetBuilder builder, - }) : super(builder: builder, maintainState: true, settings: settings); +class TestPageRoute extends MaterialPageRoute { + TestPageRoute({ required WidgetBuilder builder }) + : super(builder: builder, maintainState: true); bool get hasCallback => super.hasScopedWillPopCallback; } -class _TestPage extends Page { - _TestPage({ - required this.builder, - required LocalKey key, - }) : _key = GlobalKey(), - super(key: key); - - final WidgetBuilder builder; - final GlobalKey _key; - - @override - Route createRoute(BuildContext context) { - return _TestPageRoute( - settings: this, - builder: (BuildContext context) { - // keep state during move to another location in tree - return KeyedSubtree(key: _key, child: builder.call(context)); - }); - } -} void main() { testWidgets('ModalRoute scopedWillPopupCallback can inhibit back button', (WidgetTester tester) async { @@ -340,7 +318,7 @@ void main() { late StateSetter contentsSetState; // call this to rebuild the route's SampleForm contents bool contentsEmpty = false; // when true, don't include the SampleForm in the route - final _TestPageRoute route = _TestPageRoute( + final TestPageRoute route = TestPageRoute( builder: (BuildContext context) { return StatefulBuilder( builder: (BuildContext context, StateSetter setState) { @@ -395,61 +373,4 @@ void main() { expect(route.hasCallback, isFalse); }); - - testWidgets('should handle new route if page moved from one navigator to another', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/89133 - late StateSetter contentsSetState; - bool moveToAnotherNavigator = false; - - final List> pages = >[ - _TestPage( - key: UniqueKey(), - builder: (BuildContext context) { - return WillPopScope( - onWillPop: () async => true, - child: const Text('anchor'), - ); - }, - ) - ]; - - Widget _buildNavigator(Key? key, List> pages) { - return Navigator( - key: key, - pages: pages, - onPopPage: (Route route, dynamic result) { - return route.didPop(result); - }, - ); - } - - Widget buildFrame() { - return MaterialApp( - home: Scaffold( - body: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - contentsSetState = setState; - if (moveToAnotherNavigator) { - return _buildNavigator(const ValueKey(1), pages); - } - return _buildNavigator(const ValueKey(2), pages); - }, - ), - ), - ); - } - - await tester.pumpWidget(buildFrame()); - await tester.pump(); - final _TestPageRoute route1 = ModalRoute.of(tester.element(find.text('anchor')))! as _TestPageRoute; - expect(route1.hasCallback, isTrue); - moveToAnotherNavigator = true; - contentsSetState(() {}); - - await tester.pump(); - final _TestPageRoute route2 = ModalRoute.of(tester.element(find.text('anchor')))! as _TestPageRoute; - - expect(route1.hasCallback, isFalse); - expect(route2.hasCallback, isTrue); - }); } diff --git a/packages/flutter/test/painting/image_provider_network_image_test.dart b/packages/flutter/test/painting/image_provider_network_image_test.dart index 5407b68293f7d..333af0fb6ede1 100644 --- a/packages/flutter/test/painting/image_provider_network_image_test.dart +++ b/packages/flutter/test/painting/image_provider_network_image_test.dart @@ -36,7 +36,7 @@ void main() { }); test('Expect thrown exception with statusCode - evicts from cache and drains', () async { - const int errorStatusCode = HttpStatus.notFound; + final int errorStatusCode = HttpStatus.notFound; const String requestUrl = 'foo-url'; httpClient.request.response.statusCode = errorStatusCode; diff --git a/packages/flutter/test/painting/image_stream_test.dart b/packages/flutter/test/painting/image_stream_test.dart index 6c0d692d0ce6c..05cae5847d034 100644 --- a/packages/flutter/test/painting/image_stream_test.dart +++ b/packages/flutter/test/painting/image_stream_test.dart @@ -811,31 +811,44 @@ void main() { expect(oneFrameCodec.numFramesAsked, 1); }); // https://github.com/flutter/flutter/issues/82532 - test('Multi-frame complete unsubscribes to chunk events when disposed', () async { - final FakeCodec codec = await FakeCodec.fromData(Uint8List.fromList(kTransparentImage)); - final StreamController chunkStream = StreamController(); - - final MultiFrameImageStreamCompleter completer = MultiFrameImageStreamCompleter( - codec: Future.value(codec), - scale: 1.0, - chunkEvents: chunkStream.stream, - ); - - expect(chunkStream.hasListener, true); - - chunkStream.add(const ImageChunkEvent(cumulativeBytesLoaded: 1, expectedTotalBytes: 3)); - - final ImageStreamListener listener = ImageStreamListener((ImageInfo info, bool syncCall) {}); - // Cause the completer to dispose. - completer.addListener(listener); - completer.removeListener(listener); - - expect(chunkStream.hasListener, false); - - // The above expectation should cover this, but the point of this test is to - // make sure the completer does not assert that it's disposed and still - // receiving chunk events. Streams from the network can keep sending data - // even after evicting an image from the cache, for example. - chunkStream.add(const ImageChunkEvent(cumulativeBytesLoaded: 2, expectedTotalBytes: 3)); - }); + // TODO(amirh): enable this once WidgetTester supports flushTimers. + // https://github.com/flutter/flutter/issues/30344 + // testWidgets('remove and add listener before a delayed frame is scheduled', (WidgetTester tester) async { + // final MockCodec mockCodec = MockCodec(); + // mockCodec.frameCount = 3; + // mockCodec.repetitionCount = 0; + // final Completer codecCompleter = Completer(); + // + // final ImageStreamCompleter imageStream = MultiFrameImageStreamCompleter( + // codec: codecCompleter.future, + // scale: 1.0, + // ); + // + // final ImageListener listener = (ImageInfo image, bool synchronousCall) { }; + // imageStream.addListener(ImageLoadingListener(listener)); + // + // codecCompleter.complete(mockCodec); + // await tester.idle(); + // + // final FrameInfo frame1 = FakeFrameInfo(20, 10, const Duration(milliseconds: 200)); + // final FrameInfo frame2 = FakeFrameInfo(200, 100, const Duration(milliseconds: 400)); + // final FrameInfo frame3 = FakeFrameInfo(200, 100, Duration.zero); + // + // mockCodec.completeNextFrame(frame1); + // await tester.idle(); // let nextFrameFuture complete + // await tester.pump(); // first animation frame shows on first app frame. + // + // mockCodec.completeNextFrame(frame2); + // await tester.pump(const Duration(milliseconds: 100)); // emit 2nd frame. + // + // tester.flushTimers(); + // + // imageStream.removeListener(listener); + // imageStream.addListener(ImageLoadingListener(listener)); + // + // mockCodec.completeNextFrame(frame3); + // await tester.idle(); // let nextFrameFuture complete + // + // await tester.pump(); + // }); } diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart index fa67d50a101bf..13f036c0bc5ca 100644 --- a/packages/flutter/test/rendering/editable_test.dart +++ b/packages/flutter/test/rendering/editable_test.dart @@ -883,9 +883,7 @@ void main() { editable.layout(BoxConstraints.loose(const Size(1000.0, 1000.0))); expect(editable.maxScrollExtent, equals(10)); - // TODO(yjbanov): This test is failing in the Dart HHH-web bot and - // needs additional investigation before it can be reenabled. - }, skip: const bool.fromEnvironment('DART_HHH_BOT')); // https://github.com/flutter/flutter/issues/93691 + }); test('getEndpointsForSelection handles empty characters', () { final TextSelectionDelegate delegate = _FakeEditableTextState(); diff --git a/packages/flutter/test/rendering/first_frame_test.dart b/packages/flutter/test/rendering/first_frame_test.dart index c55878b76307a..bacf613e8946c 100644 --- a/packages/flutter/test/rendering/first_frame_test.dart +++ b/packages/flutter/test/rendering/first_frame_test.dart @@ -18,7 +18,6 @@ void main() { const MethodChannel firstFrameChannel = MethodChannel('flutter/service_worker'); binding.defaultBinaryMessenger.setMockMethodCallHandler(firstFrameChannel, (MethodCall methodCall) async { completer.complete(); - return null; }); binding.handleBeginFrame(Duration.zero); diff --git a/packages/flutter/test/rendering/layers_test.dart b/packages/flutter/test/rendering/layers_test.dart index 361fb6a0f8ef9..8d4e2dcede056 100644 --- a/packages/flutter/test/rendering/layers_test.dart +++ b/packages/flutter/test/rendering/layers_test.dart @@ -164,19 +164,7 @@ void main() { expect(followerLayer.debugSubtreeNeedsAddToScene, true); }); - test('switching layer link of an attached leader layer should not crash', () { - final LayerLink link = LayerLink(); - final LeaderLayer leaderLayer = LeaderLayer(link: link); - final RenderView view = RenderView(configuration: const ViewConfiguration(), window: window); - leaderLayer.attach(view); - final LayerLink link2 = LayerLink(); - leaderLayer.link = link2; - // This should not crash. - leaderLayer.detach(); - expect(leaderLayer.link, link2); - }); - - test('leader layers not dirty when connected to follower layer', () { + test('leader layers are always dirty when connected to follower layer', () { final ContainerLayer root = ContainerLayer()..attach(Object()); final LayerLink link = LayerLink(); @@ -190,7 +178,7 @@ void main() { followerLayer.debugMarkClean(); leaderLayer.updateSubtreeNeedsAddToScene(); followerLayer.updateSubtreeNeedsAddToScene(); - expect(leaderLayer.debugSubtreeNeedsAddToScene, false); + expect(leaderLayer.debugSubtreeNeedsAddToScene, true); }); test('leader layers are not dirty when all followers disconnects', () { @@ -204,24 +192,24 @@ void main() { leaderLayer.updateSubtreeNeedsAddToScene(); expect(leaderLayer.debugSubtreeNeedsAddToScene, false); - // Connecting a follower does not require adding to scene + // Connecting a follower requires adding to scene. final FollowerLayer follower1 = FollowerLayer(link: link); root.append(follower1); leaderLayer.debugMarkClean(); leaderLayer.updateSubtreeNeedsAddToScene(); - expect(leaderLayer.debugSubtreeNeedsAddToScene, false); + expect(leaderLayer.debugSubtreeNeedsAddToScene, true); final FollowerLayer follower2 = FollowerLayer(link: link); root.append(follower2); leaderLayer.debugMarkClean(); leaderLayer.updateSubtreeNeedsAddToScene(); - expect(leaderLayer.debugSubtreeNeedsAddToScene, false); + expect(leaderLayer.debugSubtreeNeedsAddToScene, true); - // Disconnecting one follower, still does not needs add to scene. + // Disconnecting one follower, still needs add to scene. follower2.remove(); leaderLayer.debugMarkClean(); leaderLayer.updateSubtreeNeedsAddToScene(); - expect(leaderLayer.debugSubtreeNeedsAddToScene, false); + expect(leaderLayer.debugSubtreeNeedsAddToScene, true); // Disconnecting all followers goes back to not requiring add to scene. follower1.remove(); @@ -230,36 +218,6 @@ void main() { expect(leaderLayer.debugSubtreeNeedsAddToScene, false); }); - test('LeaderLayer.applyTransform can be called after retained rendering', () { - void expectTransform(RenderObject leader) { - final LeaderLayer leaderLayer = leader.debugLayer! as LeaderLayer; - final Matrix4 expected = Matrix4.identity() - ..translate(leaderLayer.offset.dx, leaderLayer.offset.dy); - final Matrix4 transformed = Matrix4.identity(); - leaderLayer.applyTransform(null, transformed); - expect(transformed, expected); - } - - final LayerLink link = LayerLink(); - late RenderLeaderLayer leader; - final RenderRepaintBoundary root = RenderRepaintBoundary( - child:RenderRepaintBoundary( - child: leader = RenderLeaderLayer(link: link), - ), - ); - layout(root, phase: EnginePhase.composite); - - expectTransform(leader); - - // Causes a repaint, but the LeaderLayer of RenderLeaderLayer will be added - // as retained and LeaderLayer.addChildrenToScene will not be called. - root.markNeedsPaint(); - pumpFrame(phase: EnginePhase.composite); - - // The LeaderLayer.applyTransform call shouldn't crash. - expectTransform(leader); - }); - test('depthFirstIterateChildren', () { final ContainerLayer a = ContainerLayer(); final ContainerLayer b = ContainerLayer(); @@ -679,21 +637,6 @@ void main() { expect(builder.addedPicture, true); expect(layer.engineLayer, isA()); }); - - test('OpacityLayer dispose its engineLayer if there are no children', () { - final OpacityLayer layer = OpacityLayer(alpha: 128); - final FakeSceneBuilder builder = FakeSceneBuilder(); - layer.addToScene(builder); - expect(layer.engineLayer, null); - - layer.append(PictureLayer(Rect.largest)..picture = FakePicture()); - layer.addToScene(builder); - expect(layer.engineLayer, isA()); - - layer.removeAllChildren(); - layer.addToScene(builder); - expect(layer.engineLayer, null); - }); } class FakeEngineLayer extends Fake implements EngineLayer { diff --git a/packages/flutter/test/rendering/mock_canvas.dart b/packages/flutter/test/rendering/mock_canvas.dart index e2073551fdb8d..d9bb0b059cd50 100644 --- a/packages/flutter/test/rendering/mock_canvas.dart +++ b/packages/flutter/test/rendering/mock_canvas.dart @@ -426,10 +426,6 @@ abstract class PaintPattern { /// The predicate will be applied to each [Canvas] call until it returns false /// or all of the method calls have been tested. /// - /// If the predicate returns false, then the [paints] [Matcher] is considered - /// to have failed. If all calls are tested without failing, then the [paints] - /// [Matcher] is considered a success. - /// /// If the predicate throws a [String], then the [paints] [Matcher] is /// considered to have failed. The thrown string is used in the message /// displayed from the test framework and should be complete sentence @@ -835,11 +831,7 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher imp return false; } on String catch (s) { description.writeln(s); - try { - description.write('The stack of the offending call was:\n${call.current.stackToString(indent: " ")}\n'); - } on TypeError catch (_) { - // All calls have been evaluated - } + description.write('The stack of the offending call was:\n${call.current.stackToString(indent: " ")}\n'); return false; } return true; @@ -1401,18 +1393,13 @@ class _SomethingPaintPredicate extends _PaintPredicate { @override void match(Iterator call) { + assert(predicate != null); RecordedInvocation currentCall; - bool testedAllCalls = false; do { - if (testedAllCalls) { - throw 'It painted methods that the predicate passed to a "something" step, ' - 'in the paint pattern, none of which were considered correct.'; - } currentCall = call.current; if (!currentCall.invocation.isMethod) throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; - testedAllCalls = !call.moveNext(); - } while (!_runPredicate(currentCall.invocation.memberName, currentCall.invocation.positionalArguments)); + } while (call.moveNext() && !_runPredicate(currentCall.invocation.memberName, currentCall.invocation.positionalArguments)); } bool _runPredicate(Symbol methodName, List arguments) { @@ -1435,14 +1422,14 @@ class _EverythingPaintPredicate extends _PaintPredicate { @override void match(Iterator call) { - do { + assert(predicate != null); + while (call.moveNext()) { final RecordedInvocation currentCall = call.current; if (!currentCall.invocation.isMethod) throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; if (!_runPredicate(currentCall.invocation.memberName, currentCall.invocation.positionalArguments)) - throw 'It painted something that the predicate passed to an "everything" step ' - 'in the paint pattern considered incorrect.\n'; - } while (call.moveNext()); + return; + } } bool _runPredicate(Symbol methodName, List arguments) { diff --git a/packages/flutter/test/rendering/mock_canvas_test.dart b/packages/flutter/test/rendering/mock_canvas_test.dart deleted file mode 100644 index 4c097ca84aa4e..0000000000000 --- a/packages/flutter/test/rendering/mock_canvas_test.dart +++ /dev/null @@ -1,246 +0,0 @@ -// 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 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'mock_canvas.dart'; - -class MyPainter extends CustomPainter { - const MyPainter({ - required this.color, - }); - - final Color color; - - @override - void paint(Canvas canvas, Size size) { - canvas.drawColor(color, BlendMode.color); - } - - @override - bool shouldRepaint(MyPainter oldDelegate) { - return true; - } -} - -@immutable -class MethodAndArguments { - const MethodAndArguments(this.method, this.arguments); - - final Symbol method; - final List arguments; - - @override - bool operator ==(Object other) { - if (!(other is MethodAndArguments && other.method == method)) { - return false; - } - for (int i = 0; i < arguments.length; i++) { - if (arguments[i] != other.arguments[i]) { - return false; - } - } - return true; - } - - @override - int get hashCode => method.hashCode; - - @override - String toString() => '$method, $arguments'; -} - -void main() { - group('something', () { - testWidgets('matches when the predicate returns true', (WidgetTester tester) async { - await tester.pumpWidget( - const CustomPaint( - painter: MyPainter(color: Colors.transparent), - child: SizedBox(width: 50, height: 50), - ), - ); - - final List methodsAndArguments = []; - - expect( - tester.renderObject(find.byType(CustomPaint)), - paints..something((Symbol method, List arguments) { - methodsAndArguments.add(MethodAndArguments(method, arguments)); - return method == #drawColor; - }), - ); - - expect( - methodsAndArguments, - [ - const MethodAndArguments(#save, []), - const MethodAndArguments(#drawColor, [Colors.transparent, BlendMode.color]), - // The #restore call is never evaluated - ], - ); - }); - - testWidgets('fails when the predicate always returns false', (WidgetTester tester) async { - await tester.pumpWidget( - const CustomPaint( - painter: MyPainter(color: Colors.transparent), - child: SizedBox(width: 50, height: 50), - ), - ); - - final List methodsAndArguments = []; - - expect( - tester.renderObject(find.byType(CustomPaint)), - isNot( - paints..something((Symbol method, List arguments) { - methodsAndArguments.add(MethodAndArguments(method, arguments)); - return false; - }), - ), - ); - - expect( - methodsAndArguments, - [ - const MethodAndArguments(#save, []), - const MethodAndArguments(#drawColor, [Colors.transparent, BlendMode.color]), - const MethodAndArguments(#restore, []), - ], - ); - }); - - testWidgets('fails when the predicate throws', (WidgetTester tester) async { - await tester.pumpWidget( - const CustomPaint( - painter: MyPainter(color: Colors.transparent), - child: SizedBox(width: 50, height: 50), - ), - ); - - final List methodsAndArguments = []; - - expect( - tester.renderObject(find.byType(CustomPaint)), - isNot( - paints..something((Symbol method, List arguments) { - methodsAndArguments.add(MethodAndArguments(method, arguments)); - if (method == #save) { - return false; - } - if (method == #drawColor) { - throw 'fail'; - } - return true; - }), - ), - ); - - expect( - methodsAndArguments, - [ - const MethodAndArguments(#save, []), - const MethodAndArguments(#drawColor, [Colors.transparent, BlendMode.color]), - // The #restore call is never evaluated - ], - ); - }); - }); - - group('everything', () { - testWidgets('matches when the predicate always returns true', (WidgetTester tester) async { - await tester.pumpWidget( - const CustomPaint( - painter: MyPainter(color: Colors.transparent), - child: SizedBox(width: 50, height: 50), - ), - ); - - final List methodsAndArguments = []; - - expect( - tester.renderObject(find.byType(CustomPaint)), - paints..everything((Symbol method, List arguments) { - methodsAndArguments.add(MethodAndArguments(method, arguments)); - return true; - }), - ); - - expect( - methodsAndArguments, - [ - const MethodAndArguments(#save, []), - const MethodAndArguments(#drawColor, [Colors.transparent, BlendMode.color]), - const MethodAndArguments(#restore, []), - ], - ); - }); - - testWidgets('fails when the predicate returns false', (WidgetTester tester) async { - await tester.pumpWidget( - const CustomPaint( - painter: MyPainter(color: Colors.transparent), - child: SizedBox(width: 50, height: 50), - ), - ); - - final List methodsAndArguments = []; - - expect( - tester.renderObject(find.byType(CustomPaint)), - isNot( - paints..everything((Symbol method, List arguments) { - methodsAndArguments.add(MethodAndArguments(method, arguments)); - // returns false on #drawColor - return method == #restore || method == #save; - }), - ), - ); - - expect( - methodsAndArguments, - [ - const MethodAndArguments(#save, []), - const MethodAndArguments(#drawColor, [Colors.transparent, BlendMode.color]), - // The #restore call is never evaluated - ], - ); - }); - - testWidgets('fails if the predicate ever throws', (WidgetTester tester) async { - await tester.pumpWidget( - const CustomPaint( - painter: MyPainter(color: Colors.transparent), - child: SizedBox(width: 50, height: 50), - ), - ); - - final List methodsAndArguments = []; - - expect( - tester.renderObject(find.byType(CustomPaint)), - isNot( - paints..everything((Symbol method, List arguments) { - methodsAndArguments.add(MethodAndArguments(method, arguments)); - if (method == #drawColor) { - throw 'failed '; - } - return true; - }), - ), - ); - - expect( - methodsAndArguments, - [ - const MethodAndArguments(#save, []), - const MethodAndArguments(#drawColor, [Colors.transparent, BlendMode.color]), - // The #restore call is never evaluated - ], - ); - }); - }); -} diff --git a/packages/flutter/test/rendering/mouse_tracker_cursor_test.dart b/packages/flutter/test/rendering/mouse_tracker_cursor_test.dart index 58fe781d0cf4a..b74224eba17e8 100644 --- a/packages/flutter/test/rendering/mouse_tracker_cursor_test.dart +++ b/packages/flutter/test/rendering/mouse_tracker_cursor_test.dart @@ -57,10 +57,8 @@ void main() { setUp(() { _binding.postFrameCallbacks.clear(); _binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, (MethodCall call) async { - if (_methodCallHandler != null) { + if (_methodCallHandler != null) return _methodCallHandler!(call); - } - return null; }); }); diff --git a/packages/flutter/test/rendering/object_test.dart b/packages/flutter/test/rendering/object_test.dart index 90313a21d0db0..59fe13cfd195c 100644 --- a/packages/flutter/test/rendering/object_test.dart +++ b/packages/flutter/test/rendering/object_test.dart @@ -153,76 +153,6 @@ void main() { expect(renderObject.toStringShort(), contains('DISPOSED')); }); - test('Leader layer can switch to a different render object within one frame', () { - List? caughtErrors; - renderer.onErrors = () { - caughtErrors = renderer.takeAllFlutterErrorDetails().toList(); - }; - - final LayerLink layerLink = LayerLink(); - // renderObject1 paints the leader layer first. - final LeaderLayerRenderObject renderObject1 = LeaderLayerRenderObject(); - renderObject1.layerLink = layerLink; - renderObject1.attach(renderer.pipelineOwner); - final OffsetLayer rootLayer1 = OffsetLayer(); - rootLayer1.attach(renderObject1); - renderObject1.scheduleInitialPaint(rootLayer1); - renderObject1.layout(const BoxConstraints.tightForFinite()); - - final LeaderLayerRenderObject renderObject2 = LeaderLayerRenderObject(); - final OffsetLayer rootLayer2 = OffsetLayer(); - rootLayer2.attach(renderObject2); - renderObject2.attach(renderer.pipelineOwner); - renderObject2.scheduleInitialPaint(rootLayer2); - renderObject2.layout(const BoxConstraints.tightForFinite()); - renderer.pumpCompleteFrame(); - - // Swap the layer link to renderObject2 in the same frame - renderObject1.layerLink = null; - renderObject1.markNeedsPaint(); - renderObject2.layerLink = layerLink; - renderObject2.markNeedsPaint(); - renderer.pumpCompleteFrame(); - - // Swap the layer link to renderObject1 in the same frame - renderObject1.layerLink = layerLink; - renderObject1.markNeedsPaint(); - renderObject2.layerLink = null; - renderObject2.markNeedsPaint(); - renderer.pumpCompleteFrame(); - - renderer.onErrors = null; - expect(caughtErrors, isNull); - }); - - test('Leader layer append to two render objects does crash', () { - List? caughtErrors; - renderer.onErrors = () { - caughtErrors = renderer.takeAllFlutterErrorDetails().toList(); - }; - final LayerLink layerLink = LayerLink(); - // renderObject1 paints the leader layer first. - final LeaderLayerRenderObject renderObject1 = LeaderLayerRenderObject(); - renderObject1.layerLink = layerLink; - renderObject1.attach(renderer.pipelineOwner); - final OffsetLayer rootLayer1 = OffsetLayer(); - rootLayer1.attach(renderObject1); - renderObject1.scheduleInitialPaint(rootLayer1); - renderObject1.layout(const BoxConstraints.tightForFinite()); - - final LeaderLayerRenderObject renderObject2 = LeaderLayerRenderObject(); - renderObject2.layerLink = layerLink; - final OffsetLayer rootLayer2 = OffsetLayer(); - rootLayer2.attach(renderObject2); - renderObject2.attach(renderer.pipelineOwner); - renderObject2.scheduleInitialPaint(rootLayer2); - renderObject2.layout(const BoxConstraints.tightForFinite()); - renderer.pumpCompleteFrame(); - - renderer.onErrors = null; - expect(caughtErrors!.isNotEmpty, isTrue); - }); - test('RenderObject.dispose null the layer on repaint boundaries', () { final TestRenderObject renderObject = TestRenderObject(allowPaintBounds: true); // Force a layer to get set. @@ -325,39 +255,6 @@ class TestRenderObject extends RenderObject { } } -class LeaderLayerRenderObject extends RenderObject { - LeaderLayerRenderObject(); - - LayerLink? layerLink; - - @override - bool isRepaintBoundary = true; - - @override - void debugAssertDoesMeetConstraints() { } - - @override - Rect get paintBounds { - return Rect.zero; - } - - @override - void paint(PaintingContext context, Offset offset) { - if (layerLink != null) { - context.pushLayer(LeaderLayer(link: layerLink!), super.paint, offset); - } - } - - @override - void performLayout() { } - - @override - void performResize() { } - - @override - Rect get semanticBounds => const Rect.fromLTWH(0.0, 0.0, 10.0, 20.0); -} - class TestThrowingRenderObject extends RenderObject { @override void performLayout() { diff --git a/packages/flutter/test/rendering/recording_canvas.dart b/packages/flutter/test/rendering/recording_canvas.dart index d719273a2aa47..22974a40c4dd7 100644 --- a/packages/flutter/test/rendering/recording_canvas.dart +++ b/packages/flutter/test/rendering/recording_canvas.dart @@ -186,9 +186,10 @@ class TestRecordingPaintingContext extends ClipContext implements PaintingContex } class _MethodCall implements Invocation { - _MethodCall(this._name, [ this._arguments = const []]); + _MethodCall(this._name, [ this._arguments = const [], this._typeArguments = const []]); final Symbol _name; final List _arguments; + final List _typeArguments; @override bool get isAccessor => false; @override @@ -204,7 +205,7 @@ class _MethodCall implements Invocation { @override List get positionalArguments => _arguments; @override - List get typeArguments => const []; + List get typeArguments => _typeArguments; } String _valueName(Object? value) { diff --git a/packages/flutter/test/rendering/rendering_tester.dart b/packages/flutter/test/rendering/rendering_tester.dart index 3b5523ec17294..818daeb8c218c 100644 --- a/packages/flutter/test/rendering/rendering_tester.dart +++ b/packages/flutter/test/rendering/rendering_tester.dart @@ -82,35 +82,6 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser EnginePhase phase = EnginePhase.composite; - /// Pumps a frame and runs its entire life cycle. - /// - /// This method runs all of the [SchedulerPhase]s in a frame, this is useful - /// to test [SchedulerPhase.postFrameCallbacks]. - void pumpCompleteFrame() { - final FlutterExceptionHandler? oldErrorHandler = FlutterError.onError; - FlutterError.onError = (FlutterErrorDetails details) { - _errors.add(details); - }; - try { - renderer.handleBeginFrame(null); - renderer.handleDrawFrame(); - } finally { - FlutterError.onError = oldErrorHandler; - if (_errors.isNotEmpty) { - if (onErrors != null) { - onErrors!(); - if (_errors.isNotEmpty) { - _errors.forEach(FlutterError.dumpErrorToConsole); - fail('There are more errors than the test inspected using TestRenderingFlutterBinding.takeFlutterErrorDetails.'); - } - } else { - _errors.forEach(FlutterError.dumpErrorToConsole); - fail('Caught error while rendering frame. See preceding logs for details.'); - } - } - } - } - @override void drawFrame() { assert(phase != EnginePhase.build, 'rendering_tester does not support testing the build phase; use flutter_test instead'); @@ -153,7 +124,7 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser } } -final TestRenderingFlutterBinding _renderer = TestRenderingFlutterBinding(); +late final TestRenderingFlutterBinding _renderer = TestRenderingFlutterBinding(); TestRenderingFlutterBinding get renderer => _renderer; @@ -334,7 +305,6 @@ class TestClipPaintingContext extends PaintingContext { ClipRectLayer? oldLayer, }) { this.clipBehavior = clipBehavior; - return null; } Clip clipBehavior = Clip.none; diff --git a/packages/flutter/test/rendering/sliver_fixed_extent_layout_test.dart b/packages/flutter/test/rendering/sliver_fixed_extent_layout_test.dart index b110ac67b0f5e..3863b46b6397a 100644 --- a/packages/flutter/test/rendering/sliver_fixed_extent_layout_test.dart +++ b/packages/flutter/test/rendering/sliver_fixed_extent_layout_test.dart @@ -45,8 +45,8 @@ void main() { // Regression test for https://github.com/flutter/flutter/issues/68182 const double genericItemExtent = 600.0; - const double extraValueToNotHaveRoundingIssues = 1e-10; - const double extraValueToHaveRoundingIssues = 1e-11; + const double extraValueToNotHaveRoundingIssues = 0.0000001; // 6 zeros + const double extraValueToHaveRoundingIssues = 0.00000001; // 7 zeros test('should be 0 when item extent is 0', () { const double offsetValueWhichDoesntCare = 1234; @@ -91,7 +91,7 @@ void main() { expect(actual, 5); }); - test('should be 5 when offset is 6 times greater than a specific item extent where the division will return more than 13 zero decimals', () { + test('should be 5 when offset is 6 times greater than a specific item extent where the division will return more than 13 zero decimals', () { const double itemExtentSpecificForAProblematicScreenSize = 411.42857142857144; final int actual = testGetMaxChildIndexForScrollOffset( itemExtentSpecificForAProblematicScreenSize * 6 + extraValueToHaveRoundingIssues, @@ -100,7 +100,7 @@ void main() { expect(actual, 5); }); - test('should be 0 when offset is a bit greater than item extent', () { + test('should be 0 when offset is 0.00000001 times greater than item extent where the division will return more than 13 zero decimals', () { final int actual = testGetMaxChildIndexForScrollOffset( genericItemExtent + extraValueToHaveRoundingIssues, genericItemExtent, diff --git a/packages/flutter/test/rendering/viewport_test.dart b/packages/flutter/test/rendering/viewport_test.dart index 2cb80c45e0b96..d4cff3b7ca9e6 100644 --- a/packages/flutter/test/rendering/viewport_test.dart +++ b/packages/flutter/test/rendering/viewport_test.dart @@ -21,11 +21,13 @@ class _TestSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate this.key, required this.minExtent, required this.maxExtent, + this.child, this.vsync = const TestVSync(), this.showOnScreenConfiguration = const PersistentHeaderShowOnScreenConfiguration(), }); final Key? key; + final Widget? child; @override final double maxExtent; @@ -40,7 +42,7 @@ class _TestSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate final PersistentHeaderShowOnScreenConfiguration showOnScreenConfiguration; @override - Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => SizedBox.expand(key: key); + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => child ?? SizedBox.expand(key: key); @override bool shouldRebuild(_TestSliverPersistentHeaderDelegate oldDelegate) => true; diff --git a/packages/flutter/test/services/default_binary_messenger_test.dart b/packages/flutter/test/services/default_binary_messenger_test.dart index aeedf29ffc998..6576ffc2217db 100644 --- a/packages/flutter/test/services/default_binary_messenger_test.dart +++ b/packages/flutter/test/services/default_binary_messenger_test.dart @@ -41,7 +41,6 @@ void main() { (ByteData? message) async { expect(message, bar); countInbound += 1; - return null; }, ); expect(countInbound, equals(0)); diff --git a/packages/flutter/test/services/deferred_component_test.dart b/packages/flutter/test/services/deferred_component_test.dart index 275843dee4a19..6665f28467be7 100644 --- a/packages/flutter/test/services/deferred_component_test.dart +++ b/packages/flutter/test/services/deferred_component_test.dart @@ -13,7 +13,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.deferredComponent, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await DeferredComponent.installDeferredComponent(componentName: 'testComponentName'); @@ -30,7 +29,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.deferredComponent, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await DeferredComponent.uninstallDeferredComponent(componentName: 'testComponentName'); diff --git a/packages/flutter/test/services/haptic_feedback_test.dart b/packages/flutter/test/services/haptic_feedback_test.dart index e6169b085c17a..43a158f2ec3a6 100644 --- a/packages/flutter/test/services/haptic_feedback_test.dart +++ b/packages/flutter/test/services/haptic_feedback_test.dart @@ -13,7 +13,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await HapticFeedback.vibrate(); @@ -28,7 +27,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await hapticFunction(); diff --git a/packages/flutter/test/services/raw_keyboard_test.dart b/packages/flutter/test/services/raw_keyboard_test.dart index 03a00f083f372..6e2ce81a3574e 100644 --- a/packages/flutter/test/services/raw_keyboard_test.dart +++ b/packages/flutter/test/services/raw_keyboard_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. -import 'dart:ui' as ui; - import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -350,55 +348,6 @@ void main() { ); }, skip: isBrowser); // [intended] This is a GLFW-specific test. - - // Regression test for https://github.com/flutter/flutter/issues/93278 . - // - // GTK has some weird behavior where the tested key event sequence will - // result in a AltRight down event without Alt bitmask. - testWidgets('keysPressed modifiers are synchronized with key events on Linux GTK (down events)', (WidgetTester tester) async { - expect(RawKeyboard.instance.keysPressed, isEmpty); - Future simulate(bool keyDown, int scancode, int keycode, int modifiers) async { - final Map data = { - 'type': keyDown ? 'keydown' : 'keyup', - 'keymap': 'linux', - 'toolkit': 'gtk', - 'scanCode': scancode, - 'keyCode': keycode, - 'modifiers': modifiers, - }; - // Dispatch an empty key data to disable HardwareKeyboard sanity check, - // since we're only testing if the raw keyboard can handle the message. - // In real application the embedder responder will send correct key data - // (which is tested in the engine.) - TestDefaultBinaryMessengerBinding.instance!.keyEventManager.handleKeyData(const ui.KeyData( - type: ui.KeyEventType.down, - timeStamp: Duration.zero, - logical: 0, - physical: 0, - character: null, - synthesized: false, - )); - await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage( - SystemChannels.keyEvent.name, - SystemChannels.keyEvent.codec.encodeMessage(data), - (ByteData? data) {}, - ); - } - - await simulate(true, 0x6c/*AltRight*/, 0xffea/*AltRight*/, 0x2000000); - await simulate(true, 0x32/*ShiftLeft*/, 0xfe08/*NextGroup*/, 0x2000008/*MOD3*/); - await simulate(false, 0x6c/*AltRight*/, 0xfe03/*AltRight*/, 0x2002008/*MOD3|Reserve14*/); - await simulate(true, 0x6c/*AltRight*/, 0xfe03/*AltRight*/, 0x2002000/*Reserve14*/); - expect( - RawKeyboard.instance.keysPressed, - equals( - { - LogicalKeyboardKey.altRight, - }, - ), - ); - }, skip: isBrowser); // [intended] This is a GTK-specific test. - testWidgets('keysPressed modifiers are synchronized with key events on web', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. Change the modifiers so @@ -598,49 +547,6 @@ void main() { ); }, skip: isBrowser); // [intended] This is an iOS-specific test. - testWidgets('repeat events', (WidgetTester tester) async { - expect(RawKeyboard.instance.keysPressed, isEmpty); - late RawKeyEvent receivedEvent; - RawKeyboard.instance.keyEventHandler = (RawKeyEvent event) { - receivedEvent = event; - return true; - }; - - // Dispatch a down event. - final Map downData = KeyEventSimulator.getKeyData( - LogicalKeyboardKey.keyA, - platform: 'windows', - ); - await ServicesBinding.instance?.defaultBinaryMessenger.handlePlatformMessage( - SystemChannels.keyEvent.name, - SystemChannels.keyEvent.codec.encodeMessage(downData), - (ByteData? data) {}, - ); - expect(receivedEvent.repeat, false); - - // Dispatch another down event, which should be recognized as a repeat. - await ServicesBinding.instance?.defaultBinaryMessenger.handlePlatformMessage( - SystemChannels.keyEvent.name, - SystemChannels.keyEvent.codec.encodeMessage(downData), - (ByteData? data) {}, - ); - expect(receivedEvent.repeat, true); - - // Dispatch an up event. - await ServicesBinding.instance?.defaultBinaryMessenger.handlePlatformMessage( - SystemChannels.keyEvent.name, - SystemChannels.keyEvent.codec.encodeMessage(KeyEventSimulator.getKeyData( - LogicalKeyboardKey.keyA, - isDown: false, - platform: 'windows', - )), - (ByteData? data) {}, - ); - expect(receivedEvent.repeat, false); - - RawKeyboard.instance.keyEventHandler = null; - }, skip: isBrowser); // [intended] This is a Windows-specific test. - testWidgets('sided modifiers without a side set return all sides on Windows', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. @@ -1129,15 +1035,15 @@ void main() { LogicalKeyboardKey.keyA, platform: 'android', ); - Map? message; + Map? message; await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage( SystemChannels.keyEvent.name, SystemChannels.keyEvent.codec.encodeMessage(data), (ByteData? data) { - message = SystemChannels.keyEvent.codec.decodeMessage(data) as Map?; + message = SystemChannels.keyEvent.codec.decodeMessage(data) as Map; }, ); - expect(message, equals({ 'handled': false })); + expect(message, equals({ 'handled': false })); message = null; // Set up a widget that will receive focused text events. @@ -1158,15 +1064,15 @@ void main() { SystemChannels.keyEvent.name, SystemChannels.keyEvent.codec.encodeMessage(data), (ByteData? data) { - message = SystemChannels.keyEvent.codec.decodeMessage(data) as Map?; + message = SystemChannels.keyEvent.codec.decodeMessage(data) as Map; }, ); - expect(message, equals({ 'handled': true })); + expect(message, equals({ 'handled': true })); tester.binding.defaultBinaryMessenger.setMockMessageHandler(SystemChannels.keyEvent.name, null); }); test('data.toString', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'android', 'keyCode': 29, @@ -1184,7 +1090,7 @@ void main() { }); test('data.equality', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'android', 'keyCode': 29, @@ -1458,13 +1364,14 @@ void main() { } }); - test('Lower letter keys are correctly translated', () { + test('Printable keyboard keys are correctly translated', () { + const String unmodifiedCharacter = 'a'; final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'macos', 'keyCode': 0x00000000, 'characters': 'a', - 'charactersIgnoringModifiers': 'a', + 'charactersIgnoringModifiers': unmodifiedCharacter, 'modifiers': 0x0, }); final RawKeyEventDataMacOs data = keyAEvent.data as RawKeyEventDataMacOs; @@ -1473,21 +1380,6 @@ void main() { expect(data.keyLabel, equals('a')); }); - test('Upper letter keys are correctly translated', () { - final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { - 'type': 'keydown', - 'keymap': 'macos', - 'keyCode': 0x00000000, - 'characters': 'A', - 'charactersIgnoringModifiers': 'A', - 'modifiers': 0x20002, - }); - final RawKeyEventDataMacOs data = keyAEvent.data as RawKeyEventDataMacOs; - expect(data.physicalKey, equals(PhysicalKeyboardKey.keyA)); - expect(data.logicalKey, equals(LogicalKeyboardKey.keyA)); - expect(data.keyLabel, equals('A')); - }); - test('Control keyboard keys are correctly translated', () { final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', @@ -1532,20 +1424,6 @@ void main() { expect(data.logicalKey, equals(LogicalKeyboardKey.arrowLeft)); }); - test('Multi-char keyboard keys are correctly translated', () { - final RawKeyEvent leftArrowKey = RawKeyEvent.fromMessage(const { - 'type': 'keydown', - 'keymap': 'macos', - 'keyCode': 0x00000000, - 'characters': 'án', - 'charactersIgnoringModifiers': 'án', - 'modifiers': 0, - }); - final RawKeyEventDataMacOs data = leftArrowKey.data as RawKeyEventDataMacOs; - expect(data.physicalKey, equals(PhysicalKeyboardKey.keyA)); - expect(data.logicalKey, equals(const LogicalKeyboardKey(0x1400000000))); - }); - test('data.toString', () { expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', @@ -1904,7 +1782,7 @@ void main() { }); test('Unprintable keyboard keys are correctly translated', () { - final RawKeyEvent leftArrowKey = RawKeyEvent.fromMessage(const { + final RawKeyEvent leftArrowKey = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'windows', 'keyCode': 37, // keyCode for left arrow. @@ -1925,7 +1803,7 @@ void main() { Future simulateKeyEventMessage(String type, int keyCode, int scanCode) { return ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage( SystemChannels.keyEvent.name, - SystemChannels.keyEvent.codec.encodeMessage({ + SystemChannels.keyEvent.codec.encodeMessage({ 'type': type, 'keymap': platform, 'keyCode': keyCode, @@ -1933,8 +1811,8 @@ void main() { 'modifiers': 0, }), (ByteData? data) { - final Map decoded = SystemChannels.keyEvent.codec.decodeMessage(data)! as Map; - lastHandled = decoded['handled']! as bool; + final Map decoded = SystemChannels.keyEvent.codec.decodeMessage(data) as Map; + lastHandled = decoded['handled'] as bool; }, ); } @@ -1950,7 +1828,7 @@ void main() { }); test('data.toString', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'windows', 'keyCode': 0x00000010, @@ -1962,7 +1840,7 @@ void main() { }); test('data.equality', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'windows', 'keyCode': 0x00000010, @@ -1976,7 +1854,7 @@ void main() { characterCodePoint: 10, )); - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'windows', 'keyCode': 0x00000010, @@ -2021,7 +1899,7 @@ void main() { for (final int modifier in modifierTests.keys) { for (final bool isDown in [true, false]) { for (final bool isLeft in [true, false]) { - final RawKeyEvent event = RawKeyEvent.fromMessage({ + final RawKeyEvent event = RawKeyEvent.fromMessage({ 'type': isDown ? 'keydown' : 'keyup', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2059,7 +1937,7 @@ void main() { // No need to combine CTRL key with itself. continue; } - final RawKeyEvent event = RawKeyEvent.fromMessage({ + final RawKeyEvent event = RawKeyEvent.fromMessage({ 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2095,7 +1973,7 @@ void main() { }); test('Printable keyboard keys are correctly translated', () { - final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2111,7 +1989,7 @@ void main() { }); test('Code points with two Unicode scalar values are allowed', () { - final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2129,7 +2007,7 @@ void main() { test('Code points with more than three Unicode scalar values are not allowed', () { // |keyCode| and |scanCode| are arbitrary values. This test should fail due to an invalid |unicodeScalarValues|. void _createFailingKey() { - RawKeyEvent.fromMessage(const { + RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2144,7 +2022,7 @@ void main() { }); test('Control keyboard keys are correctly translated', () { - final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2160,7 +2038,7 @@ void main() { }); test('Modifier keyboard keys are correctly translated', () { - final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2175,7 +2053,7 @@ void main() { }); test('data.toString', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2188,7 +2066,7 @@ void main() { }); test('data.equality', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2205,7 +2083,7 @@ void main() { isDown: true, )); - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'glfw', @@ -2253,7 +2131,7 @@ void main() { for (final int modifier in modifierTests.keys) { for (final bool isDown in [true, false]) { for (final bool isLeft in [true, false]) { - final RawKeyEvent event = RawKeyEvent.fromMessage({ + final RawKeyEvent event = RawKeyEvent.fromMessage({ 'type': isDown ? 'keydown' : 'keyup', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2291,7 +2169,7 @@ void main() { // No need to combine CTRL key with itself. continue; } - final RawKeyEvent event = RawKeyEvent.fromMessage({ + final RawKeyEvent event = RawKeyEvent.fromMessage({ 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2327,7 +2205,7 @@ void main() { }); test('Printable keyboard keys are correctly translated', () { - final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2343,7 +2221,7 @@ void main() { }); test('Code points with two Unicode scalar values are allowed', () { - final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2361,7 +2239,7 @@ void main() { test('Code points with more than three Unicode scalar values are not allowed', () { // |keyCode| and |scanCode| are arbitrary values. This test should fail due to an invalid |unicodeScalarValues|. void _createFailingKey() { - RawKeyEvent.fromMessage(const { + RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2376,7 +2254,7 @@ void main() { }); test('Control keyboard keys are correctly translated', () { - final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2392,7 +2270,7 @@ void main() { }); test('Modifier keyboard keys are correctly translated', () { - final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2407,7 +2285,7 @@ void main() { }); test('data.toString', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2420,7 +2298,7 @@ void main() { }); test('data.equality', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2437,7 +2315,7 @@ void main() { isDown: true, )); - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2454,7 +2332,7 @@ void main() { isDown: true, )))); - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'linux', 'toolkit': 'gtk', @@ -2481,7 +2359,7 @@ void main() { test('modifier keys are recognized individually', () { for (final int modifier in modifierTests.keys) { - final RawKeyEvent event = RawKeyEvent.fromMessage({ + final RawKeyEvent event = RawKeyEvent.fromMessage({ 'type': 'keydown', 'keymap': 'web', 'code': 'RandomCode', @@ -2512,7 +2390,7 @@ void main() { // No need to combine meta key with itself. continue; } - final RawKeyEvent event = RawKeyEvent.fromMessage({ + final RawKeyEvent event = RawKeyEvent.fromMessage({ 'type': 'keydown', 'keymap': 'web', 'code': 'RandomCode', @@ -2539,93 +2417,68 @@ void main() { } }); - test('Lower letter keys are correctly translated', () { - final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { + test('Printable keyboard keys are correctly translated', () { + final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'web', 'code': 'KeyA', 'key': 'a', 'location': 0, 'metaState': 0x0, - 'keyCode': 0x41, }); final RawKeyEventDataWeb data = keyAEvent.data as RawKeyEventDataWeb; expect(data.physicalKey, equals(PhysicalKeyboardKey.keyA)); expect(data.logicalKey, equals(LogicalKeyboardKey.keyA)); expect(data.keyLabel, equals('a')); - expect(data.keyCode, equals(0x41)); - }); - - test('Upper letter keys are correctly translated', () { - final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const { - 'type': 'keydown', - 'keymap': 'web', - 'code': 'KeyA', - 'key': 'A', - 'location': 0, - 'metaState': 0x1, // Shift - 'keyCode': 0x41, - }); - final RawKeyEventDataWeb data = keyAEvent.data as RawKeyEventDataWeb; - expect(data.physicalKey, equals(PhysicalKeyboardKey.keyA)); - expect(data.logicalKey, equals(LogicalKeyboardKey.keyA)); - expect(data.keyLabel, equals('A')); - expect(data.keyCode, equals(0x41)); }); test('Control keyboard keys are correctly translated', () { - final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'web', 'code': 'Escape', 'key': 'Escape', 'location': 0, 'metaState': 0x0, - 'keyCode': 0x1B, }); final RawKeyEventDataWeb data = escapeKeyEvent.data as RawKeyEventDataWeb; expect(data.physicalKey, equals(PhysicalKeyboardKey.escape)); expect(data.logicalKey, equals(LogicalKeyboardKey.escape)); expect(data.keyLabel, isEmpty); - expect(data.keyCode, equals(0x1B)); }); test('Modifier keyboard keys are correctly translated', () { - final RawKeyEvent shiftKeyEvent = RawKeyEvent.fromMessage(const { + final RawKeyEvent shiftKeyEvent = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'web', 'code': 'ShiftLeft', 'key': 'Shift', 'location': 1, 'metaState': RawKeyEventDataWeb.modifierShift, - 'keyCode': 0x10, }); final RawKeyEventDataWeb data = shiftKeyEvent.data as RawKeyEventDataWeb; expect(data.physicalKey, equals(PhysicalKeyboardKey.shiftLeft)); expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft)); expect(data.keyLabel, isEmpty); - expect(data.keyCode, equals(0x10)); }); test('Arrow keys from a keyboard give correct physical key mappings', () { - final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const { + final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'web', 'code': 'ArrowDown', 'key': 'ArrowDown', 'location': 0, 'metaState': 0x0, - 'keyCode': 0x28, }); final RawKeyEventDataWeb data = arrowKeyDown.data as RawKeyEventDataWeb; expect(data.physicalKey, equals(PhysicalKeyboardKey.arrowDown)); expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown)); expect(data.keyLabel, isEmpty); - expect(data.keyCode, equals(0x28)); }); test('Unrecognized keys are mapped to Web plane', () { - final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const { + final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'web', 'code': 'Unrecog1', @@ -2641,58 +2494,52 @@ void main() { expect(data.logicalKey.keyId, greaterThan(0x01700000000)); expect(data.logicalKey.keyId, lessThan(0x01800000000)); expect(data.keyLabel, isEmpty); - expect(data.keyCode, equals(0)); }); test('data.toString', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'web', 'code': 'KeyA', 'key': 'a', 'location': 2, 'metaState': 0x10, - 'keyCode': 0x41, }).data.toString(), equalsIgnoringHashCodes( - 'RawKeyEventDataWeb#00000(code: KeyA, key: a, location: 2, metaState: 16, keyCode: 65)')); + 'RawKeyEventDataWeb#00000(code: KeyA, key: a, location: 2, metaState: 16)')); // Without location - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'web', 'code': 'KeyA', 'key': 'a', 'metaState': 0x10, - 'keyCode': 0x41, }).data.toString(), equalsIgnoringHashCodes( - 'RawKeyEventDataWeb#00000(code: KeyA, key: a, location: 0, metaState: 16, keyCode: 65)')); + 'RawKeyEventDataWeb#00000(code: KeyA, key: a, location: 0, metaState: 16)')); }); test('data.equality', () { - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'web', 'code': 'KeyA', 'key': 'a', 'location': 2, 'metaState': 0x10, - 'keyCode': 0x41, }).data, const RawKeyEventDataWeb( key: 'a', code: 'KeyA', location: 2, metaState: 0x10, - keyCode: 0x41 )); - expect(RawKeyEvent.fromMessage(const { + expect(RawKeyEvent.fromMessage(const { 'type': 'keydown', 'keymap': 'web', 'code': 'KeyA', 'key': 'a', 'location': 2, 'metaState': 0x10, - 'keyCode': 0x41, }).data, isNot(equals(const RawKeyEventDataWeb(code: 'KeyA', key: 'a')))); }); }); @@ -2712,6 +2559,6 @@ Future _runWhileOverridingOnError(AsyncCallback body, {required FlutterExc Map _groupDiagnosticsByName(Iterable infos) { return Map.fromIterable( infos, - key: (Object? node) => (node! as DiagnosticsNode).name ?? '', + key: (dynamic node) => (node as DiagnosticsNode).name ?? '', ); } diff --git a/packages/flutter/test/services/restoration_test.dart b/packages/flutter/test/services/restoration_test.dart index 014efefdd6ed5..cc132308c3ac6 100644 --- a/packages/flutter/test/services/restoration_test.dart +++ b/packages/flutter/test/services/restoration_test.dart @@ -66,7 +66,6 @@ void main() { final List callsToEngine = []; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) async { callsToEngine.add(call); - return null; }); final RestorationManager manager = RestorationManager(); diff --git a/packages/flutter/test/services/system_chrome_test.dart b/packages/flutter/test/services/system_chrome_test.dart index b39fa929a1806..8b442153a3591 100644 --- a/packages/flutter/test/services/system_chrome_test.dart +++ b/packages/flutter/test/services/system_chrome_test.dart @@ -14,7 +14,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); // The first call is a cache miss and will queue a microtask @@ -72,7 +71,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await SystemChrome.setPreferredOrientations([ @@ -91,7 +89,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await SystemChrome.setApplicationSwitcherDescription( @@ -110,7 +107,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/platform', (ByteData? message) async { log.add(message); - return null; }); await SystemChrome.setApplicationSwitcherDescription( @@ -125,7 +121,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.top]); @@ -142,7 +137,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await SystemChrome.setEnabledSystemUIMode(SystemUiMode.leanBack); @@ -171,7 +165,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); @@ -188,7 +181,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await SystemChrome.setSystemUIChangeCallback(null); diff --git a/packages/flutter/test/services/system_navigator_test.dart b/packages/flutter/test/services/system_navigator_test.dart index 3b2a566bb302e..47bb60e88ea2b 100644 --- a/packages/flutter/test/services/system_navigator_test.dart +++ b/packages/flutter/test/services/system_navigator_test.dart @@ -20,7 +20,6 @@ void main() { test('System navigator control test - platform messages', () async { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await verify(() => SystemNavigator.pop(), [ @@ -33,7 +32,6 @@ void main() { test('System navigator control test - navigation messages', () async { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await verify(() => SystemNavigator.selectSingleEntryHistory(), [ diff --git a/packages/flutter/test/services/system_sound_test.dart b/packages/flutter/test/services/system_sound_test.dart index 04d2a97d021e6..823d7f083a8e9 100644 --- a/packages/flutter/test/services/system_sound_test.dart +++ b/packages/flutter/test/services/system_sound_test.dart @@ -14,7 +14,6 @@ void main() { TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await SystemSound.play(SystemSoundType.click); diff --git a/packages/flutter/test/services/text_input_test.dart b/packages/flutter/test/services/text_input_test.dart index 9b6e1414c70ee..fc6161e5cd8b0 100644 --- a/packages/flutter/test/services/text_input_test.dart +++ b/packages/flutter/test/services/text_input_test.dart @@ -43,110 +43,6 @@ void main() { }); }); - group('TextEditingValue', () { - group('replaced', () { - const String testText = 'From a false proposition, anything follows.'; - - test('selection deletion', () { - const TextSelection selection = TextSelection(baseOffset: 5, extentOffset: 13); - expect( - const TextEditingValue(text: testText, selection: selection).replaced(selection, ''), - const TextEditingValue(text: 'From proposition, anything follows.', selection: TextSelection.collapsed(offset: 5)), - ); - }); - - test('reversed selection deletion', () { - const TextSelection selection = TextSelection(baseOffset: 13, extentOffset: 5); - expect( - const TextEditingValue(text: testText, selection: selection).replaced(selection, ''), - const TextEditingValue(text: 'From proposition, anything follows.', selection: TextSelection.collapsed(offset: 5)), - ); - }); - - test('insert', () { - const TextSelection selection = TextSelection.collapsed(offset: 5); - expect( - const TextEditingValue(text: testText, selection: selection).replaced(selection, 'AA'), - const TextEditingValue( - text: 'From AAa false proposition, anything follows.', - // The caret moves to the end of the text inserted. - selection: TextSelection.collapsed(offset: 7), - ), - ); - }); - - test('replace before selection', () { - const TextSelection selection = TextSelection(baseOffset: 13, extentOffset: 5); - expect( - // From |a false |proposition, anything follows. - // Replace the first whitespace with "AA". - const TextEditingValue(text: testText, selection: selection).replaced(const TextRange(start: 4, end: 5), 'AA'), - const TextEditingValue(text: 'FromAAa false proposition, anything follows.', selection: TextSelection(baseOffset: 14, extentOffset: 6)), - ); - }); - - test('replace after selection', () { - const TextSelection selection = TextSelection(baseOffset: 13, extentOffset: 5); - expect( - // From |a false |proposition, anything follows. - // replace the first "p" with "AA". - const TextEditingValue(text: testText, selection: selection).replaced(const TextRange(start: 13, end: 14), 'AA'), - const TextEditingValue(text: 'From a false AAroposition, anything follows.', selection: selection), - ); - }); - - test('replace inside selection - start boundary', () { - const TextSelection selection = TextSelection(baseOffset: 13, extentOffset: 5); - expect( - // From |a false |proposition, anything follows. - // replace the first "a" with "AA". - const TextEditingValue(text: testText, selection: selection).replaced(const TextRange(start: 5, end: 6), 'AA'), - const TextEditingValue(text: 'From AA false proposition, anything follows.', selection: TextSelection(baseOffset: 14, extentOffset: 5)), - ); - }); - - test('replace inside selection - end boundary', () { - const TextSelection selection = TextSelection(baseOffset: 13, extentOffset: 5); - expect( - // From |a false |proposition, anything follows. - // replace the second whitespace with "AA". - const TextEditingValue(text: testText, selection: selection).replaced(const TextRange(start: 12, end: 13), 'AA'), - const TextEditingValue(text: 'From a falseAAproposition, anything follows.', selection: TextSelection(baseOffset: 14, extentOffset: 5)), - ); - }); - - test('delete after selection', () { - const TextSelection selection = TextSelection(baseOffset: 13, extentOffset: 5); - expect( - // From |a false |proposition, anything follows. - // Delete the first "p". - const TextEditingValue(text: testText, selection: selection).replaced(const TextRange(start: 13, end: 14), ''), - const TextEditingValue(text: 'From a false roposition, anything follows.', selection: selection), - ); - }); - - test('delete inside selection - start boundary', () { - const TextSelection selection = TextSelection(baseOffset: 13, extentOffset: 5); - expect( - // From |a false |proposition, anything follows. - // Delete the first "a". - const TextEditingValue(text: testText, selection: selection).replaced(const TextRange(start: 5, end: 6), ''), - const TextEditingValue(text: 'From false proposition, anything follows.', selection: TextSelection(baseOffset: 12, extentOffset: 5)), - ); - }); - - test('delete inside selection - end boundary', () { - const TextSelection selection = TextSelection(baseOffset: 13, extentOffset: 5); - expect( - // From |a false |proposition, anything follows. - // Delete the second whitespace. - const TextEditingValue(text: testText, selection: selection).replaced(const TextRange(start: 12, end: 13), ''), - const TextEditingValue(text: 'From a falseproposition, anything follows.', selection: TextSelection(baseOffset: 12, extentOffset: 5)), - ); - }); - }); - }); - group('TextInput message channels', () { late FakeTextChannel fakeTextChannel; diff --git a/packages/flutter/test/services/use_platform_channel_without_initialization_test.dart b/packages/flutter/test/services/use_platform_channel_without_initialization_test.dart deleted file mode 100644 index c2049e87e4bc8..0000000000000 --- a/packages/flutter/test/services/use_platform_channel_without_initialization_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -// 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 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - // We need a separate test file for this test case (instead of including it - // in platform_channel_test.dart) since we rely on the WidgetsFlutterBinding - // not being initialized and we call ensureInitialized() in the other test - // file. - test('throws assertion error iff WidgetsFlutterBinding is not yet initialized', () { - const MethodChannel methodChannel = MethodChannel('mock'); - - // Ensure that accessing the binary messenger before initialization reports - // a helpful error message. - expect(() => methodChannel.binaryMessenger, throwsA(isA() - .having((AssertionError e) => e.message, 'message', contains('WidgetsFlutterBinding.ensureInitialized()')))); - - TestWidgetsFlutterBinding.ensureInitialized(); - expect(() => methodChannel.binaryMessenger, returnsNormally); - }); -} diff --git a/packages/flutter/test/widgets/actions_test.dart b/packages/flutter/test/widgets/actions_test.dart index 0a7879d62d9a1..d2c1f61da8df3 100644 --- a/packages/flutter/test/widgets/actions_test.dart +++ b/packages/flutter/test/widgets/actions_test.dart @@ -962,75 +962,6 @@ void main() { expect(buttonNode.hasFocus, isFalse); }, ); - - testWidgets( - 'FocusableActionDetector can prevent its descendants from being traversable', - (WidgetTester tester) async { - final FocusNode buttonNode1 = FocusNode(debugLabel: 'Button Node 1'); - final FocusNode buttonNode2 = FocusNode(debugLabel: 'Button Node 2'); - - await tester.pumpWidget( - MaterialApp( - home: FocusableActionDetector( - child: Column( - children: [ - MaterialButton( - focusNode: buttonNode1, - child: const Text('Node 1'), - onPressed: () {}, - ), - MaterialButton( - focusNode: buttonNode2, - child: const Text('Node 2'), - onPressed: () {}, - ), - ], - ), - ), - ), - ); - - buttonNode1.requestFocus(); - await tester.pump(); - expect(buttonNode1.hasFocus, isTrue); - expect(buttonNode2.hasFocus, isFalse); - primaryFocus!.nextFocus(); - await tester.pump(); - expect(buttonNode1.hasFocus, isFalse); - expect(buttonNode2.hasFocus, isTrue); - - await tester.pumpWidget( - MaterialApp( - home: FocusableActionDetector( - descendantsAreTraversable: false, - child: Column( - children: [ - MaterialButton( - focusNode: buttonNode1, - child: const Text('Node 1'), - onPressed: () {}, - ), - MaterialButton( - focusNode: buttonNode2, - child: const Text('Node 2'), - onPressed: () {}, - ), - ], - ), - ), - ), - ); - - buttonNode1.requestFocus(); - await tester.pump(); - expect(buttonNode1.hasFocus, isTrue); - expect(buttonNode2.hasFocus, isFalse); - primaryFocus!.nextFocus(); - await tester.pump(); - expect(buttonNode1.hasFocus, isTrue); - expect(buttonNode2.hasFocus, isFalse); - }, - ); }); group('Diagnostics', () { @@ -1770,8 +1701,9 @@ class TestContextAction extends ContextAction { List capturedContexts = []; @override - void invoke(covariant TestIntent intent, [BuildContext? context]) { + Object? invoke(covariant TestIntent intent, [BuildContext? context]) { capturedContexts.add(context); + return null; } } @@ -1792,7 +1724,7 @@ class LogInvocationAction extends Action { bool get isActionEnabled => enabled; @override - void invoke(LogIntent intent) { + Object? invoke(LogIntent intent) { final Action? callingAction = this.callingAction; if (callingAction == null) { intent.log.add('$actionName.invoke'); @@ -1823,7 +1755,7 @@ class LogInvocationContextAction extends ContextAction { bool get isActionEnabled => enabled; @override - void invoke(LogIntent intent, [BuildContext? context]) { + Object? invoke(LogIntent intent, [BuildContext? context]) { invokeContext = context; final Action? callingAction = this.callingAction; if (callingAction == null) { @@ -1860,5 +1792,5 @@ class RedirectOutputAction extends LogInvocationAction { final List newLog; @override - void invoke(LogIntent intent) => super.invoke(LogIntent(log: newLog)); + Object? invoke(LogIntent intent) => super.invoke(LogIntent(log: newLog)); } diff --git a/packages/flutter/test/widgets/app_test.dart b/packages/flutter/test/widgets/app_test.dart index d9a4469770bad..dd81d71a46184 100644 --- a/packages/flutter/test/widgets/app_test.dart +++ b/packages/flutter/test/widgets/app_test.dart @@ -461,30 +461,6 @@ void main() { ); }); - testWidgets("WidgetsApp reports an exception if the selected locale isn't supported", (WidgetTester tester) async { - late final List? localesArg; - late final Iterable supportedLocalesArg; - await tester.pumpWidget( - MaterialApp( // This uses a MaterialApp because it introduces some actual localizations. - localeListResolutionCallback: (List? locales, Iterable supportedLocales) { - localesArg = locales; - supportedLocalesArg = supportedLocales; - return const Locale('C_UTF-8'); - }, - builder: (BuildContext context, Widget? child) => const Placeholder(), - color: const Color(0xFF000000), - ), - ); - if (!kIsWeb) { - // On web, `flutter test` does not guarantee a particular locale, but - // when using `flutter_tester`, we guarantee that it's en-US, zh-CN. - // https://github.com/flutter/flutter/issues/93290 - expect(localesArg, const [Locale('en', 'US'), Locale('zh', 'CN')]); - } - expect(supportedLocalesArg, const [Locale('en', 'US')]); - expect(tester.takeException(), "Warning: This application's locale, C_UTF-8, is not supported by all of its localization delegates."); - }); - testWidgets('WidgetsApp creates a MediaQuery if `useInheritedMediaQuery` is set to false', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/app_title_test.dart b/packages/flutter/test/widgets/app_title_test.dart index 7cddafb6d56ea..0d59fdb6f5da1 100644 --- a/packages/flutter/test/widgets/app_title_test.dart +++ b/packages/flutter/test/widgets/app_title_test.dart @@ -8,7 +8,7 @@ import 'package:flutter_test/flutter_test.dart'; const Color kTitleColor = Color(0xFF333333); const String kTitleString = 'Hello World'; -Future pumpApp(WidgetTester tester, { GenerateAppTitle? onGenerateTitle, Color? color }) async { +Future pumpApp(WidgetTester tester, { GenerateAppTitle? onGenerateTitle }) async { await tester.pumpWidget( WidgetsApp( supportedLocales: const [ @@ -16,7 +16,7 @@ Future pumpApp(WidgetTester tester, { GenerateAppTitle? onGenerateTitle, C Locale('en', 'GB'), ], title: kTitleString, - color: color ?? kTitleColor, + color: kTitleColor, onGenerateTitle: onGenerateTitle, onGenerateRoute: (RouteSettings settings) { return PageRouteBuilder( @@ -36,15 +36,6 @@ void main() { expect(tester.widget(find.byType(Title)).color, kTitleColor); }); - testWidgets('Specified color is made opaque for Title', (WidgetTester tester) async { - // The Title widget can only handle fully opaque colors, the WidgetApp should - // ensure it only uses a fully opaque version of its color for the title. - const Color transparentBlue = Color(0xDD0000ff); - const Color opaqueBlue = Color(0xFF0000ff); - await pumpApp(tester, color: transparentBlue); - expect(tester.widget<Title>(find.byType(Title)).color, opaqueBlue); - }); - testWidgets('onGenerateTitle handles changing locales', (WidgetTester tester) async { String generateTitle(BuildContext context) { return Localizations.localeOf(context).toString(); diff --git a/packages/flutter/test/widgets/async_test.dart b/packages/flutter/test/widgets/async_test.dart index d9de5524d60ff..367a268f5fe09 100644 --- a/packages/flutter/test/widgets/async_test.dart +++ b/packages/flutter/test/widgets/async_test.dart @@ -12,20 +12,6 @@ void main() { return Text(snapshot.toString(), textDirection: TextDirection.ltr); } group('AsyncSnapshot', () { - test('requiring data preserves the stackTrace', () { - final StackTrace originalStackTrace = StackTrace.current; - - try { - AsyncSnapshot<String>.withError( - ConnectionState.done, - Error(), - originalStackTrace, - ).requireData; - fail('requireData did not throw'); - } catch (error, stackTrace) { - expect(stackTrace, originalStackTrace); - } - }); test('requiring data succeeds if data is present', () { expect( const AsyncSnapshot<String>.withData(ConnectionState.done, 'hello').requireData, diff --git a/packages/flutter/test/widgets/clipboard_utils.dart b/packages/flutter/test/widgets/clipboard_utils.dart index 1636148236c1c..b7a27d0791b3d 100644 --- a/packages/flutter/test/widgets/clipboard_utils.dart +++ b/packages/flutter/test/widgets/clipboard_utils.dart @@ -29,6 +29,5 @@ class MockClipboard { _clipboardData = methodCall.arguments; break; } - return null; } } diff --git a/packages/flutter/test/widgets/composited_transform_test.dart b/packages/flutter/test/widgets/composited_transform_test.dart index daaff69e8da04..4e18b415368f7 100644 --- a/packages/flutter/test/widgets/composited_transform_test.dart +++ b/packages/flutter/test/widgets/composited_transform_test.dart @@ -300,22 +300,4 @@ void main() { } } }); - - testWidgets('Leader after Follower asserts', (WidgetTester tester) async { - final LayerLink link = LayerLink(); - await tester.pumpWidget( - CompositedTransformFollower( - link: link, - child: CompositedTransformTarget( - link: link, - child: const SizedBox(height: 20, width: 20), - ), - ), - ); - - expect( - (tester.takeException() as AssertionError).message, - contains('LeaderLayer anchor must come before FollowerLayer in paint order'), - ); - }); } diff --git a/packages/flutter/test/widgets/custom_scroll_view_test.dart b/packages/flutter/test/widgets/custom_scroll_view_test.dart index 02c3281332338..9e1aa36d68e07 100644 --- a/packages/flutter/test/widgets/custom_scroll_view_test.dart +++ b/packages/flutter/test/widgets/custom_scroll_view_test.dart @@ -6,81 +6,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - // Regression test for https://github.com/flutter/flutter/issues/96024 - testWidgets('CustomScrollView.center update test 1', (WidgetTester tester) async { - final Key centerKey = UniqueKey(); - late StateSetter setState; - bool hasKey = false; - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: CustomScrollView( - center: centerKey, - slivers: <Widget>[ - const SliverToBoxAdapter(key: Key('a'), child: SizedBox(height: 100.0)), - StatefulBuilder( - key: centerKey, - builder: (BuildContext context, StateSetter setter) { - setState = setter; - if (hasKey) { - return const SliverToBoxAdapter( - key: Key('b'), - child: SizedBox(height: 100.0), - ); - } else { - return const SliverToBoxAdapter( - child: SizedBox(height: 100.0), - ); - } - }, - ), - ], - ), - )); - await tester.pumpAndSettle(); - - // Change the center key will trigger the old RenderObject remove and a new - // RenderObject insert. - setState(() { - hasKey = true; - }); - - await tester.pumpAndSettle(); - - // Pass without throw. - }); - - testWidgets('CustomScrollView.center update test 2', (WidgetTester tester) async { - const List<Widget> slivers1 = <Widget>[ - SliverToBoxAdapter(key: Key('a'), child: SizedBox(height: 100.0)), - SliverToBoxAdapter(key: Key('b'), child: SizedBox(height: 100.0)), - SliverToBoxAdapter(key: Key('c'), child: SizedBox(height: 100.0)), - ]; - - const List<Widget> slivers2 = <Widget>[ - SliverToBoxAdapter(key: Key('c'), child: SizedBox(height: 100.0)), - SliverToBoxAdapter(key: Key('d'), child: SizedBox(height: 100.0)), - SliverToBoxAdapter(key: Key('a'), child: SizedBox(height: 100.0)), - ]; - - Widget buildFrame(List<Widget> slivers, Key center) { - return Directionality( - textDirection: TextDirection.ltr, - child: CustomScrollView( - center: center, - slivers: slivers, - ), - ); - } - - await tester.pumpWidget(buildFrame(slivers1, const Key('b'))); - await tester.pumpAndSettle(); - - await tester.pumpWidget(buildFrame(slivers2, const Key('d'))); - await tester.pumpAndSettle(); - - // Pass without throw. - }); - testWidgets('CustomScrollView.center', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/default_text_editing_actions_test.dart b/packages/flutter/test/widgets/default_text_editing_actions_test.dart new file mode 100644 index 0000000000000..ff674e88cda14 --- /dev/null +++ b/packages/flutter/test/widgets/default_text_editing_actions_test.dart @@ -0,0 +1,118 @@ +// 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 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +class TestLeftIntent extends Intent { + const TestLeftIntent(); +} +class TestRightIntent extends Intent { + const TestRightIntent(); +} + +void main() { + testWidgets('DoNothingAndStopPropagationTextIntent', (WidgetTester tester) async { + bool leftCalled = false; + bool rightCalled = false; + final TextEditingController controller = TextEditingController( + text: 'blah1 blah2', + ); + final FocusNode focusNodeTarget = FocusNode(); + final FocusNode focusNodeNonTarget = FocusNode(); + + await tester.pumpWidget(MaterialApp( + theme: ThemeData(), + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return Shortcuts( + shortcuts: const <ShortcutActivator, Intent>{ + SingleActivator(LogicalKeyboardKey.arrowLeft): TestLeftIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): TestRightIntent(), + }, + child: Shortcuts( + shortcuts: const <ShortcutActivator, Intent>{ + SingleActivator(LogicalKeyboardKey.arrowRight): DoNothingAndStopPropagationTextIntent(), + }, + child: Actions( + // These Actions intercept default Intents, set a flag that they + // were called, and then call through to the default Action. + actions: <Type, Action<Intent>>{ + TestLeftIntent: CallbackAction<TestLeftIntent>(onInvoke: (Intent intent) { + leftCalled = true; + }), + TestRightIntent: CallbackAction<TestRightIntent>(onInvoke: (Intent intent) { + rightCalled = true; + }), + }, + child: Center( + child: Column( + children: <Widget>[ + EditableText( + controller: controller, + focusNode: focusNodeTarget, + style: Typography.material2018().black.subtitle1!, + cursorColor: Colors.blue, + backgroundCursorColor: Colors.grey, + ), + Focus( + focusNode: focusNodeNonTarget, + child: const Text('focusable'), + ), + ], + ), + ), + ), + ), + ); + }, + ), + ), + )); + + // Focus on the EditableText, which is a TextEditingActionTarget. + focusNodeTarget.requestFocus(); + await tester.pump(); + expect(focusNodeTarget.hasFocus, isTrue); + expect(focusNodeNonTarget.hasFocus, isFalse); + expect(controller.selection.isCollapsed, isTrue); + expect(controller.selection.baseOffset, 11); + + // The left arrow key's Action is called. + await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft); + await tester.pump(); + expect(leftCalled, isTrue); + expect(rightCalled, isFalse); + leftCalled = false; + + // The right arrow key is blocked by DoNothingAndStopPropagationTextIntent. + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pump(); + expect(rightCalled, isFalse); + expect(leftCalled, isFalse); + + // Focus on the other node, which is not a TextEditingActionTarget. + focusNodeNonTarget.requestFocus(); + await tester.pump(); + expect(focusNodeTarget.hasFocus, isFalse); + expect(focusNodeNonTarget.hasFocus, isTrue); + + // The left arrow key's Action is called as normal. + await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft); + await tester.pump(); + expect(leftCalled, isTrue); + expect(rightCalled, isFalse); + leftCalled = false; + + // The right arrow key's Action is also called. That's because + // DoNothingAndStopPropagationTextIntent only applies if a + // TextEditingActionTarget is currently focused. + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pump(); + expect(leftCalled, isFalse); + expect(rightCalled, isTrue); + }, variant: KeySimulatorTransitModeVariant.all()); +} diff --git a/packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart b/packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart index 20d304cadf0d5..ce9b0b38a5b8d 100644 --- a/packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart +++ b/packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart @@ -8,7 +8,6 @@ import 'package:flutter_test/flutter_test.dart'; void main() { Widget _boilerplate(VoidCallback? onButtonPressed, { - DraggableScrollableController? controller, int itemCount = 100, double initialChildSize = .5, double maxChildSize = 1.0, @@ -34,7 +33,6 @@ void main() { ), DraggableScrollableActuator( child: DraggableScrollableSheet( - controller: controller, maxChildSize: maxChildSize, minChildSize: minChildSize, initialChildSize: initialChildSize, @@ -348,42 +346,33 @@ void main() { )); }, variant: TargetPlatformVariant.all()); - for (final bool useActuator in <bool>[false, true]) { - testWidgets('Does not snap away from initial child on ${useActuator ? 'actuator' : 'controller'}.reset()', (WidgetTester tester) async { - const Key containerKey = ValueKey<String>('container'); - const Key stackKey = ValueKey<String>('stack'); - final DraggableScrollableController controller = DraggableScrollableController(); - await tester.pumpWidget(_boilerplate( - null, - controller: controller, - snap: true, - containerKey: containerKey, - stackKey: stackKey, - )); - await tester.pumpAndSettle(); - final double screenHeight = tester.getSize(find.byKey(stackKey)).height; + testWidgets('Does not snap away from initial child on reset', (WidgetTester tester) async { + const Key containerKey = ValueKey<String>('container'); + const Key stackKey = ValueKey<String>('stack'); + await tester.pumpWidget(_boilerplate(null, + snap: true, + containerKey: containerKey, + stackKey: stackKey, + )); + await tester.pumpAndSettle(); + final double screenHeight = tester.getSize(find.byKey(stackKey)).height; - await tester.drag(find.text('Item 1'), Offset(0, -.4 * screenHeight)); - await tester.pumpAndSettle(); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(1.0, precisionErrorTolerance), - ); + await tester.drag(find.text('Item 1'), Offset(0, -.4 * screenHeight)); + await tester.pumpAndSettle(); + expect( + tester.getSize(find.byKey(containerKey)).height / screenHeight, + closeTo(1.0, precisionErrorTolerance), + ); - if (useActuator) { - DraggableScrollableActuator.reset(tester.element(find.byKey(containerKey))); - } else { - controller.reset(); - } - await tester.pumpAndSettle(); + DraggableScrollableActuator.reset(tester.element(find.byKey(containerKey))); + await tester.pumpAndSettle(); - // The sheet should have reset without snapping away from initial child. - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.5, precisionErrorTolerance), - ); - }); - } + // The sheet should have reset without snapping away from initial child. + expect( + tester.getSize(find.byKey(containerKey)).height / screenHeight, + closeTo(.5, precisionErrorTolerance), + ); + }, variant: TargetPlatformVariant.all()); testWidgets('Zero velocity drag snaps to nearest snap target', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); @@ -706,446 +695,4 @@ void main() { expect(tester.takeException(), isNull); }); - - for (final bool shouldAnimate in <bool>[true, false]) { - testWidgets('Can ${shouldAnimate ? 'animate' : 'jump'} to arbitrary positions', (WidgetTester tester) async { - const Key stackKey = ValueKey<String>('stack'); - const Key containerKey = ValueKey<String>('container'); - final DraggableScrollableController controller = DraggableScrollableController(); - await tester.pumpWidget(_boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - await tester.pumpAndSettle(); - final double screenHeight = tester.getSize(find.byKey(stackKey)).height; - // Use a local helper to animate so we can share code across a jumpTo test - // and an animateTo test. - void goTo(double size) => shouldAnimate - ? controller.animateTo(size, duration: const Duration(milliseconds: 200), curve: Curves.linear) - : controller.jumpTo(size); - // If we're animating, pump will call four times, two of which are for the - // animation duration. - final int expectedPumpCount = shouldAnimate ? 4 : 2; - - goTo(.6); - expect(await tester.pumpAndSettle(), expectedPumpCount); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.6, precisionErrorTolerance), - ); - expect(find.text('Item 1'), findsOneWidget); - expect(find.text('Item 20'), findsOneWidget); - expect(find.text('Item 70'), findsNothing); - - goTo(.4); - expect(await tester.pumpAndSettle(), expectedPumpCount); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.4, precisionErrorTolerance), - ); - expect(find.text('Item 1'), findsOneWidget); - expect(find.text('Item 20'), findsNothing); - expect(find.text('Item 70'), findsNothing); - - await tester.fling(find.text('Item 1'), Offset(0, -screenHeight), 100); - await tester.pumpAndSettle(); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(1, precisionErrorTolerance), - ); - expect(find.text('Item 1'), findsNothing); - expect(find.text('Item 20'), findsOneWidget); - expect(find.text('Item 70'), findsNothing); - - // Programmatic control does not affect the inner scrollable's position. - goTo(.8); - expect(await tester.pumpAndSettle(), expectedPumpCount); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.8, precisionErrorTolerance), - ); - expect(find.text('Item 1'), findsNothing); - expect(find.text('Item 20'), findsOneWidget); - expect(find.text('Item 70'), findsNothing); - - // Attempting to move to a size too big or too small instead moves to the - // min or max child size. - goTo(.5); - await tester.pumpAndSettle(); - goTo(0); - // The animation was cut short by half, there should have been on less pumps - final int truncatedPumpCount = shouldAnimate ? expectedPumpCount - 1 : expectedPumpCount; - expect(await tester.pumpAndSettle(), truncatedPumpCount); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.25, precisionErrorTolerance), - ); - }); - } - - testWidgets('Can reuse a controller after the old controller is disposed', (WidgetTester tester) async { - const Key stackKey = ValueKey<String>('stack'); - const Key containerKey = ValueKey<String>('container'); - final DraggableScrollableController controller = DraggableScrollableController(); - await tester.pumpWidget(_boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - await tester.pumpAndSettle(); - - // Pump a new sheet with the same controller. This will dispose of the old sheet first. - await tester.pumpWidget(_boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - await tester.pumpAndSettle(); - final double screenHeight = tester.getSize(find.byKey(stackKey)).height; - - controller.jumpTo(.6); - await tester.pumpAndSettle(); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.6, precisionErrorTolerance), - ); - }); - - testWidgets('animateTo interrupts other animations', (WidgetTester tester) async { - const Key stackKey = ValueKey<String>('stack'); - const Key containerKey = ValueKey<String>('container'); - final DraggableScrollableController controller = DraggableScrollableController(); - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: _boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - ), - )); - await tester.pumpAndSettle(); - final double screenHeight = tester.getSize(find.byKey(stackKey)).height; - - await tester.flingFrom(Offset(0, .5*screenHeight), Offset(0, -.5*screenHeight), 2000); - // Wait until `flinFrom` finished dragging, but before the scrollable goes ballistic. - await tester.pump(const Duration(seconds: 1)); - - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(1, precisionErrorTolerance), - ); - expect(find.text('Item 1'), findsOneWidget); - - controller.animateTo(.9, duration: const Duration(milliseconds: 200), curve: Curves.linear); - await tester.pumpAndSettle(); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.9, precisionErrorTolerance), - ); - // The ballistic animation should have been canceled so item 1 should still be visible. - expect(find.text('Item 1'), findsOneWidget); - }); - - testWidgets('Other animations interrupt animateTo', (WidgetTester tester) async { - const Key stackKey = ValueKey<String>('stack'); - const Key containerKey = ValueKey<String>('container'); - final DraggableScrollableController controller = DraggableScrollableController(); - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: _boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - ), - )); - await tester.pumpAndSettle(); - final double screenHeight = tester.getSize(find.byKey(stackKey)).height; - - controller.animateTo(1, duration: const Duration(milliseconds: 200), curve: Curves.linear); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 100)); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.75, precisionErrorTolerance), - ); - - // Interrupt animation and drag downward. - await tester.drag(find.text('Item 1'), Offset(0, .1 * screenHeight)); - await tester.pumpAndSettle(); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.65, precisionErrorTolerance), - ); - }); - - testWidgets('animateTo can be interrupted by other animateTo or jumpTo', (WidgetTester tester) async { - const Key stackKey = ValueKey<String>('stack'); - const Key containerKey = ValueKey<String>('container'); - final DraggableScrollableController controller = DraggableScrollableController(); - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: _boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - ), - )); - await tester.pumpAndSettle(); - final double screenHeight = tester.getSize(find.byKey(stackKey)).height; - - controller.animateTo(1, duration: const Duration(milliseconds: 200), curve: Curves.linear); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 100)); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.75, precisionErrorTolerance), - ); - - // Interrupt animation with a new `animateTo`. - controller.animateTo(.25, duration: const Duration(milliseconds: 200), curve: Curves.linear); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 100)); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.5, precisionErrorTolerance), - ); - - // Interrupt animation with a jump. - controller.jumpTo(.6); - await tester.pumpAndSettle(); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.6, precisionErrorTolerance), - ); - }); - - testWidgets('Can get size and pixels', (WidgetTester tester) async { - const Key stackKey = ValueKey<String>('stack'); - const Key containerKey = ValueKey<String>('container'); - final DraggableScrollableController controller = DraggableScrollableController(); - await tester.pumpWidget(_boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - await tester.pumpAndSettle(); - final double screenHeight = tester.getSize(find.byKey(stackKey)).height; - - expect(controller.sizeToPixels(.25), .25*screenHeight); - expect(controller.pixelsToSize(.25*screenHeight), .25); - - controller.animateTo(.6, duration: const Duration(milliseconds: 200), curve: Curves.linear); - await tester.pumpAndSettle(); - expect( - tester.getSize(find.byKey(containerKey)).height / screenHeight, - closeTo(.6, precisionErrorTolerance), - ); - expect(controller.size, closeTo(.6, precisionErrorTolerance)); - expect(controller.pixels, closeTo(.6*screenHeight, precisionErrorTolerance)); - - await tester.drag(find.text('Item 5'), Offset(0, .2*screenHeight)); - expect(controller.size, closeTo(.4, precisionErrorTolerance)); - expect(controller.pixels, closeTo(.4*screenHeight, precisionErrorTolerance)); - }); - - testWidgets('Cannot attach a controller to multiple sheets', (WidgetTester tester) async { - final DraggableScrollableController controller = DraggableScrollableController(); - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: Stack( - children: <Widget>[ - _boilerplate( - null, - controller: controller, - ), - _boilerplate( - null, - controller: controller, - ) - ], - ), - ), null, EnginePhase.build); - expect(tester.takeException(), isAssertionError); - }); - - testWidgets('Can listen for changes in sheet size', (WidgetTester tester) async { - const Key stackKey = ValueKey<String>('stack'); - const Key containerKey = ValueKey<String>('container'); - final List<double> loggedSizes = <double>[]; - final DraggableScrollableController controller = DraggableScrollableController(); - controller.addListener(() { - loggedSizes.add(controller.size); - }); - await tester.pumpWidget(_boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - await tester.pumpAndSettle(); - final double screenHeight = tester - .getSize(find.byKey(stackKey)) - .height; - - // The initial size shouldn't be logged because no change has occurred yet. - expect(loggedSizes.isEmpty, true); - - await tester.drag(find.text('Item 1'), Offset(0, .1 * screenHeight), touchSlopY: 0); - await tester.pumpAndSettle(); - expect(loggedSizes, <double>[.4].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - - await tester.timedDrag(find.text('Item 1'), Offset(0, -.1 * screenHeight), const Duration(seconds: 1), frequency: 2); - await tester.pumpAndSettle(); - expect(loggedSizes, <double>[.45, .5].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - - controller.jumpTo(.6); - await tester.pumpAndSettle(); - expect(loggedSizes, <double>[.6].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - - controller.animateTo(1, duration: const Duration(milliseconds: 400), curve: Curves.linear); - await tester.pumpAndSettle(); - expect(loggedSizes, <double>[.7, .8, .9, 1].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - - DraggableScrollableActuator.reset(tester.element(find.byKey(containerKey))); - await tester.pumpAndSettle(); - expect(loggedSizes, <double>[.5].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - }); - - testWidgets('Listener does not fire on parameter change and persists after change', (WidgetTester tester) async { - const Key stackKey = ValueKey<String>('stack'); - const Key containerKey = ValueKey<String>('container'); - final List<double> loggedSizes = <double>[]; - final DraggableScrollableController controller = DraggableScrollableController(); - controller.addListener(() { - loggedSizes.add(controller.size); - }); - await tester.pumpWidget(_boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - await tester.pumpAndSettle(); - final double screenHeight = tester - .getSize(find.byKey(stackKey)) - .height; - - expect(loggedSizes.isEmpty, true); - - await tester.drag(find.text('Item 1'), Offset(0, .1 * screenHeight), touchSlopY: 0); - await tester.pumpAndSettle(); - expect(loggedSizes, <double>[.4].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - - // Update a parameter without forcing a change in the current size. - await tester.pumpWidget(_boilerplate( - null, - minChildSize: .1, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - expect(loggedSizes.isEmpty, true); - - await tester.drag(find.text('Item 1'), Offset(0, .1 * screenHeight), touchSlopY: 0); - await tester.pumpAndSettle(); - expect(loggedSizes, <double>[.3].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - }); - - testWidgets('Listener fires if a parameter change forces a change in size', (WidgetTester tester) async { - const Key stackKey = ValueKey<String>('stack'); - const Key containerKey = ValueKey<String>('container'); - final List<double> loggedSizes = <double>[]; - final DraggableScrollableController controller = DraggableScrollableController(); - controller.addListener(() { - loggedSizes.add(controller.size); - }); - await tester.pumpWidget(_boilerplate( - null, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - await tester.pumpAndSettle(); - final double screenHeight = tester - .getSize(find.byKey(stackKey)) - .height; - - expect(loggedSizes.isEmpty, true); - - // Set a new `initialChildSize` which will trigger a size change because we - // haven't moved away initial size yet. - await tester.pumpWidget(_boilerplate( - null, - initialChildSize: .6, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - expect(loggedSizes, <double>[.6].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - - // Move away from initial child size. - await tester.drag(find.text('Item 1'), Offset(0, .3 * screenHeight), touchSlopY: 0); - await tester.pumpAndSettle(); - expect(loggedSizes, <double>[.3].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - - // Set a `minChildSize` greater than the current size. - await tester.pumpWidget(_boilerplate( - null, - minChildSize: .4, - controller: controller, - stackKey: stackKey, - containerKey: containerKey, - )); - expect(loggedSizes, <double>[.4].map((double v) => closeTo(v, precisionErrorTolerance))); - loggedSizes.clear(); - }); - - testWidgets('Invalid controller interactions throw assertion errors', (WidgetTester tester) async { - final DraggableScrollableController controller = DraggableScrollableController(); - // Can't use a controller before attaching it. - expect(() => controller.jumpTo(.1), throwsAssertionError); - - expect(() => controller.pixels, throwsAssertionError); - expect(() => controller.size, throwsAssertionError); - expect(() => controller.pixelsToSize(0), throwsAssertionError); - expect(() => controller.sizeToPixels(0), throwsAssertionError); - - await tester.pumpWidget(_boilerplate( - null, - controller: controller, - )); - - - // Can't jump or animate to invalid sizes. - expect(() => controller.jumpTo(-1), throwsAssertionError); - expect(() => controller.jumpTo(1.1), throwsAssertionError); - expect( - () => controller.animateTo(-1, duration: const Duration(milliseconds: 1), curve: Curves.linear), - throwsAssertionError, - ); - expect( - () => controller.animateTo(1.1, duration: const Duration(milliseconds: 1), curve: Curves.linear), - throwsAssertionError, - ); - - // Can't use animateTo with a zero duration. - expect(() => controller.animateTo(.5, duration: Duration.zero, curve: Curves.linear), throwsAssertionError); - }); } diff --git a/packages/flutter/test/widgets/draggable_test.dart b/packages/flutter/test/widgets/draggable_test.dart index e58ee03713a7f..a85dd934f834a 100644 --- a/packages/flutter/test/widgets/draggable_test.dart +++ b/packages/flutter/test/widgets/draggable_test.dart @@ -3116,7 +3116,6 @@ Future<void> _testLongPressDraggableHapticFeedback({ required WidgetTester teste if (methodCall.method == 'HapticFeedback.vibrate') { hapticFeedbackCalls++; } - return null; }); await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/widgets/editable_text_shortcuts_tests.dart b/packages/flutter/test/widgets/editable_text_shortcuts_tests.dart deleted file mode 100644 index 6941c25a37334..0000000000000 --- a/packages/flutter/test/widgets/editable_text_shortcuts_tests.dart +++ /dev/null @@ -1,1800 +0,0 @@ -// 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 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; - -Future<void> sendKeyCombination( - WidgetTester tester, - SingleActivator activator, -) async { - final List<LogicalKeyboardKey> modifiers = <LogicalKeyboardKey>[ - if (activator.control) LogicalKeyboardKey.control, - if (activator.shift) LogicalKeyboardKey.shift, - if (activator.alt) LogicalKeyboardKey.alt, - if (activator.meta) LogicalKeyboardKey.meta, - ]; - for (final LogicalKeyboardKey modifier in modifiers) { - await tester.sendKeyDownEvent(modifier); - } - await tester.sendKeyDownEvent(activator.trigger); - await tester.sendKeyUpEvent(activator.trigger); - await tester.pump(); - for (final LogicalKeyboardKey modifier in modifiers.reversed) { - await tester.sendKeyUpEvent(modifier); - } -} - -Iterable<SingleActivator> allModifierVariants(LogicalKeyboardKey trigger) { - const Iterable<bool> trueFalse = <bool>[false, true]; - return trueFalse.expand((bool shift) { - return trueFalse.expand((bool control) { - return trueFalse.expand((bool alt) { - return trueFalse.map((bool meta) => SingleActivator(trigger, shift: shift, control: control, alt: alt, meta: meta)); - }); - }); - }); -} - -void main() { - const String testText = - 'Now is the time for\n' // 20 - 'all good people\n' // 20 + 16 => 36 - 'to come to the aid\n' // 36 + 19 => 55 - 'of their country.'; // 55 + 17 => 72 - const String testCluster = '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'; // 8 * 3 - - // Exactly 20 characters each line. - const String testSoftwrapText = - '0123456789ABCDEFGHIJ' - '0123456789ABCDEFGHIJ' - '0123456789ABCDEFGHIJ' - '0123456789ABCDEFGHIJ'; - final TextEditingController controller = TextEditingController(text: testText); - - final FocusNode focusNode = FocusNode(); - Widget buildEditableText({ - TextAlign textAlign = TextAlign.left, - bool readOnly = false, - bool obscured = false, - TextStyle style = const TextStyle(fontSize: 10.0), - }) { - return MaterialApp( - home: Align( - alignment: Alignment.topLeft, - child: SizedBox( - // Softwrap at exactly 20 characters. - width: 201, - child: EditableText( - controller: controller, - showSelectionHandles: true, - autofocus: true, - focusNode: focusNode, - style: style, - textScaleFactor: 1, - // Avoid the cursor from taking up width. - cursorWidth: 0, - cursorColor: Colors.blue, - backgroundCursorColor: Colors.grey, - selectionControls: materialTextSelectionControls, - keyboardType: TextInputType.text, - maxLines: obscured ? 1 : null, - readOnly: readOnly, - textAlign: textAlign, - obscureText: obscured, - ), - ), - ), - ); - } - - testWidgets( - 'Movement/Deletion shortcuts do nothing when the selection is invalid', - (WidgetTester tester) async { - await tester.pumpWidget(buildEditableText()); - controller.text = testText; - controller.selection = const TextSelection.collapsed(offset: -1); - await tester.pump(); - - const List<LogicalKeyboardKey> triggers = <LogicalKeyboardKey>[ - LogicalKeyboardKey.backspace, - LogicalKeyboardKey.delete, - LogicalKeyboardKey.arrowLeft, - LogicalKeyboardKey.arrowRight, - LogicalKeyboardKey.arrowUp, - LogicalKeyboardKey.arrowDown, - LogicalKeyboardKey.home, - LogicalKeyboardKey.end, - ]; - - for (final SingleActivator activator in triggers.expand(allModifierVariants)) { - await sendKeyCombination(tester, activator); - await tester.pump(); - expect(controller.text, testText, reason: activator.toString()); - expect(controller.selection, const TextSelection.collapsed(offset: -1), reason: activator.toString()); - } - }, - skip: kIsWeb, // [intended] - variant: TargetPlatformVariant.all(), - ); - - group('Common text editing shortcuts: ', - () { - final TargetPlatformVariant allExceptMacOS = TargetPlatformVariant(TargetPlatform.values.toSet()..remove(TargetPlatform.macOS)); - - group('backspace', () { - const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace; - - testWidgets('backspace', (WidgetTester tester) async { - controller.text = testText; - // Move the selection to the beginning of the 2nd line (after the newline - // character). - controller.selection = const TextSelection.collapsed( - offset: 20, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - 'Now is the time forall good people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 19), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('backspace readonly', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 20, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText(readOnly: true)); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect(controller.text, testText); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 20, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('backspace at start', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 0, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - 'Now is the time for\n' - 'all good people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('backspace at end', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 72, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - 'Now is the time for\n' - 'all good people\n' - 'to come to the aid\n' - 'of their country', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 71), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('backspace inside of a cluster', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 1, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('backspace at cluster boundary', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 8, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - }); - - group('delete: ', () { - const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete; - - testWidgets('delete', (WidgetTester tester) async { - controller.text = testText; - // Move the selection to the beginning of the 2nd line (after the newline - // character). - controller.selection = const TextSelection.collapsed( - offset: 20, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - 'Now is the time for\n' - 'll good people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 20), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('delete readonly', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 20, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText(readOnly: true)); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect(controller.text, testText); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 20, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('delete at start', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 0, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - 'ow is the time for\n' - 'all good people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('delete at end', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 72, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - 'Now is the time for\n' - 'all good people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 72, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('delete inside of a cluster', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 1, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('delete at cluster boundary', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 8, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 8), - ); - }, variant: TargetPlatformVariant.all()); - }); - - group('Non-collapsed delete', () { - // This shares the same logic as backspace. - const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete; - - testWidgets('inside of a cluster', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection( - baseOffset: 9, - extentOffset: 12, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 8), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at the boundaries of a cluster', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection( - baseOffset: 8, - extentOffset: 16, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 8), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('cross-cluster', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection( - baseOffset: 1, - extentOffset: 9, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - '👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('cross-cluster obscured text', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection( - baseOffset: 1, - extentOffset: 9, - ); - - await tester.pumpWidget(buildEditableText(obscured: true)); - await sendKeyCombination(tester, const SingleActivator(trigger)); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 1), - ); - }, variant: TargetPlatformVariant.all()); - }); - - group('word modifier + backspace', () { - const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace; - SingleActivator wordModifierBackspace() { - final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS; - return SingleActivator(trigger, control: !isMacOS, alt: isMacOS); - } - - testWidgets('WordModifier-backspace', (WidgetTester tester) async { - controller.text = testText; - // Place the caret before "people". - controller.selection = const TextSelection.collapsed( - offset: 29, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierBackspace()); - - expect( - controller.text, - 'Now is the time for\n' - 'all people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 24), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('readonly', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 29, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText(readOnly: true)); - await sendKeyCombination(tester, wordModifierBackspace()); - - expect(controller.text, testText); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 29, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at start', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 0, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierBackspace()); - - expect( - controller.text, - 'Now is the time for\n' - 'all good people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at end', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 72, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierBackspace()); - - expect( - controller.text, - 'Now is the time for\n' - 'all good people\n' - 'to come to the aid\n' - 'of their country', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 71), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('inside of a cluster', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 1, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierBackspace()); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at cluster boundary', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 8, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierBackspace()); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - }); - - group('word modifier + delete', () { - const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete; - SingleActivator wordModifierDelete() { - final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS; - return SingleActivator(trigger, control: !isMacOS, alt: isMacOS); - } - - testWidgets('WordModifier-delete', (WidgetTester tester) async { - controller.text = testText; - // Place the caret after "all". - controller.selection = const TextSelection.collapsed( - offset: 23, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierDelete()); - - expect( - controller.text, - 'Now is the time for\n' - 'all people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 23), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('readonly', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 23, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText(readOnly: true)); - await sendKeyCombination(tester, wordModifierDelete()); - - expect(controller.text, testText); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 23, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at start', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 0, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierDelete()); - - expect( - controller.text, - ' is the time for\n' - 'all good people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at end', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 72, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierDelete()); - - expect(controller.text, testText); - expect( - controller.selection, - const TextSelection.collapsed(offset: 72, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('inside of a cluster', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 1, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierDelete()); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at cluster boundary', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 8, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, wordModifierDelete()); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 8), - ); - }, variant: TargetPlatformVariant.all()); - }); - - group('line modifier + backspace', () { - const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace; - SingleActivator lineModifierBackspace() { - final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS; - return SingleActivator(trigger, meta: isMacOS, alt: !isMacOS); - } - - testWidgets('alt-backspace', (WidgetTester tester) async { - controller.text = testText; - // Place the caret before "people". - controller.selection = const TextSelection.collapsed( - offset: 29, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierBackspace()); - - expect( - controller.text, - 'Now is the time for\n' - 'people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 20), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('softwrap line boundary, upstream', (WidgetTester tester) async { - controller.text = testSoftwrapText; - // Place the caret at the beginning of the 3rd line. - controller.selection = const TextSelection.collapsed( - offset: 40, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierBackspace()); - - expect( - controller.text, - '0123456789ABCDEFGHIJ' - '0123456789ABCDEFGHIJ' - '0123456789ABCDEFGHIJ' - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 20), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('softwrap line boundary, downstream', (WidgetTester tester) async { - controller.text = testSoftwrapText; - // Place the caret at the beginning of the 3rd line. - controller.selection = const TextSelection.collapsed( - offset: 40, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierBackspace()); - - expect(controller.text, testSoftwrapText); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 40), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('readonly', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 29, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText(readOnly: true)); - await sendKeyCombination(tester, lineModifierBackspace()); - - expect(controller.text, testText); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 29, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at start', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 0, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierBackspace()); - - expect( - controller.text, - 'Now is the time for\n' - 'all good people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at end', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 72, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierBackspace()); - - expect( - controller.text, - 'Now is the time for\n' - 'all good people\n' - 'to come to the aid\n' - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 55), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('inside of a cluster', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 1, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierBackspace()); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at cluster boundary', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 8, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierBackspace()); - - expect( - controller.text, - '👨‍👩‍👦👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - }); - - group('line modifier + delete', () { - const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete; - SingleActivator lineModifierDelete() { - final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS; - return SingleActivator(trigger, meta: isMacOS, alt: !isMacOS); - } - - testWidgets('alt-delete', (WidgetTester tester) async { - controller.text = testText; - // Place the caret after "all". - controller.selection = const TextSelection.collapsed( - offset: 23, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierDelete()); - - expect( - controller.text, - 'Now is the time for\n' - 'all\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 23), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('softwrap line boundary, upstream', (WidgetTester tester) async { - controller.text = testSoftwrapText; - // Place the caret at the beginning of the 3rd line. - controller.selection = const TextSelection.collapsed( - offset: 40, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierDelete()); - - expect(controller.text, testSoftwrapText); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 40, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('softwrap line boundary, downstream', (WidgetTester tester) async { - controller.text = testSoftwrapText; - // Place the caret at the beginning of the 3rd line. - controller.selection = const TextSelection.collapsed( - offset: 40, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierDelete()); - - expect( - controller.text, - '0123456789ABCDEFGHIJ' - '0123456789ABCDEFGHIJ' - '0123456789ABCDEFGHIJ' - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 40), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('readonly', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 23, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText(readOnly: true)); - await sendKeyCombination(tester, lineModifierDelete()); - - expect(controller.text, testText); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 23, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at start', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 0, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierDelete()); - - expect( - controller.text, - '\n' - 'all good people\n' - 'to come to the aid\n' - 'of their country.', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at end', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 72, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierDelete()); - - expect(controller.text, testText); - expect( - controller.selection, - const TextSelection.collapsed(offset: 72, affinity: TextAffinity.upstream), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('inside of a cluster', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 1, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierDelete()); - - expect( - controller.text, - isEmpty, - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - ); - }, variant: TargetPlatformVariant.all()); - - testWidgets('at cluster boundary', (WidgetTester tester) async { - controller.text = testCluster; - controller.selection = const TextSelection.collapsed( - offset: 8, - affinity: TextAffinity.upstream, - ); - - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, lineModifierDelete()); - - expect( - controller.text, - '👨‍👩‍👦', - ); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 8), - ); - }, variant: TargetPlatformVariant.all()); - }); - - group('Arrow Movement', () { - group('left', () { - const LogicalKeyboardKey trigger = LogicalKeyboardKey.arrowLeft; - - testWidgets('at start', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 0, - ); - - await tester.pumpWidget(buildEditableText()); - - for (final SingleActivator activator in allModifierVariants(trigger)) { - await sendKeyCombination(tester, activator); - await tester.pump(); - - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - reason: activator.toString(), - ); - } - }, variant: TargetPlatformVariant.all()); - - testWidgets('base arrow key movement', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 20, - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 19, - )); - }, variant: TargetPlatformVariant.all()); - - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 7, // Before the first "the" - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger, control: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 4, - )); - }, variant: allExceptMacOS); - - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 24, // Before the "good". - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger, alt: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 20, - )); - }, variant: allExceptMacOS); - }); - - group('right', () { - const LogicalKeyboardKey trigger = LogicalKeyboardKey.arrowRight; - - testWidgets('at end', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 72, - ); - - await tester.pumpWidget(buildEditableText()); - - for (final SingleActivator activator in allModifierVariants(trigger)) { - await sendKeyCombination(tester, activator); - await tester.pump(); - - expect(controller.selection.isCollapsed, isTrue, reason: activator.toString()); - expect(controller.selection.baseOffset, 72, reason: activator.toString()); - } - }, variant: TargetPlatformVariant.all()); - - testWidgets('base arrow key movement', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 20, - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 21, - )); - }, variant: TargetPlatformVariant.all()); - - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 7, // Before the first "the" - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger, control: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 10, - )); - }, variant: allExceptMacOS); - - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 24, // Before the "good". - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(trigger, alt: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 35, // Before the newline character. - affinity: TextAffinity.upstream, - )); - }, variant: allExceptMacOS); - }); - - group('With initial non-collapsed selection', () { - testWidgets('base arrow key movement', (WidgetTester tester) async { - controller.text = testText; - // The word "all" is selected. - controller.selection = const TextSelection( - baseOffset: 20, - extentOffset: 23, - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 20, - )); - - // The word "all" is selected. - controller.selection = const TextSelection( - baseOffset: 23, - extentOffset: 20, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 20, - )); - - // The word "all" is selected. - controller.selection = const TextSelection( - baseOffset: 20, - extentOffset: 23, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 23, - )); - - // The word "all" is selected. - controller.selection = const TextSelection( - baseOffset: 23, - extentOffset: 20, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 23, - )); - }, variant: TargetPlatformVariant.all()); - - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { - controller.text = testText; - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 24, - extentOffset: 43, - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, control: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 39, // Before "come". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 43, - extentOffset: 24, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, control: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 20, // Before "all". - //offset: 39, // Before "come". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 24, - extentOffset: 43, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, control: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 46, // After "to". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 43, - extentOffset: 24, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, control: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 28, // After "good". - )); - }, variant: allExceptMacOS); - - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { - controller.text = testText; - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 24, - extentOffset: 43, - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 36, // Before "to". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 43, - extentOffset: 24, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 20, // Before "all". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 24, - extentOffset: 43, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 54, // After "aid". - affinity: TextAffinity.upstream, - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 43, - extentOffset: 24, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 35, // After "people". - affinity: TextAffinity.upstream, - )); - }, variant: allExceptMacOS); - }); - - group('vertical movement', () { - testWidgets('at start', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 0, - ); - - await tester.pumpWidget(buildEditableText()); - - for (final SingleActivator activator in allModifierVariants(LogicalKeyboardKey.arrowUp)) { - await sendKeyCombination(tester, activator); - await tester.pump(); - - expect(controller.text, testText); - expect( - controller.selection, - const TextSelection.collapsed(offset: 0), - reason: activator.toString(), - ); - } - }, variant: TargetPlatformVariant.all()); - - testWidgets('at end', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 72, - ); - - await tester.pumpWidget(buildEditableText()); - - for (final SingleActivator activator in allModifierVariants(LogicalKeyboardKey.arrowDown)) { - await sendKeyCombination(tester, activator); - await tester.pump(); - - expect(controller.text, testText); - expect(controller.selection.baseOffset, 72, reason: activator.toString()); - expect(controller.selection.extentOffset, 72, reason: activator.toString()); - } - }, variant: TargetPlatformVariant.all()); - - testWidgets('run', (WidgetTester tester) async { - controller.text = - 'aa\n' // 3 - 'a\n' // 3 + 2 = 5 - 'aa\n' // 5 + 3 = 8 - 'aaa\n' // 8 + 4 = 12 - 'aaaa'; // 12 + 4 = 16 - - controller.selection = const TextSelection.collapsed( - offset: 2, - ); - await tester.pumpWidget(buildEditableText()); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 4, - affinity: TextAffinity.upstream, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 7, - affinity: TextAffinity.upstream, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 10, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 14, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 16, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 10, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 7, - affinity: TextAffinity.upstream, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 4, - affinity: TextAffinity.upstream, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 2, - affinity: TextAffinity.upstream, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 0, - )); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 4, - affinity: TextAffinity.upstream, - )); - }, variant: TargetPlatformVariant.all()); - - testWidgets('run can be interrupted by layout changes', (WidgetTester tester) async { - controller.text = - 'aa\n' // 3 - 'a\n' // 3 + 2 = 5 - 'aa\n' // 5 + 3 = 8 - 'aaa\n' // 8 + 4 = 12 - 'aaaa'; // 12 + 4 = 16 - - controller.selection = const TextSelection.collapsed( - offset: 2, - ); - await tester.pumpWidget(buildEditableText()); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 0, - )); - - // Layout changes. - await tester.pumpWidget(buildEditableText(textAlign: TextAlign.right)); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 3, - )); - }, variant: TargetPlatformVariant.all()); - - testWidgets('run can be interrupted by selection changes', (WidgetTester tester) async { - controller.text = - 'aa\n' // 3 - 'a\n' // 3 + 2 = 5 - 'aa\n' // 5 + 3 = 8 - 'aaa\n' // 8 + 4 = 12 - 'aaaa'; // 12 + 4 = 16 - - controller.selection = const TextSelection.collapsed( - offset: 2, - ); - await tester.pumpWidget(buildEditableText()); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 0, - )); - - controller.selection = const TextSelection.collapsed( - offset: 1, - ); - await tester.pump(); - controller.selection = const TextSelection.collapsed( - offset: 0, - ); - await tester.pump(); - - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 3, // Would have been 4 if the run wasn't interrupted. - )); - }, variant: TargetPlatformVariant.all()); - - testWidgets('long run with fractional text height', (WidgetTester tester) async { - controller.text = "${'źdźbło\n' * 49}źdźbło"; - controller.selection = const TextSelection.collapsed(offset: 2); - await tester.pumpWidget(buildEditableText(style: const TextStyle(fontSize: 13.0, height: 1.17))); - - for (int i = 1; i <= 49; i++) { - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown)); - await tester.pump(); - expect( - controller.selection, - TextSelection.collapsed(offset: 2 + i * 7), - reason: 'line $i', - ); - } - - for (int i = 49; i >= 1; i--) { - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp)); - await tester.pump(); - expect( - controller.selection, - TextSelection.collapsed(offset: 2 + (i - 1) * 7), - reason: 'line $i', - ); - } - }, variant: TargetPlatformVariant.all()); - }); - }); - }, - skip: kIsWeb, // [intended] - ); - - group('macOS shortcuts', () { - final TargetPlatformVariant macOSOnly = TargetPlatformVariant.only(TargetPlatform.macOS); - - testWidgets('word modifier + arrowLeft', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 7, // Before the first "the" - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 4, - )); - }, variant: macOSOnly); - - testWidgets('word modifier + arrowRight', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 7, // Before the first "the" - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 10, - )); - }, variant: macOSOnly); - - testWidgets('line modifier + arrowLeft', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 24, // Before the "good". - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 20, - )); - }, variant: macOSOnly); - - testWidgets('line modifier + arrowRight', (WidgetTester tester) async { - controller.text = testText; - controller.selection = const TextSelection.collapsed( - offset: 24, // Before the "good". - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 35, // Before the newline character. - affinity: TextAffinity.upstream, - )); - }, variant: macOSOnly); - - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { - controller.text = testText; - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 24, - extentOffset: 43, - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 39, // Before "come". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 43, - extentOffset: 24, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 20, // Before "all". - //offset: 39, // Before "come". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 24, - extentOffset: 43, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 46, // After "to". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 43, - extentOffset: 24, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 28, // After "good". - )); - }, variant: macOSOnly); - - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { - controller.text = testText; - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 24, - extentOffset: 43, - ); - await tester.pumpWidget(buildEditableText()); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true)); - await tester.pump(); - - expect(controller.selection, const TextSelection.collapsed( - offset: 36, // Before "to". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 43, - extentOffset: 24, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 20, // Before "all". - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 24, - extentOffset: 43, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 54, // After "aid". - affinity: TextAffinity.upstream, - )); - - // "good" to "come" is selected. - controller.selection = const TextSelection( - baseOffset: 43, - extentOffset: 24, - ); - await tester.pump(); - await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true)); - await tester.pump(); - expect(controller.selection, const TextSelection.collapsed( - offset: 35, // After "people". - affinity: TextAffinity.upstream, - )); - }, variant: macOSOnly); - }); -} diff --git a/packages/flutter/test/widgets/editable_text_show_on_screen_test.dart b/packages/flutter/test/widgets/editable_text_show_on_screen_test.dart index 27ca95df01abf..0603ece9433e0 100644 --- a/packages/flutter/test/widgets/editable_text_show_on_screen_test.dart +++ b/packages/flutter/test/widgets/editable_text_show_on_screen_test.dart @@ -14,6 +14,7 @@ class _TestSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate required this.maxExtent, required this.child, this.vsync = const TestVSync(), + this.showOnScreenConfiguration = const PersistentHeaderShowOnScreenConfiguration(), }); final Widget child; @@ -28,7 +29,7 @@ class _TestSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate final TickerProvider? vsync; @override - final PersistentHeaderShowOnScreenConfiguration showOnScreenConfiguration = const PersistentHeaderShowOnScreenConfiguration(); + final PersistentHeaderShowOnScreenConfiguration showOnScreenConfiguration; @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => child; diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 025123a27d1ba..3ccb3c219c201 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -1506,7 +1506,7 @@ void main() { expect(find.text('Cut'), findsNothing); }); - testWidgets('cut and paste are disabled in read only mode even if explicitly set', (WidgetTester tester) async { + testWidgets('cut and paste are disabled in read only mode even if explicit set', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( @@ -1514,12 +1514,6 @@ void main() { controller: TextEditingController(text: 'blah blah'), focusNode: focusNode, readOnly: true, - toolbarOptions: const ToolbarOptions( - copy: true, - cut: true, - paste: true, - selectAll: true, - ), style: textStyle, cursorColor: cursorColor, selectionControls: materialTextSelectionControls, @@ -1545,113 +1539,6 @@ void main() { expect(find.text('Cut'), findsNothing); }); - testWidgets('cut and copy are disabled in obscured mode even if explicitly set', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: EditableText( - backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), - focusNode: focusNode, - obscureText: true, - toolbarOptions: const ToolbarOptions( - copy: true, - cut: true, - paste: true, - selectAll: true, - ), - style: textStyle, - cursorColor: cursorColor, - selectionControls: materialTextSelectionControls, - ), - ), - ); - - final EditableTextState state = - tester.state<EditableTextState>(find.byType(EditableText)); - await tester.tap(find.byType(EditableText)); - await tester.pump(); - // Select something, but not the whole thing. - state.renderEditable.selectWord(cause: SelectionChangedCause.tap); - await tester.pump(); - expect(state.selectAllEnabled, isTrue); - expect(state.pasteEnabled, isTrue); - expect(state.cutEnabled, isFalse); - expect(state.copyEnabled, isFalse); - - // On web, we don't let Flutter show the toolbar. - expect(state.showToolbar(), kIsWeb ? isFalse : isTrue); - await tester.pump(); - expect(find.text('Select all'), kIsWeb ? findsNothing : findsOneWidget); - expect(find.text('Copy'), findsNothing); - expect(find.text('Paste'), kIsWeb ? findsNothing : findsOneWidget); - expect(find.text('Cut'), findsNothing); - }); - - testWidgets('cut and copy do nothing in obscured mode even if explicitly called', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: EditableText( - backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), - focusNode: focusNode, - obscureText: true, - style: textStyle, - cursorColor: cursorColor, - selectionControls: materialTextSelectionControls, - ), - ), - ); - - final EditableTextState state = - tester.state<EditableTextState>(find.byType(EditableText)); - expect(state.selectAllEnabled, isTrue); - expect(state.pasteEnabled, isTrue); - expect(state.cutEnabled, isFalse); - expect(state.copyEnabled, isFalse); - - // Select all. - state.selectAll(SelectionChangedCause.toolbar); - await tester.pump(); - await Clipboard.setData(const ClipboardData(text: '')); - state.cutSelection(SelectionChangedCause.toolbar); - ClipboardData? data = await Clipboard.getData('text/plain'); - expect(data, isNotNull); - expect(data!.text, isEmpty); - - state.selectAll(SelectionChangedCause.toolbar); - await tester.pump(); - await Clipboard.setData(const ClipboardData(text: '')); - state.copySelection(SelectionChangedCause.toolbar); - data = await Clipboard.getData('text/plain'); - expect(data, isNotNull); - expect(data!.text, isEmpty); - }); - - testWidgets('select all does nothing if obscured and read-only, even if explicitly called', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: EditableText( - backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), - focusNode: focusNode, - obscureText: true, - readOnly: true, - style: textStyle, - cursorColor: cursorColor, - selectionControls: materialTextSelectionControls, - ), - ), - ); - - final EditableTextState state = - tester.state<EditableTextState>(find.byType(EditableText)); - - // Select all. - state.selectAll(SelectionChangedCause.toolbar); - expect(state.selectAllEnabled, isFalse); - expect(state.textEditingValue.selection.isCollapsed, isTrue); - }); - testWidgets('Handles the read-only flag correctly', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(text: 'Lorem ipsum dolor sit amet'); @@ -2256,7 +2143,8 @@ void main() { // Show prompt rect when told to. verifyAutocorrectionRectVisibility(expectVisible: true); - await tester.enterText(find.byType(EditableText), '12345'); + // Text changed, prompt rect goes away. + controller.text = '12345'; await tester.pump(); verifyAutocorrectionRectVisibility(expectVisible: false); @@ -2267,8 +2155,7 @@ void main() { // Unfocus, prompt rect should go away. focusNode.unfocus(); - await tester.pumpAndSettle(); - + await tester.pump(); verifyAutocorrectionRectVisibility(expectVisible: false); }, ); @@ -2320,7 +2207,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.showKeyboard(find.byType(EditableText)); @@ -3616,7 +3502,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final TextEditingController controller = TextEditingController(); @@ -3646,7 +3531,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final TextEditingController controller = TextEditingController(); @@ -3682,7 +3566,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final TextEditingController controller1 = TextEditingController(); @@ -3768,7 +3651,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); const Offset offset = Offset(10.0, 20.0); @@ -3811,7 +3693,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final TextEditingController controller = TextEditingController(); @@ -3899,7 +3780,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); setState(() { currentTextStyle = textStyle2; @@ -4127,7 +4007,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final TextEditingController controller = TextEditingController(); @@ -4433,10 +4312,10 @@ void main() { // toolbar. Until we change that, this test should remain skipped. }, skip: kIsWeb); // [intended] - const String testText = 'Now is the time for\n' // 20 - 'all good people\n' // 20 + 16 => 36 - 'to come to the aid\n' // 36 + 19 => 55 - 'of their country.'; // 55 + 17 => 72 + const String testText = 'Now is the time for\n' + 'all good people\n' + 'to come to the aid\n' + 'of their country.'; Future<void> sendKeys( WidgetTester tester, @@ -4582,6 +4461,7 @@ void main() { const TextSelection( baseOffset: 0, extentOffset: 0, + affinity: TextAffinity.upstream, ), ), reason: 'on $platform', @@ -4603,6 +4483,7 @@ void main() { const TextSelection( baseOffset: 0, extentOffset: 0, + affinity: TextAffinity.upstream, ), ), reason: 'on $platform', @@ -4756,7 +4637,7 @@ void main() { equals( const TextSelection( baseOffset: 20, - extentOffset: 39, + extentOffset: 57, ), ), reason: 'on $platform', @@ -4778,13 +4659,14 @@ void main() { equals( const TextSelection( baseOffset: 20, - extentOffset: 54, + extentOffset: 72, affinity: TextAffinity.upstream, ), ), reason: 'on $platform', ); + // Can't move left by line because we're already at the beginning of a line. await sendKeys( tester, <LogicalKeyboardKey>[ @@ -4795,41 +4677,17 @@ void main() { targetPlatform: defaultTargetPlatform, ); - switch (defaultTargetPlatform) { - // These platforms extend by line. - case TargetPlatform.iOS: - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: - expect( - selection, - equals( - const TextSelection( - baseOffset: 20, - extentOffset: 36, - affinity: TextAffinity.upstream, - ), - ), - reason: 'on $platform', - ); - break; - - // Mac expands by line. - case TargetPlatform.macOS: - expect( - selection, - equals( - const TextSelection( - baseOffset: 20, - extentOffset: 54, - affinity: TextAffinity.upstream, - ), - ), - reason: 'on $platform', - ); - break; - } + expect( + selection, + equals( + const TextSelection( + baseOffset: 20, + extentOffset: 72, + affinity: TextAffinity.upstream, + ), + ), + reason: 'on $platform', + ); // Select All await sendKeys( @@ -4888,7 +4746,6 @@ void main() { equals( const TextSelection.collapsed( offset: testText.length, - affinity: TextAffinity.upstream, ), ), reason: 'on $platform', @@ -4910,6 +4767,7 @@ void main() { equals( const TextSelection.collapsed( offset: 0, + affinity: TextAffinity.upstream, ), ), reason: 'on $platform', @@ -4974,7 +4832,7 @@ void main() { selection, equals( const TextSelection( - baseOffset: 3, + baseOffset: testText.length, extentOffset: 0, affinity: TextAffinity.upstream, ), @@ -4996,6 +4854,7 @@ void main() { equals( const TextSelection.collapsed( offset: 0, + affinity: TextAffinity.upstream, ), ), reason: 'on $platform', @@ -5019,6 +4878,7 @@ void main() { const TextSelection( baseOffset: 10, extentOffset: 10, + affinity: TextAffinity.upstream, ), ), reason: 'on $platform', @@ -5088,6 +4948,7 @@ void main() { const TextSelection( baseOffset: 4, extentOffset: 4, + affinity: TextAffinity.upstream, ), ), reason: 'on $platform', @@ -5124,6 +4985,7 @@ void main() { const TextSelection( baseOffset: 10, extentOffset: 10, + affinity: TextAffinity.upstream, ), ), reason: 'on $platform', @@ -5169,55 +5031,12 @@ void main() { const TextSelection( baseOffset: 0, extentOffset: 0, + affinity: TextAffinity.upstream, ), ), reason: 'on $platform', ); expect(controller.text, isEmpty, reason: 'on $platform'); - - controller.text = 'abc'; - controller.selection = const TextSelection(baseOffset: 2, extentOffset: 2); - - // Backspace - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.backspace, - ], - targetPlatform: defaultTargetPlatform, - ); - expect( - selection, - equals( - const TextSelection( - baseOffset: 1, - extentOffset: 1, - ), - ), - reason: 'on $platform', - ); - expect(controller.text, 'ac', reason: 'on $platform'); - - // Shift-backspace (same as backspace) - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.backspace, - ], - shift: true, - targetPlatform: defaultTargetPlatform, - ); - expect( - selection, - equals( - const TextSelection( - baseOffset: 0, - extentOffset: 0, - ), - ), - reason: 'on $platform', - ); - expect(controller.text, 'c', reason: 'on $platform'); } testWidgets('keyboard text selection works (RawKeyEvent)', (WidgetTester tester) async { @@ -5243,7 +5062,7 @@ void main() { testWidgets( 'keyboard shortcuts respect read-only', (WidgetTester tester) async { - final String platform = defaultTargetPlatform.name.toLowerCase(); + final String platform = describeEnum(defaultTargetPlatform).toLowerCase(); final TextEditingController controller = TextEditingController(text: testText); controller.selection = const TextSelection( baseOffset: 0, @@ -5489,9 +5308,9 @@ void main() { targetPlatform: defaultTargetPlatform, ); - final int afterHomeOffset; - final int afterEndOffset; - final TextAffinity afterEndAffinity; + late final int afterHomeOffset; + late final int afterEndOffset; + late final TextAffinity afterEndAffinity; switch (defaultTargetPlatform) { // These platforms don't handle home/end at all. case TargetPlatform.android: @@ -5745,314 +5564,49 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('shift + home/end keys (Windows only)', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/31287 + testWidgets('text selection handle visibility', (WidgetTester tester) async { + // Text with two separate words to select. + const String testText = 'XXXXX XXXXX'; final TextEditingController controller = TextEditingController(text: testText); - controller.selection = const TextSelection( - baseOffset: 0, - extentOffset: 0, - affinity: TextAffinity.upstream, - ); + await tester.pumpWidget(MaterialApp( home: Align( alignment: Alignment.topLeft, child: SizedBox( - width: 400, + width: 100, child: EditableText( - maxLines: 10, - controller: controller, showSelectionHandles: true, - autofocus: true, + controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018(platform: TargetPlatform.iOS).black.subtitle1!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, - selectionControls: materialTextSelectionControls, + selectionControls: cupertinoTextSelectionControls, keyboardType: TextInputType.text, - textAlign: TextAlign.right, ), ), ), )); - await tester.pump(); + final EditableTextState state = + tester.state<EditableTextState>(find.byType(EditableText)); + final RenderEditable renderEditable = state.renderEditable; + final Scrollable scrollable = tester.widget<Scrollable>(find.byType(Scrollable)); - // Move the selection away from the start so it can invert. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowRight, - LogicalKeyboardKey.arrowRight, - LogicalKeyboardKey.arrowRight, - LogicalKeyboardKey.arrowRight, - ], - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - expect( - controller.selection, - equals(const TextSelection.collapsed( - offset: 4, - )), - ); + bool expectedLeftVisibleBefore = false; + bool expectedRightVisibleBefore = false; - // Press shift + end and extend the selection to the end of the line. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.end, - ], - shift: true, - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - expect( - controller.selection, - equals(const TextSelection( - baseOffset: 4, - extentOffset: 19, - affinity: TextAffinity.upstream, - )), - ); + Future<void> verifyVisibility( + HandlePositionInViewport leftPosition, + bool expectedLeftVisible, + HandlePositionInViewport rightPosition, + bool expectedRightVisible, + ) async { + await tester.pump(); - // Press shift + home and the selection inverts and extends to the start, it - // does not collapse and stop at the inversion. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.home, - ], - shift: true, - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - expect( - controller.selection, - equals(const TextSelection( - baseOffset: 4, - extentOffset: 0, - )), - ); - - // Press shift + end again and the selection inverts and extends to the end, - // again it does not stop at the inversion. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.end, - ], - shift: true, - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - expect( - controller.selection, - equals(const TextSelection( - baseOffset: 4, - extentOffset: 19, - )), - ); - }, - skip: kIsWeb, // [intended] on web these keys are handled by the browser. - variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.windows }) - ); - - testWidgets('control + home/end keys (Windows only)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); - controller.selection = const TextSelection( - baseOffset: 0, - extentOffset: 0, - affinity: TextAffinity.upstream, - ); - await tester.pumpWidget(MaterialApp( - home: Align( - alignment: Alignment.topLeft, - child: SizedBox( - width: 400, - child: EditableText( - maxLines: 10, - controller: controller, - showSelectionHandles: true, - autofocus: true, - focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, - cursorColor: Colors.blue, - backgroundCursorColor: Colors.grey, - selectionControls: materialTextSelectionControls, - keyboardType: TextInputType.text, - textAlign: TextAlign.right, - ), - ), - ), - )); - - await tester.pump(); - - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.end, - ], - shortcutModifier: true, - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - expect( - controller.selection, - equals(const TextSelection.collapsed( - offset: testText.length, - affinity: TextAffinity.upstream, - )), - ); - - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.home, - ], - shortcutModifier: true, - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - expect( - controller.selection, - equals(const TextSelection.collapsed(offset: 0)), - ); - }, - skip: kIsWeb, // [intended] on web these keys are handled by the browser. - variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.windows }) - ); - - testWidgets('control + shift + home/end keys (Windows only)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); - controller.selection = const TextSelection( - baseOffset: 0, - extentOffset: 0, - affinity: TextAffinity.upstream, - ); - await tester.pumpWidget(MaterialApp( - home: Align( - alignment: Alignment.topLeft, - child: SizedBox( - width: 400, - child: EditableText( - maxLines: 10, - controller: controller, - showSelectionHandles: true, - autofocus: true, - focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, - cursorColor: Colors.blue, - backgroundCursorColor: Colors.grey, - selectionControls: materialTextSelectionControls, - keyboardType: TextInputType.text, - textAlign: TextAlign.right, - ), - ), - ), - )); - - await tester.pump(); - - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.end, - ], - shortcutModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - expect( - controller.selection, - equals(const TextSelection( - baseOffset: 0, - extentOffset: testText.length, - )), - ); - - // Collapse the selection at the end. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowRight, - ], - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - expect( - controller.selection, - equals(const TextSelection.collapsed( - offset: testText.length, - affinity: TextAffinity.upstream, - )), - ); - - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.home, - ], - shortcutModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - expect( - controller.selection, - equals(const TextSelection( - baseOffset: testText.length, - extentOffset: 0, - )), - ); - }, - skip: kIsWeb, // [intended] on web these keys are handled by the browser. - variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.windows }) - ); - - // Regression test for https://github.com/flutter/flutter/issues/31287 - testWidgets('text selection handle visibility', (WidgetTester tester) async { - // Text with two separate words to select. - const String testText = 'XXXXX XXXXX'; - final TextEditingController controller = TextEditingController(text: testText); - - await tester.pumpWidget(MaterialApp( - home: Align( - alignment: Alignment.topLeft, - child: SizedBox( - width: 100, - child: EditableText( - showSelectionHandles: true, - controller: controller, - focusNode: FocusNode(), - style: Typography.material2018(platform: TargetPlatform.iOS).black.subtitle1!, - cursorColor: Colors.blue, - backgroundCursorColor: Colors.grey, - selectionControls: cupertinoTextSelectionControls, - keyboardType: TextInputType.text, - ), - ), - ), - )); - - final EditableTextState state = - tester.state<EditableTextState>(find.byType(EditableText)); - final RenderEditable renderEditable = state.renderEditable; - final Scrollable scrollable = tester.widget<Scrollable>(find.byType(Scrollable)); - - bool expectedLeftVisibleBefore = false; - bool expectedRightVisibleBefore = false; - - Future<void> verifyVisibility( - HandlePositionInViewport leftPosition, - bool expectedLeftVisible, - HandlePositionInViewport rightPosition, - bool expectedRightVisible, - ) async { - await tester.pump(); - - // Check the signal from RenderEditable about whether they're within the - // viewport. + // Check the signal from RenderEditable about whether they're within the + // viewport. expect(renderEditable.selectionStartInViewport.value, equals(expectedLeftVisible)); expect(renderEditable.selectionEndInViewport.value, equals(expectedRightVisible)); @@ -6710,19 +6264,14 @@ void main() { )); await tester.showKeyboard(find.byType(EditableText)); - // TextInput.show should be after TextInput.setEditingState. - // On Android setEditingState triggers an IME restart which may prevent - // the keyboard from showing if the show keyboard request comes before the - // restart. - // See: https://github.com/flutter/flutter/issues/68571. + // TextInput.show should be before TextInput.setEditingState final List<String> logOrder = <String>[ 'TextInput.setClient', + 'TextInput.show', 'TextInput.setEditableSizeAndTransform', 'TextInput.setMarkedTextRect', 'TextInput.setStyle', 'TextInput.setEditingState', - 'TextInput.show', - 'TextInput.requestAutofill', 'TextInput.setEditingState', 'TextInput.show', 'TextInput.setCaretRect', @@ -6733,68 +6282,6 @@ void main() { ); }); - testWidgets( - 'keyboard is requested after setEditingState after switching to a new text field', - (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/68571. - final EditableText editableText1 = EditableText( - showSelectionHandles: true, - maxLines: 2, - controller: TextEditingController(), - focusNode: FocusNode(), - cursorColor: Colors.red, - backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), - keyboardType: TextInputType.text, - ); - - final EditableText editableText2 = EditableText( - showSelectionHandles: true, - maxLines: 2, - controller: TextEditingController(), - focusNode: FocusNode(), - cursorColor: Colors.red, - backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), - keyboardType: TextInputType.text, - ); - - await tester.pumpWidget(MaterialApp( - home: Center( - child: Column( - children: <Widget>[editableText1, editableText2], - ), - ), - )); - - await tester.tap(find.byWidget(editableText1)); - await tester.pumpAndSettle(); - - tester.testTextInput.log.clear(); - await tester.tap(find.byWidget(editableText2)); - await tester.pumpAndSettle(); - - // Send TextInput.show after TextInput.setEditingState. Otherwise - // some Android keyboards ignore the "show keyboard" request, as the - // Android text input plugin restarts the input method when setEditingState - // is sent by the framework. - final List<String> logOrder = <String>[ - 'TextInput.clearClient', - 'TextInput.setClient', - 'TextInput.setEditableSizeAndTransform', - 'TextInput.setMarkedTextRect', - 'TextInput.setStyle', - 'TextInput.setEditingState', - 'TextInput.show', - 'TextInput.requestAutofill', - 'TextInput.setCaretRect', - ]; - expect( - tester.testTextInput.log.map((MethodCall m) => m.method), - logOrder, - ); - }); - testWidgets('setEditingState is not called when text changes', (WidgetTester tester) async { // We shouldn't get a message here because this change is owned by the platform side. const String testText = 'flutter is the best!'; @@ -6824,12 +6311,11 @@ void main() { final List<String> logOrder = <String>[ 'TextInput.setClient', + 'TextInput.show', 'TextInput.setEditableSizeAndTransform', 'TextInput.setMarkedTextRect', 'TextInput.setStyle', 'TextInput.setEditingState', - 'TextInput.show', - 'TextInput.requestAutofill', 'TextInput.setEditingState', 'TextInput.show', 'TextInput.setCaretRect', @@ -6875,12 +6361,11 @@ void main() { final List<String> logOrder = <String>[ 'TextInput.setClient', + 'TextInput.show', 'TextInput.setEditableSizeAndTransform', 'TextInput.setMarkedTextRect', 'TextInput.setStyle', 'TextInput.setEditingState', - 'TextInput.show', - 'TextInput.requestAutofill', 'TextInput.setEditingState', 'TextInput.show', 'TextInput.setCaretRect', @@ -6899,7 +6384,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) { if (newValue.text == 'I will be modified by the formatter.') { @@ -7028,7 +6512,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) { return const TextEditingValue(text: 'Flutter is the best!'); @@ -7108,7 +6591,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final TextEditingController controller = TextEditingController(); @@ -7230,7 +6712,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final TextEditingController controller = TextEditingController(); @@ -8388,11 +7869,11 @@ void main() { testWidgets('can change behavior by overriding text editing shortcuts', (WidgetTester tester) async { const Map<SingleActivator, Intent> testShortcuts = <SingleActivator, Intent>{ - SingleActivator(LogicalKeyboardKey.arrowLeft): ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), - SingleActivator(LogicalKeyboardKey.keyX, control: true): ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), - SingleActivator(LogicalKeyboardKey.keyC, control: true): ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), - SingleActivator(LogicalKeyboardKey.keyV, control: true): ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), - SingleActivator(LogicalKeyboardKey.keyA, control: true): ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), + SingleActivator(LogicalKeyboardKey.arrowLeft): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.keyX, control: true): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.keyC, control: true): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.keyV, control: true): MoveSelectionRightTextIntent(), + SingleActivator(LogicalKeyboardKey.keyA, control: true): MoveSelectionRightTextIntent(), }; final TextEditingController controller = TextEditingController(text: testText); controller.selection = const TextSelection( @@ -8590,7 +8071,7 @@ void main() { }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] testWidgets('navigating multiline text', (WidgetTester tester) async { - const String multilineText = 'word word word\nword word\nword'; // 15 + 10 + 4; + const String multilineText = 'word word word\nword word\nword'; final TextEditingController controller = TextEditingController(text: multilineText); // wo|rd wo|rd controller.selection = const TextSelection( @@ -8639,7 +8120,7 @@ void main() { expect(controller.selection.baseOffset, 17); expect(controller.selection.extentOffset, 24); - // Multiple expandLeftByLine shortcuts only move to the start of the line + // Multiple expandLeftByLine shortcuts only move ot the start of the line // and not to the previous line. await sendKeys( tester, @@ -8653,23 +8134,8 @@ void main() { targetPlatform: defaultTargetPlatform, ); expect(controller.selection.isCollapsed, false); - switch (defaultTargetPlatform) { - // These platforms extend by line. - case TargetPlatform.iOS: - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: - expect(controller.selection.baseOffset, 17); - expect(controller.selection.extentOffset, 15); - break; - - // Mac expands by line. - case TargetPlatform.macOS: - expect(controller.selection.baseOffset, 15); - expect(controller.selection.extentOffset, 24); - break; - } + expect(controller.selection.baseOffset, 15); + expect(controller.selection.extentOffset, 24); // Set the caret to the end of a line. controller.selection = const TextSelection( @@ -8707,8 +8173,8 @@ void main() { targetPlatform: defaultTargetPlatform, ); expect(controller.selection.isCollapsed, false); - expect(controller.selection.baseOffset, 24); - expect(controller.selection.extentOffset, 15); + expect(controller.selection.baseOffset, 15); + expect(controller.selection.extentOffset, 24); // Set the caret to the start of a line. controller.selection = const TextSelection( @@ -8751,15 +8217,12 @@ void main() { // On web, using keyboard for selection is handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets("Mac's expand by line behavior on multiple lines", (WidgetTester tester) async { - const String multilineText = 'word word word\nword word\nword'; // 15 + 10 + 4; - final TextEditingController controller = TextEditingController(text: multilineText); - // word word word - // wo|rd word - // w|ord + testWidgets('expanding selection to start/end', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(text: 'word word word'); + // word wo|rd| word controller.selection = const TextSelection( - baseOffset: 17, - extentOffset: 26, + baseOffset: 7, + extentOffset: 9, affinity: TextAffinity.upstream, ); await tester.pumpWidget(MaterialApp( @@ -8783,351 +8246,17 @@ void main() { await tester.pump(); // Wait for autofocus to take effect. expect(controller.selection.isCollapsed, false); - expect(controller.selection.baseOffset, 17); - expect(controller.selection.extentOffset, 26); + expect(controller.selection.baseOffset, 7); + expect(controller.selection.extentOffset, 9); + + final String targetPlatform = defaultTargetPlatform.toString(); + final String platform = targetPlatform.substring(targetPlatform.indexOf('.') + 1).toLowerCase(); - // Expanding right to the end of the line moves the extent on the second - // selected line. + // Select to the start. await sendKeys( tester, <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowRight, - ], - shift: true, - lineModifier: true, - targetPlatform: defaultTargetPlatform, - ); - expect(controller.selection.isCollapsed, false); - expect(controller.selection.baseOffset, 17); - expect(controller.selection.extentOffset, 29); - - // Expanding right again does nothing. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowRight, - LogicalKeyboardKey.arrowRight, - LogicalKeyboardKey.arrowRight, - ], - shift: true, - lineModifier: true, - targetPlatform: defaultTargetPlatform, - ); - expect(controller.selection.isCollapsed, false); - expect(controller.selection.baseOffset, 17); - expect(controller.selection.extentOffset, 29); - - // Expanding left by line moves the base on the first selected line to the - // beginning of that line. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowLeft, - ], - shift: true, - lineModifier: true, - targetPlatform: defaultTargetPlatform, - ); - expect(controller.selection.isCollapsed, false); - expect(controller.selection.baseOffset, 15); - expect(controller.selection.extentOffset, 29); - - // Expanding left again does nothing. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowLeft, - LogicalKeyboardKey.arrowLeft, - LogicalKeyboardKey.arrowLeft, - ], - shift: true, - lineModifier: true, - targetPlatform: defaultTargetPlatform, - ); - expect(controller.selection.isCollapsed, false); - expect(controller.selection.baseOffset, 15); - expect(controller.selection.extentOffset, 29); - }, - // On web, using keyboard for selection is handled by the browser. - skip: kIsWeb, // [intended] - variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }) - ); - - testWidgets("Mac's expand extent position", (WidgetTester tester) async { - const String testText = 'Now is the time for all good people to come to the aid of their country'; - final TextEditingController controller = TextEditingController(text: testText); - // Start the selection in the middle somewhere. - controller.selection = const TextSelection.collapsed(offset: 10); - await tester.pumpWidget(MaterialApp( - home: Align( - alignment: Alignment.topLeft, - child: SizedBox( - width: 400, - child: EditableText( - maxLines: 10, - controller: controller, - autofocus: true, - focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, - cursorColor: Colors.blue, - backgroundCursorColor: Colors.grey, - keyboardType: TextInputType.text, - ), - ), - ), - )); - - await tester.pump(); // Wait for autofocus to take effect. - expect(controller.selection.isCollapsed, true); - expect(controller.selection.baseOffset, 10); - - // With cursor in the middle of the line, cmd + left. Left end is the extent. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowLeft, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - expect( - controller.selection, - equals( - const TextSelection( - baseOffset: 10, - extentOffset: 0, - affinity: TextAffinity.upstream, - ), - ), - ); - - // With cursor in the middle of the line, cmd + right. Right end is the extent. - controller.selection = const TextSelection.collapsed(offset: 10); - await tester.pump(); - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowRight, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - expect( - controller.selection, - equals( - const TextSelection( - baseOffset: 10, - extentOffset: 29, - affinity: TextAffinity.upstream, - ), - ), - ); - - // With cursor in the middle of the line, cmd + left then cmd + right. Left end is the extent. - controller.selection = const TextSelection.collapsed(offset: 10); - await tester.pump(); - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowLeft, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowRight, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - expect( - controller.selection, - equals( - const TextSelection( - baseOffset: 29, - extentOffset: 0, - affinity: TextAffinity.upstream, - ), - ), - ); - - // With cursor in the middle of the line, cmd + right then cmd + left. Right end is the extent. - controller.selection = const TextSelection.collapsed(offset: 10); - await tester.pump(); - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowRight, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - await tester.pump(); - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowLeft, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - expect( - controller.selection, - equals( - const TextSelection( - baseOffset: 0, - extentOffset: 29, - affinity: TextAffinity.upstream, - ), - ), - ); - - // With an RTL selection in the middle of the line, cmd + left. Left end is the extent. - controller.selection = const TextSelection(baseOffset: 12, extentOffset: 8); - await tester.pump(); - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowLeft, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - expect( - controller.selection, - equals( - const TextSelection( - baseOffset: 12, - extentOffset: 0, - affinity: TextAffinity.upstream, - ), - ), - ); - - // With an RTL selection in the middle of the line, cmd + right. Left end is the extent. - controller.selection = const TextSelection(baseOffset: 12, extentOffset: 8); - await tester.pump(); - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowRight, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - expect( - controller.selection, - equals( - const TextSelection( - baseOffset: 29, - extentOffset: 8, - affinity: TextAffinity.upstream, - ), - ), - ); - - // With an LTR selection in the middle of the line, cmd + right. Right end is the extent. - controller.selection = const TextSelection(baseOffset: 8, extentOffset: 12); - await tester.pump(); - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowRight, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - expect( - controller.selection, - equals( - const TextSelection( - baseOffset: 8, - extentOffset: 29, - affinity: TextAffinity.upstream, - ), - ), - ); - - // With an LTR selection in the middle of the line, cmd + left. Right end is the extent. - controller.selection = const TextSelection(baseOffset: 8, extentOffset: 12); - await tester.pump(); - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.arrowLeft, - ], - lineModifier: true, - shift: true, - targetPlatform: defaultTargetPlatform, - ); - expect( - controller.selection, - equals( - const TextSelection( - baseOffset: 0, - extentOffset: 12, - affinity: TextAffinity.upstream, - ), - ), - ); - }, - // On web, using keyboard for selection is handled by the browser. - skip: kIsWeb, // [intended] - variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }) - ); - - testWidgets('expanding selection to start/end', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'word word word'); - // word wo|rd| word - controller.selection = const TextSelection( - baseOffset: 7, - extentOffset: 9, - affinity: TextAffinity.upstream, - ); - await tester.pumpWidget(MaterialApp( - home: Align( - alignment: Alignment.topLeft, - child: SizedBox( - width: 400, - child: EditableText( - maxLines: 10, - controller: controller, - autofocus: true, - focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, - cursorColor: Colors.blue, - backgroundCursorColor: Colors.grey, - keyboardType: TextInputType.text, - ), - ), - ), - )); - - await tester.pump(); // Wait for autofocus to take effect. - expect(controller.selection.isCollapsed, false); - expect(controller.selection.baseOffset, 7); - expect(controller.selection.extentOffset, 9); - - final String targetPlatform = defaultTargetPlatform.toString(); - final String platform = targetPlatform.substring(targetPlatform.indexOf('.') + 1).toLowerCase(); - - // Select to the start. - await sendKeys( - tester, - <LogicalKeyboardKey>[ - LogicalKeyboardKey.home, + LogicalKeyboardKey.home, ], shift: true, targetPlatform: defaultTargetPlatform, @@ -9138,7 +8267,7 @@ void main() { controller.selection, equals( const TextSelection( - baseOffset: 7, + baseOffset: 9, extentOffset: 0, affinity: TextAffinity.upstream, ), @@ -9161,7 +8290,7 @@ void main() { controller.selection, equals( const TextSelection( - baseOffset: 7, + baseOffset: 9, extentOffset: 0, affinity: TextAffinity.upstream, ), @@ -9175,7 +8304,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }) ); - testWidgets('can change text editing behavior by overriding actions', (WidgetTester tester) async { + testWidgets('can change behavior by overriding text editing actions', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(text: testText); controller.selection = const TextSelection( baseOffset: 0, @@ -9183,16 +8312,34 @@ void main() { affinity: TextAffinity.upstream, ); bool myIntentWasCalled = false; - final CallbackAction<ExtendSelectionByCharacterIntent> overrideAction = CallbackAction<ExtendSelectionByCharacterIntent>( - onInvoke: (ExtendSelectionByCharacterIntent intent) { myIntentWasCalled = true; return null; }, + final _MyMoveSelectionRightTextAction myMoveSelectionRightTextAction = + _MyMoveSelectionRightTextAction( + onInvoke: () { + myIntentWasCalled = true; + }, ); + const Iterable<SingleActivator> testSingleActivators = <SingleActivator>{ + SingleActivator(LogicalKeyboardKey.arrowLeft), + SingleActivator(LogicalKeyboardKey.keyX, control: true), + SingleActivator(LogicalKeyboardKey.keyC, control: true), + SingleActivator(LogicalKeyboardKey.keyV, control: true), + SingleActivator(LogicalKeyboardKey.keyA, control: true), + }; + + final Map<Type, Action<Intent>> testActions = <Type, Action<Intent>>{ + MoveSelectionLeftTextIntent: myMoveSelectionRightTextAction, + CutSelectionTextIntent: myMoveSelectionRightTextAction, + CopySelectionTextIntent: myMoveSelectionRightTextAction, + PasteTextIntent: myMoveSelectionRightTextAction, + SelectAllTextIntent: myMoveSelectionRightTextAction, + }; await tester.pumpWidget(MaterialApp( home: Align( alignment: Alignment.topLeft, child: SizedBox( width: 400, child: Actions( - actions: <Type, Action<Intent>>{ ExtendSelectionByCharacterIntent: overrideAction, }, + actions: testActions, child: EditableText( maxLines: 10, controller: controller, @@ -9210,13 +8357,32 @@ void main() { ), ), )); + await tester.pump(); // Wait for autofocus to take effect. + // The right arrow key moves to the right as usual. await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); await tester.pump(); expect(controller.selection.isCollapsed, isTrue); - expect(controller.selection.baseOffset, 0); - expect(myIntentWasCalled, isTrue); + expect(controller.selection.baseOffset, 1); + expect(myIntentWasCalled, isFalse); + + // And the testSingleActivators also moves to the right due to the Shortcuts override. + for (final SingleActivator singleActivator in testSingleActivators) { + myIntentWasCalled = false; + controller.selection = const TextSelection.collapsed(offset: 0); + await tester.pump(); + + await sendKeys( + tester, + <LogicalKeyboardKey>[singleActivator.trigger], + shortcutModifier: singleActivator.control, + targetPlatform: defaultTargetPlatform, + ); + expect(controller.selection.isCollapsed, isTrue); + expect(controller.selection.baseOffset, 1); + expect(myIntentWasCalled, isTrue); + } // On web, using keyboard for selection is handled by the browser. }, skip: kIsWeb); // [intended] @@ -9238,8 +8404,10 @@ void main() { width: 400, child: Actions( actions: <Type, Action<Intent>>{ - ExtendSelectionByCharacterIntent: CallbackAction<ExtendSelectionByCharacterIntent>( - onInvoke: (ExtendSelectionByCharacterIntent intent) { myIntentWasCalled = true; return null; }, + MoveSelectionRightTextIntent: _MyMoveSelectionRightTextAction( + onInvoke: () { + myIntentWasCalled = true; + }, ), }, child: EditableText( @@ -9273,7 +8441,7 @@ void main() { await tester.pump(); expect(myIntentWasCalled, isTrue); expect(controller.selection.isCollapsed, true); - expect(controller.selection.baseOffset, 0); + expect(controller.selection.baseOffset, 1); } }, variant: KeySimulatorTransitModeVariant.all()); @@ -9467,53 +8635,6 @@ void main() { await tester.pump(); expect(scrollController.offset.roundToDouble(), 0.0); }); - - testWidgets('Autofill enabled by default', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget( - MaterialApp( - home: EditableText( - autofocus: true, - controller: TextEditingController(text: 'A'), - focusNode: focusNode, - style: textStyle, - cursorColor: Colors.blue, - backgroundCursorColor: Colors.grey, - cursorOpacityAnimates: true, - ), - ), - ); - - assert(focusNode.hasFocus); - expect( - tester.testTextInput.log, - contains(matchesMethodCall('TextInput.requestAutofill')), - ); - }); - - testWidgets('Autofill can be disabled', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget( - MaterialApp( - home: EditableText( - autofocus: true, - controller: TextEditingController(text: 'A'), - focusNode: focusNode, - style: textStyle, - cursorColor: Colors.blue, - backgroundCursorColor: Colors.grey, - cursorOpacityAnimates: true, - autofillHints: null, - ), - ), - ); - - assert(focusNode.hasFocus); - expect( - tester.testTextInput.log, - isNot(contains(matchesMethodCall('TextInput.requestAutofill'))), - ); - }); } class UnsettableController extends TextEditingController { @@ -9739,6 +8860,20 @@ class _AccentColorTextEditingController extends TextEditingController { } } +class _MyMoveSelectionRightTextAction extends TextEditingAction<Intent> { + _MyMoveSelectionRightTextAction({ + required this.onInvoke, + }) : super(); + + final VoidCallback onInvoke; + + @override + Object? invoke(Intent intent, [BuildContext? context]) { + textEditingActionTarget!.moveSelectionRight(SelectionChangedCause.keyboard); + onInvoke(); + } +} + class _TestScrollController extends ScrollController { bool get attached => hasListeners; } diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index 052bd88734462..c7c1d3d655037 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -151,70 +151,6 @@ void main() { expect(scope.traversalDescendants.contains(child2), isFalse); }); - testWidgets('descendantsAreTraversable disables traversal for descendants.', (WidgetTester tester) async { - final BuildContext context = await setupWidget(tester); - final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); - final FocusAttachment scopeAttachment = scope.attach(context); - final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1'); - final FocusAttachment parent1Attachment = parent1.attach(context); - final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2'); - final FocusAttachment parent2Attachment = parent2.attach(context); - final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); - final FocusAttachment child1Attachment = child1.attach(context); - final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); - final FocusAttachment child2Attachment = child2.attach(context); - - scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); - parent1Attachment.reparent(parent: scope); - parent2Attachment.reparent(parent: scope); - child1Attachment.reparent(parent: parent1); - child2Attachment.reparent(parent: parent2); - - expect(scope.traversalDescendants, equals(<FocusNode>[child1, parent1, child2, parent2])); - - parent2.descendantsAreTraversable = false; - expect(scope.traversalDescendants, equals(<FocusNode>[child1, parent1, parent2])); - - parent1.descendantsAreTraversable = false; - expect(scope.traversalDescendants, equals(<FocusNode>[parent1, parent2])); - - parent1.descendantsAreTraversable = true; - parent2.descendantsAreTraversable = true; - scope.descendantsAreTraversable = false; - expect(scope.traversalDescendants, equals(<FocusNode>[])); - }); - - testWidgets("canRequestFocus doesn't affect traversalChildren", (WidgetTester tester) async { - final BuildContext context = await setupWidget(tester); - final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); - final FocusAttachment scopeAttachment = scope.attach(context); - final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1'); - final FocusAttachment parent1Attachment = parent1.attach(context); - final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2'); - final FocusAttachment parent2Attachment = parent2.attach(context); - final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); - final FocusAttachment child1Attachment = child1.attach(context); - final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); - final FocusAttachment child2Attachment = child2.attach(context); - scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); - parent1Attachment.reparent(parent: scope); - parent2Attachment.reparent(parent: scope); - child1Attachment.reparent(parent: parent1); - child2Attachment.reparent(parent: parent2); - child1.requestFocus(); - await tester.pump(); - - expect(tester.binding.focusManager.primaryFocus, equals(child1)); - expect(scope.focusedChild, equals(child1)); - expect(parent2.traversalChildren.contains(child2), isTrue); - expect(scope.traversalChildren.contains(parent2), isTrue); - - parent2.canRequestFocus = false; - await tester.pump(); - expect(parent2.traversalChildren.contains(child2), isTrue); - expect(scope.traversalChildren.contains(parent2), isFalse); - }); - testWidgets('implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); FocusNode( @@ -224,7 +160,6 @@ void main() { expect(description, <String>[ 'context: null', 'descendantsAreFocusable: true', - 'descendantsAreTraversable: true', 'canRequestFocus: true', 'hasFocus: false', 'hasPrimaryFocus: false', @@ -567,8 +502,6 @@ void main() { expect(scope.focusedChild, equals(child1)); expect(scope.traversalDescendants.contains(child1), isTrue); expect(scope.traversalDescendants.contains(child2), isTrue); - expect(scope.traversalChildren.contains(parent1), isTrue); - expect(parent1.traversalChildren.contains(child2), isTrue); scope.canRequestFocus = false; await tester.pump(); @@ -579,8 +512,6 @@ void main() { expect(scope.focusedChild, equals(child1)); expect(scope.traversalDescendants.contains(child1), isFalse); expect(scope.traversalDescendants.contains(child2), isFalse); - expect(scope.traversalChildren.contains(parent1), isFalse); - expect(parent1.traversalChildren.contains(child2), isFalse); }); testWidgets("skipTraversal doesn't affect children.", (WidgetTester tester) async { @@ -1190,7 +1121,6 @@ void main() { expect(description, <String>[ 'context: null', 'descendantsAreFocusable: true', - 'descendantsAreTraversable: true', 'canRequestFocus: true', 'hasFocus: false', 'hasPrimaryFocus: false', diff --git a/packages/flutter/test/widgets/focus_scope_test.dart b/packages/flutter/test/widgets/focus_scope_test.dart index 892031481acdc..a8b05f9722cf3 100644 --- a/packages/flutter/test/widgets/focus_scope_test.dart +++ b/packages/flutter/test/widgets/focus_scope_test.dart @@ -1085,7 +1085,6 @@ void main() { focusScopeNode.onKey = ignoreCallback; focusScopeNode.onKeyEvent = ignoreEventCallback; focusScopeNode.descendantsAreFocusable = false; - focusScopeNode.descendantsAreTraversable = false; focusScopeNode.skipTraversal = false; focusScopeNode.canRequestFocus = true; FocusScope focusScopeWidget = FocusScope.withExternalFocusNode( @@ -1096,13 +1095,11 @@ void main() { expect(focusScopeNode.onKey, equals(ignoreCallback)); expect(focusScopeNode.onKeyEvent, equals(ignoreEventCallback)); expect(focusScopeNode.descendantsAreFocusable, isFalse); - expect(focusScopeNode.descendantsAreTraversable, isFalse); expect(focusScopeNode.skipTraversal, isFalse); expect(focusScopeNode.canRequestFocus, isTrue); expect(focusScopeWidget.onKey, equals(focusScopeNode.onKey)); expect(focusScopeWidget.onKeyEvent, equals(focusScopeNode.onKeyEvent)); expect(focusScopeWidget.descendantsAreFocusable, equals(focusScopeNode.descendantsAreFocusable)); - expect(focusScopeWidget.descendantsAreTraversable, equals(focusScopeNode.descendantsAreTraversable)); expect(focusScopeWidget.skipTraversal, equals(focusScopeNode.skipTraversal)); expect(focusScopeWidget.canRequestFocus, equals(focusScopeNode.canRequestFocus)); @@ -1114,7 +1111,6 @@ void main() { focusScopeNode.onKey = handleCallback; focusScopeNode.onKeyEvent = handleEventCallback; focusScopeNode.descendantsAreFocusable = true; - focusScopeNode.descendantsAreTraversable = true; focusScopeWidget = FocusScope.withExternalFocusNode( focusScopeNode: focusScopeNode, child: Container(key: key1), @@ -1123,13 +1119,11 @@ void main() { expect(focusScopeNode.onKey, equals(handleCallback)); expect(focusScopeNode.onKeyEvent, equals(handleEventCallback)); expect(focusScopeNode.descendantsAreFocusable, isTrue); - expect(focusScopeNode.descendantsAreTraversable, isTrue); expect(focusScopeNode.skipTraversal, isFalse); expect(focusScopeNode.canRequestFocus, isTrue); expect(focusScopeWidget.onKey, equals(focusScopeNode.onKey)); expect(focusScopeWidget.onKeyEvent, equals(focusScopeNode.onKeyEvent)); expect(focusScopeWidget.descendantsAreFocusable, equals(focusScopeNode.descendantsAreFocusable)); - expect(focusScopeWidget.descendantsAreTraversable, equals(focusScopeNode.descendantsAreTraversable)); expect(focusScopeWidget.skipTraversal, equals(focusScopeNode.skipTraversal)); expect(focusScopeWidget.canRequestFocus, equals(focusScopeNode.canRequestFocus)); @@ -1645,47 +1639,12 @@ void main() { expect(containerNode.hasFocus, isFalse); expect(unfocusableNode.hasFocus, isFalse); }); - - testWidgets('descendantsAreTraversable works as expected.', (WidgetTester tester) async { - final FocusScopeNode scopeNode = FocusScopeNode(debugLabel: 'scope'); - final FocusNode node1 = FocusNode(debugLabel: 'node 1'); - final FocusNode node2 = FocusNode(debugLabel: 'node 2'); - final FocusNode node3 = FocusNode(debugLabel: 'node 3'); - - await tester.pumpWidget( - FocusScope( - node: scopeNode, - child: Column( - children: <Widget>[ - Focus( - focusNode: node1, - child: Container(), - ), - Focus( - focusNode: node2, - descendantsAreTraversable: false, - child: Focus( - focusNode: node3, - child: Container(), - ) - ), - ], - ), - ), - ); - await tester.pump(); - - expect(scopeNode.traversalDescendants, equals(<FocusNode>[node1, node2])); - expect(node2.traversalDescendants, equals(<FocusNode>[])); - }); - testWidgets("Focus doesn't introduce a Semantics node when includeSemantics is false", (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Focus(includeSemantics: false, child: Container())); final TestSemantics expectedSemantics = TestSemantics.root(); expect(semantics, hasSemantics(expectedSemantics)); }); - testWidgets('Focus updates the onKey handler when the widget updates', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode focusNode = FocusNode(); @@ -1736,7 +1695,6 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.enter); expect(keyEventHandled, isTrue); }); - testWidgets('Focus updates the onKeyEvent handler when the widget updates', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode focusNode = FocusNode(); @@ -1787,7 +1745,6 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.enter); expect(keyEventHandled, isTrue); }); - testWidgets("Focus doesn't update the focusNode attributes when the widget updates if withExternalFocusNode is used", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode focusNode = FocusNode(); @@ -1809,7 +1766,6 @@ void main() { focusNode.onKey = ignoreCallback; focusNode.onKeyEvent = ignoreEventCallback; focusNode.descendantsAreFocusable = false; - focusNode.descendantsAreTraversable = false; focusNode.skipTraversal = false; focusNode.canRequestFocus = true; Focus focusWidget = Focus.withExternalFocusNode( @@ -1820,13 +1776,11 @@ void main() { expect(focusNode.onKey, equals(ignoreCallback)); expect(focusNode.onKeyEvent, equals(ignoreEventCallback)); expect(focusNode.descendantsAreFocusable, isFalse); - expect(focusNode.descendantsAreTraversable, isFalse); expect(focusNode.skipTraversal, isFalse); expect(focusNode.canRequestFocus, isTrue); expect(focusWidget.onKey, equals(focusNode.onKey)); expect(focusWidget.onKeyEvent, equals(focusNode.onKeyEvent)); expect(focusWidget.descendantsAreFocusable, equals(focusNode.descendantsAreFocusable)); - expect(focusWidget.descendantsAreTraversable, equals(focusNode.descendantsAreTraversable)); expect(focusWidget.skipTraversal, equals(focusNode.skipTraversal)); expect(focusWidget.canRequestFocus, equals(focusNode.canRequestFocus)); @@ -1838,7 +1792,6 @@ void main() { focusNode.onKey = handleCallback; focusNode.onKeyEvent = handleEventCallback; focusNode.descendantsAreFocusable = true; - focusNode.descendantsAreTraversable = true; focusWidget = Focus.withExternalFocusNode( focusNode: focusNode, child: Container(key: key1), @@ -1847,29 +1800,18 @@ void main() { expect(focusNode.onKey, equals(handleCallback)); expect(focusNode.onKeyEvent, equals(handleEventCallback)); expect(focusNode.descendantsAreFocusable, isTrue); - expect(focusNode.descendantsAreTraversable, isTrue); expect(focusNode.skipTraversal, isFalse); expect(focusNode.canRequestFocus, isTrue); expect(focusWidget.onKey, equals(focusNode.onKey)); expect(focusWidget.onKeyEvent, equals(focusNode.onKeyEvent)); expect(focusWidget.descendantsAreFocusable, equals(focusNode.descendantsAreFocusable)); - expect(focusWidget.descendantsAreTraversable, equals(focusNode.descendantsAreTraversable)); expect(focusWidget.skipTraversal, equals(focusNode.skipTraversal)); expect(focusWidget.canRequestFocus, equals(focusNode.canRequestFocus)); await tester.sendKeyEvent(LogicalKeyboardKey.enter); expect(keyEventHandled, isTrue); }); - - testWidgets('Focus passes changes in attribute values to its focus node', (WidgetTester tester) async { - await tester.pumpWidget( - Focus( - child: Container(), - ), - ); - }); }); - group('ExcludeFocus', () { testWidgets("Descendants of ExcludeFocus aren't focusable.", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); @@ -1977,43 +1919,11 @@ void main() { expect(parentFocusNode.hasFocus, isFalse); expect(parentFocusNode.enclosingScope!.hasPrimaryFocus, isTrue); }); - testWidgets("ExcludeFocus doesn't introduce a Semantics node", (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(ExcludeFocus(child: Container())); final TestSemantics expectedSemantics = TestSemantics.root(); expect(semantics, hasSemantics(expectedSemantics)); }); - - // Regression test for https://github.com/flutter/flutter/issues/92693 - testWidgets('Setting parent FocusScope.canRequestFocus to false, does not set descendant Focus._internalNode._canRequestFocus to false', (WidgetTester tester) async { - final FocusNode childFocusNode = FocusNode(debugLabel: 'node 1'); - - Widget buildFocusTree({required bool parentCanRequestFocus}) { - return FocusScope( - canRequestFocus: parentCanRequestFocus, - child: Column( - children: <Widget>[ - Focus( - focusNode: childFocusNode, - child: Container(), - ), - ], - ), - ); - } - - // childFocusNode.canRequestFocus is true when parent canRequestFocus is true - await tester.pumpWidget(buildFocusTree(parentCanRequestFocus: true)); - expect(childFocusNode.canRequestFocus, isTrue); - - // childFocusNode.canRequestFocus is false when parent canRequestFocus is false - await tester.pumpWidget(buildFocusTree(parentCanRequestFocus: false)); - expect(childFocusNode.canRequestFocus, isFalse); - - // childFocusNode.canRequestFocus is true again when parent canRequestFocus is changed back to true - await tester.pumpWidget(buildFocusTree(parentCanRequestFocus: true)); - expect(childFocusNode.canRequestFocus, isTrue); - }); }); } diff --git a/packages/flutter/test/widgets/focus_traversal_test.dart b/packages/flutter/test/widgets/focus_traversal_test.dart index ff4c6e8054bfb..af77ebd0293ea 100644 --- a/packages/flutter/test/widgets/focus_traversal_test.dart +++ b/packages/flutter/test/widgets/focus_traversal_test.dart @@ -2054,7 +2054,6 @@ void main() { final TestSemantics expectedSemantics = TestSemantics.root(); expect(semantics, hasSemantics(expectedSemantics)); }); - testWidgets("Descendants of FocusTraversalGroup aren't focusable if descendantsAreFocusable is false.", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); @@ -2093,78 +2092,6 @@ void main() { expect(containerNode.hasFocus, isFalse); expect(unfocusableNode.hasFocus, isFalse); }); - - testWidgets("Descendants of FocusTraversalGroup aren't traversable if descendantsAreTraversable is false.", (WidgetTester tester) async { - final FocusNode node1 = FocusNode(); - final FocusNode node2 = FocusNode(); - - await tester.pumpWidget( - FocusTraversalGroup( - descendantsAreTraversable: false, - child: Column( - children: <Widget>[ - Focus( - focusNode: node1, - child: Container(), - ), - Focus( - focusNode: node2, - child: Container(), - ), - ], - ), - ), - ); - - node1.requestFocus(); - await tester.pump(); - - expect(node1.hasPrimaryFocus, isTrue); - expect(node2.hasPrimaryFocus, isFalse); - - expect(primaryFocus!.nextFocus(), isFalse); - await tester.pump(); - - expect(node1.hasPrimaryFocus, isTrue); - expect(node2.hasPrimaryFocus, isFalse); - }); - - testWidgets("FocusTraversalGroup with skipTraversal for all descendents set to true doesn't cause an exception.", (WidgetTester tester) async { - final FocusNode node1 = FocusNode(); - final FocusNode node2 = FocusNode(); - - await tester.pumpWidget( - FocusTraversalGroup( - child: Column( - children: <Widget>[ - Focus( - skipTraversal: true, - focusNode: node1, - child: Container(), - ), - Focus( - skipTraversal: true, - focusNode: node2, - child: Container(), - ), - ], - ), - ), - ); - - node1.requestFocus(); - await tester.pump(); - - expect(node1.hasPrimaryFocus, isTrue); - expect(node2.hasPrimaryFocus, isFalse); - - expect(primaryFocus!.nextFocus(), isFalse); - await tester.pump(); - - expect(node1.hasPrimaryFocus, isTrue); - expect(node2.hasPrimaryFocus, isFalse); - }); - testWidgets("Nested FocusTraversalGroup with unfocusable children doesn't assert.", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); @@ -2213,7 +2140,6 @@ void main() { expect(containerNode.hasFocus, isFalse); expect(unfocusableNode.hasFocus, isFalse); }); - testWidgets("Empty FocusTraversalGroup doesn't cause an exception.", (WidgetTester tester) async { final GlobalKey key = GlobalKey(debugLabel: 'Test Key'); final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); @@ -2243,7 +2169,6 @@ void main() { expect(primaryFocus, equals(focusNode)); }); }); - group(RawKeyboardListener, () { testWidgets('Raw keyboard listener introduces a Semantics node by default', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); @@ -2270,7 +2195,6 @@ void main() { ignoreTransform: true, )); }); - testWidgets("Raw keyboard listener doesn't introduce a Semantics node when specified", (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final FocusNode focusNode = FocusNode(); @@ -2285,63 +2209,6 @@ void main() { expect(semantics, hasSemantics(expectedSemantics)); }); }); - - group(ExcludeFocusTraversal, () { - testWidgets("Descendants aren't traversable", (WidgetTester tester) async { - final FocusNode node1 = FocusNode(debugLabel: 'node 1'); - final FocusNode node2 = FocusNode(debugLabel: 'node 2'); - final FocusNode node3 = FocusNode(debugLabel: 'node 3'); - final FocusNode node4 = FocusNode(debugLabel: 'node 4'); - - await tester.pumpWidget( - FocusTraversalGroup( - child: Column( - children: <Widget>[ - Focus( - autofocus: true, - focusNode: node1, - child: Container(), - ), - ExcludeFocusTraversal( - child: Focus( - focusNode: node2, - child: Focus( - focusNode: node3, - child: Container(), - ), - ), - ), - Focus( - focusNode: node4, - child: Container(), - ), - ], - ), - ), - ); - await tester.pump(); - - expect(node1.hasPrimaryFocus, isTrue); - expect(node2.hasPrimaryFocus, isFalse); - expect(node3.hasPrimaryFocus, isFalse); - expect(node4.hasPrimaryFocus, isFalse); - - node1.nextFocus(); - await tester.pump(); - - expect(node1.hasPrimaryFocus, isFalse); - expect(node2.hasPrimaryFocus, isFalse); - expect(node3.hasPrimaryFocus, isFalse); - expect(node4.hasPrimaryFocus, isTrue); - }); - - testWidgets("Doesn't introduce a Semantics node", (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget(ExcludeFocusTraversal(child: Container())); - final TestSemantics expectedSemantics = TestSemantics.root(); - expect(semantics, hasSemantics(expectedSemantics)); - }); - }); } class TestRoute extends PageRouteBuilder<void> { diff --git a/packages/flutter/test/widgets/framework_test.dart b/packages/flutter/test/widgets/framework_test.dart index 23f9c370a125b..ba4c9e8a23e29 100644 --- a/packages/flutter/test/widgets/framework_test.dart +++ b/packages/flutter/test/widgets/framework_test.dart @@ -1656,21 +1656,6 @@ The findRenderObject() method was called for the following element: )), ); }); - - testWidgets('Elements use the identity hashCode', (WidgetTester tester) async { - final StatefulElement statefulElement = StatefulElement(const _StatefulLeaf()); - expect(statefulElement.hashCode, identityHashCode(statefulElement)); - - final StatelessElement statelessElement = StatelessElement(const Placeholder()); - - expect(statelessElement.hashCode, identityHashCode(statelessElement)); - - final InheritedElement inheritedElement = InheritedElement( - const Directionality(textDirection: TextDirection.ltr, child: Placeholder()), - ); - - expect(inheritedElement.hashCode, identityHashCode(inheritedElement)); - }); } class _WidgetWithNoVisitChildren extends StatelessWidget { diff --git a/packages/flutter/test/widgets/image_filter_quality_test.dart b/packages/flutter/test/widgets/image_filter_quality_test.dart index aa6232ba126a8..1bacdb1abb23e 100644 --- a/packages/flutter/test/widgets/image_filter_quality_test.dart +++ b/packages/flutter/test/widgets/image_filter_quality_test.dart @@ -72,6 +72,8 @@ Future<void> testImageQuality(WidgetTester tester, ui.FilterQuality? quality) as } class _TestImageStreamCompleter extends ImageStreamCompleter { + _TestImageStreamCompleter([this._currentImage]); + ImageInfo? _currentImage; final Set<ImageStreamListener> listeners = <ImageStreamListener>{}; diff --git a/packages/flutter/test/widgets/image_test.dart b/packages/flutter/test/widgets/image_test.dart index a2866981bbece..04c7cafae2077 100644 --- a/packages/flutter/test/widgets/image_test.dart +++ b/packages/flutter/test/widgets/image_test.dart @@ -7,7 +7,6 @@ @Tags(<String>['reduced-test-set']) import 'dart:async'; -import 'dart:io'; import 'dart:math' as math; import 'dart:typed_data'; import 'dart:ui' as ui; @@ -1957,22 +1956,6 @@ void main() { matchesGoldenFile('image_test.missing.2.png'), ); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/74935 (broken assets not being reported on web) - - testWidgets('Image.file throws a non-implemented error on web', (WidgetTester tester) async { - const String expectedError = - 'Image.file is not supported on Flutter Web. ' - 'Consider using either Image.asset or Image.network instead.'; - final Uri uri = Uri.parse('/home/flutter/dash.png'); - final File file = File.fromUri(uri); - expect( - () => Image.file(file), - kIsWeb - // Web does not support file access, expect AssertionError - ? throwsA(predicate((AssertionError e) => e.message == expectedError)) - // AOT supports file access, expect constructor to succeed - : isNot(throwsA(anything)), - ); - }); } @immutable diff --git a/packages/flutter/test/widgets/interactive_viewer_test.dart b/packages/flutter/test/widgets/interactive_viewer_test.dart index a9764e2b60ccb..a10aa9d3f502c 100644 --- a/packages/flutter/test/widgets/interactive_viewer_test.dart +++ b/packages/flutter/test/widgets/interactive_viewer_test.dart @@ -1311,86 +1311,6 @@ void main() { expect(find.byType(LayoutBuilder), findsOneWidget); }); - - testWidgets('scaleFactor', (WidgetTester tester) async { - const double scrollAmount = 30.0; - final TransformationController transformationController = TransformationController(); - Future<void> pumpScaleFactor(double scaleFactor) { - return tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: InteractiveViewer( - boundaryMargin: const EdgeInsets.all(double.infinity), - transformationController: transformationController, - scaleFactor: scaleFactor, - child: const SizedBox(width: 200.0, height: 200.0), - ), - ), - ), - ), - ); - } - - // Start with the default scaleFactor. - await pumpScaleFactor(200.0); - - expect(transformationController.value, equals(Matrix4.identity())); - - // Zoom out. The scale decreases. - final Offset center = tester.getCenter(find.byType(InteractiveViewer)); - await scrollAt(center, tester, const Offset(0.0, scrollAmount)); - await tester.pumpAndSettle(); - final double scaleZoomedOut = transformationController.value.getMaxScaleOnAxis(); - expect(scaleZoomedOut, lessThan(1.0)); - - // Zoom in. The scale increases. - await scrollAt(center, tester, const Offset(0.0, -scrollAmount)); - await tester.pumpAndSettle(); - final double scaleZoomedIn = transformationController.value.getMaxScaleOnAxis(); - expect(scaleZoomedIn, greaterThan(scaleZoomedOut)); - - // Reset and decrease the scaleFactor below the default, so that scaling - // will happen more quickly. - transformationController.value = Matrix4.identity(); - await pumpScaleFactor(100.0); - - // Zoom out. The scale decreases more quickly than with the default - // (higher) scaleFactor. - await scrollAt(center, tester, const Offset(0.0, scrollAmount)); - await tester.pumpAndSettle(); - final double scaleLowZoomedOut = transformationController.value.getMaxScaleOnAxis(); - expect(scaleLowZoomedOut, lessThan(1.0)); - expect(scaleLowZoomedOut, lessThan(scaleZoomedOut)); - - // Zoom in. The scale increases more quickly than with the default - // (higher) scaleFactor. - await scrollAt(center, tester, const Offset(0.0, -scrollAmount)); - await tester.pumpAndSettle(); - final double scaleLowZoomedIn = transformationController.value.getMaxScaleOnAxis(); - expect(scaleLowZoomedIn, greaterThan(scaleLowZoomedOut)); - expect(scaleLowZoomedIn - scaleLowZoomedOut, greaterThan(scaleZoomedIn - scaleZoomedOut)); - - // Reset and increase the scaleFactor above the default. - transformationController.value = Matrix4.identity(); - await pumpScaleFactor(400.0); - - // Zoom out. The scale decreases, but not by as much as with the default - // (higher) scaleFactor. - await scrollAt(center, tester, const Offset(0.0, scrollAmount)); - await tester.pumpAndSettle(); - final double scaleHighZoomedOut = transformationController.value.getMaxScaleOnAxis(); - expect(scaleHighZoomedOut, lessThan(1.0)); - expect(scaleHighZoomedOut, greaterThan(scaleZoomedOut)); - - // Zoom in. The scale increases, but not by as much as with the default - // (higher) scaleFactor. - await scrollAt(center, tester, const Offset(0.0, -scrollAmount)); - await tester.pumpAndSettle(); - final double scaleHighZoomedIn = transformationController.value.getMaxScaleOnAxis(); - expect(scaleHighZoomedIn, greaterThan(scaleHighZoomedOut)); - expect(scaleHighZoomedIn - scaleHighZoomedOut, lessThan(scaleZoomedIn - scaleZoomedOut)); - }); }); group('getNearestPointOnLine', () { diff --git a/packages/flutter/test/widgets/keep_alive_test.dart b/packages/flutter/test/widgets/keep_alive_test.dart index 2a3bdf30eaac6..b276ee938e85a 100644 --- a/packages/flutter/test/widgets/keep_alive_test.dart +++ b/packages/flutter/test/widgets/keep_alive_test.dart @@ -226,11 +226,6 @@ void main() { ' │ parentData: <none> (can use size)\n' ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n' ' │ size: Size(800.0, 600.0)\n' - ' │ painter: null\n' - ' │ foregroundPainter:\n' - ' │ _GlowingOverscrollIndicatorPainter(_GlowController(color:\n' - ' │ Color(0xffffffff), axis: vertical), _GlowController(color:\n' - ' │ Color(0xffffffff), axis: vertical))\n' ' │\n' ' └─child: RenderRepaintBoundary#00000\n' ' │ needs compositing\n' @@ -327,9 +322,6 @@ void main() { ' │ parentData: <none> (can use size)\n' ' │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ size: Size(800.0, 400.0)\n' - ' │ painter: null\n' - ' │ foregroundPainter: _PlaceholderPainter#00000()\n' - ' │ preferredSize: Size(Infinity, Infinity)\n' ' │\n' ' ├─child with index 1: RenderLimitedBox#00000\n' // <----- no dashed line starts here ' │ │ parentData: index=1; layoutOffset=400.0\n' @@ -342,9 +334,6 @@ void main() { ' │ parentData: <none> (can use size)\n' ' │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ size: Size(800.0, 400.0)\n' - ' │ painter: null\n' - ' │ foregroundPainter: _PlaceholderPainter#00000()\n' - ' │ preferredSize: Size(Infinity, Infinity)\n' ' │\n' ' └─child with index 2: RenderLimitedBox#00000 NEEDS-PAINT\n' ' │ parentData: index=2; layoutOffset=800.0\n' @@ -356,10 +345,7 @@ void main() { ' └─child: RenderCustomPaint#00000 NEEDS-PAINT\n' ' parentData: <none> (can use size)\n' ' constraints: BoxConstraints(w=800.0, h=400.0)\n' - ' size: Size(800.0, 400.0)\n' - ' painter: null\n' - ' foregroundPainter: _PlaceholderPainter#00000()\n' - ' preferredSize: Size(Infinity, Infinity)\n', + ' size: Size(800.0, 400.0)\n', )); const GlobalObjectKey<_LeafState>(0).currentState!.setKeepAlive(true); await tester.drag(find.byType(ListView), const Offset(0.0, -1000.0)); @@ -389,11 +375,6 @@ void main() { ' │ parentData: <none> (can use size)\n' ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n' ' │ size: Size(800.0, 600.0)\n' - ' │ painter: null\n' - ' │ foregroundPainter:\n' - ' │ _GlowingOverscrollIndicatorPainter(_GlowController(color:\n' - ' │ Color(0xffffffff), axis: vertical), _GlowController(color:\n' - ' │ Color(0xffffffff), axis: vertical))\n' ' │\n' ' └─child: RenderRepaintBoundary#00000\n' ' │ needs compositing\n' @@ -490,9 +471,6 @@ void main() { ' │ parentData: <none> (can use size)\n' ' │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ size: Size(800.0, 400.0)\n' - ' │ painter: null\n' - ' │ foregroundPainter: _PlaceholderPainter#00000()\n' - ' │ preferredSize: Size(Infinity, Infinity)\n' ' │\n' ' ├─child with index 5: RenderLimitedBox#00000\n' // <----- this is index 5, not 0 ' │ │ parentData: index=5; layoutOffset=2000.0\n' @@ -505,9 +483,6 @@ void main() { ' │ parentData: <none> (can use size)\n' ' │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ size: Size(800.0, 400.0)\n' - ' │ painter: null\n' - ' │ foregroundPainter: _PlaceholderPainter#00000()\n' - ' │ preferredSize: Size(Infinity, Infinity)\n' ' │\n' ' ├─child with index 6: RenderLimitedBox#00000\n' ' │ │ parentData: index=6; layoutOffset=2400.0\n' @@ -520,9 +495,6 @@ void main() { ' │ parentData: <none> (can use size)\n' ' │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ size: Size(800.0, 400.0)\n' - ' │ painter: null\n' - ' │ foregroundPainter: _PlaceholderPainter#00000()\n' - ' │ preferredSize: Size(Infinity, Infinity)\n' ' │\n' ' ├─child with index 7: RenderLimitedBox#00000 NEEDS-PAINT\n' ' ╎ │ parentData: index=7; layoutOffset=2800.0\n' @@ -535,9 +507,6 @@ void main() { ' ╎ parentData: <none> (can use size)\n' ' ╎ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' ╎ size: Size(800.0, 400.0)\n' - ' ╎ painter: null\n' - ' ╎ foregroundPainter: _PlaceholderPainter#00000()\n' - ' ╎ preferredSize: Size(Infinity, Infinity)\n' ' ╎\n' ' ╎╌child with index 0 (kept alive but not laid out): RenderLimitedBox#00000\n' // <----- this one is index 0 and is marked as being kept alive but not laid out ' ╎ │ parentData: index=0; keepAlive; layoutOffset=0.0\n' @@ -550,9 +519,6 @@ void main() { ' ╎ parentData: <none> (can use size)\n' ' ╎ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' ╎ size: Size(800.0, 400.0)\n' - ' ╎ painter: null\n' - ' ╎ foregroundPainter: _PlaceholderPainter#00000()\n' - ' ╎ preferredSize: Size(Infinity, Infinity)\n' ' ╎\n' // <----- dashed line ends here ' └╌child with index 3 (kept alive but not laid out): RenderLimitedBox#00000\n' ' │ parentData: index=3; keepAlive; layoutOffset=1200.0\n' @@ -564,10 +530,7 @@ void main() { ' └─child: RenderCustomPaint#00000\n' ' parentData: <none> (can use size)\n' ' constraints: BoxConstraints(w=800.0, h=400.0)\n' - ' size: Size(800.0, 400.0)\n' - ' painter: null\n' - ' foregroundPainter: _PlaceholderPainter#00000()\n' - ' preferredSize: Size(Infinity, Infinity)\n', + ' size: Size(800.0, 400.0)\n', )); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/87876 diff --git a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart index ba9b6fedc113d..395b56ada2734 100644 --- a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart +++ b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart @@ -230,7 +230,6 @@ void main() { }); testWidgets('child builder with lower and upper limits', (WidgetTester tester) async { - // Adjust the content dimensions at the end of `RenderListWheelViewport.performLayout()` final List<int> paintedChildren = <int>[]; final FixedExtentScrollController controller = @@ -286,69 +285,6 @@ void main() { }); group('layout', () { - // Regression test for https://github.com/flutter/flutter/issues/90953 - testWidgets('ListWheelScrollView childDelegate update test 2', (WidgetTester tester) async { - final FixedExtentScrollController controller = FixedExtentScrollController( initialItem: 2 ); - Widget buildFrame(int childCount) { - return Directionality( - textDirection: TextDirection.ltr, - child: ListWheelScrollView.useDelegate( - controller: controller, - itemExtent: 400.0, - onSelectedItemChanged: (_) { }, - childDelegate: ListWheelChildBuilderDelegate( - childCount: childCount, - builder: (BuildContext context, int index) { - return SizedBox( - width: 400.0, - height: 400.0, - child: Text(index.toString()), - ); - }, - ), - ), - ); - } - - await tester.pumpWidget(buildFrame(5)); - expect(find.text('0'), findsNothing); - expect(tester.renderObject(find.text('1')).attached, true); - expect(tester.renderObject(find.text('2')).attached, true); - expect(tester.renderObject(find.text('3')).attached, true); - expect(find.text('4'), findsNothing); - - // Remove the last 3 items. - await tester.pumpWidget(buildFrame(2)); - expect(tester.renderObject(find.text('0')).attached, true); - expect(tester.renderObject(find.text('1')).attached, true); - expect(find.text('3'), findsNothing); - - // Add 3 items at the end. - await tester.pumpWidget(buildFrame(5)); - expect(tester.renderObject(find.text('0')).attached, true); - expect(tester.renderObject(find.text('1')).attached, true); - expect(tester.renderObject(find.text('2')).attached, true); - expect(find.text('3'), findsNothing); - expect(find.text('4'), findsNothing); - - - // Scroll to the last item. - final TestGesture scrollGesture = await tester.startGesture(const Offset(10.0, 10.0)); - await scrollGesture.moveBy(const Offset(0.0, -1200.0)); - await tester.pump(); - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsNothing); - expect(find.text('2'), findsNothing); - expect(tester.renderObject(find.text('3')).attached, true); - expect(tester.renderObject(find.text('4')).attached, true); - - // Remove the last 3 items. - await tester.pumpWidget(buildFrame(2)); - expect(tester.renderObject(find.text('0')).attached, true); - expect(tester.renderObject(find.text('1')).attached, true); - expect(find.text('3'), findsNothing); - }); - // Regression test for https://github.com/flutter/flutter/issues/58144 testWidgets('ListWheelScrollView childDelegate update test', (WidgetTester tester) async { final FixedExtentScrollController controller = FixedExtentScrollController(); diff --git a/packages/flutter/test/widgets/listener_test.dart b/packages/flutter/test/widgets/listener_test.dart index 11630a6d7b1c8..d1e33fbd10c68 100644 --- a/packages/flutter/test/widgets/listener_test.dart +++ b/packages/flutter/test/widgets/listener_test.dart @@ -406,7 +406,6 @@ void main() { onPointerDown: (PointerDownEvent event) {}, onPointerUp: (PointerUpEvent event) {}, onPointerMove: (PointerMoveEvent event) {}, - onPointerHover: (PointerHoverEvent event) {}, onPointerCancel: (PointerCancelEvent event) {}, onPointerSignal: (PointerSignalEvent event) {}, behavior: HitTestBehavior.opaque, @@ -423,7 +422,7 @@ void main() { 'constraints: MISSING', 'size: MISSING', 'behavior: opaque', - 'listeners: down, move, up, hover, cancel, signal', + 'listeners: down, move, up, cancel, signal', ]); }); } diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 85055a8cb6d15..48c54f6804e77 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show Brightness, DisplayFeature, DisplayFeatureState, DisplayFeatureType; +import 'dart:ui' show Brightness; import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; @@ -112,7 +112,6 @@ void main() { expect(data.highContrast, false); expect(data.platformBrightness, Brightness.light); expect(data.gestureSettings.touchSlop, null); - expect(data.displayFeatures, isEmpty); }); testWidgets('MediaQueryData.copyWith defaults to source', (WidgetTester tester) async { @@ -133,7 +132,6 @@ void main() { expect(copied.highContrast, data.highContrast); expect(copied.platformBrightness, data.platformBrightness); expect(copied.gestureSettings, data.gestureSettings); - expect(copied.displayFeatures, data.displayFeatures); }); testWidgets('MediaQuery.copyWith copies specified values', (WidgetTester tester) async { @@ -147,13 +145,6 @@ void main() { const EdgeInsets customViewInsets = EdgeInsets.all(1.67262); const EdgeInsets customSystemGestureInsets = EdgeInsets.all(1.5556); const DeviceGestureSettings gestureSettings = DeviceGestureSettings(touchSlop: 8.0); - const List<DisplayFeature> customDisplayFeatures = <DisplayFeature>[ - DisplayFeature( - bounds: Rect.zero, - type: DisplayFeatureType.cutout, - state: DisplayFeatureState.unknown, - ), - ]; final MediaQueryData data = MediaQueryData.fromWindow(WidgetsBinding.instance!.window); final MediaQueryData copied = data.copyWith( @@ -172,7 +163,6 @@ void main() { highContrast: true, platformBrightness: Brightness.dark, gestureSettings: gestureSettings, - displayFeatures: customDisplayFeatures, ); expect(copied.size, customSize); expect(copied.devicePixelRatio, customDevicePixelRatio); @@ -189,7 +179,6 @@ void main() { expect(copied.highContrast, true); expect(copied.platformBrightness, Brightness.dark); expect(copied.gestureSettings, gestureSettings); - expect(copied.displayFeatures, customDisplayFeatures); }); testWidgets('MediaQuery.removePadding removes specified padding', (WidgetTester tester) async { @@ -199,13 +188,6 @@ void main() { const EdgeInsets padding = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); - const List<DisplayFeature> displayFeatures = <DisplayFeature>[ - DisplayFeature( - bounds: Rect.zero, - type: DisplayFeatureType.cutout, - state: DisplayFeatureState.unknown, - ), - ]; late MediaQueryData unpadded; await tester.pumpWidget( @@ -223,7 +205,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - displayFeatures: displayFeatures, ), child: Builder( builder: (BuildContext context) { @@ -257,7 +238,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.displayFeatures, displayFeatures); }); testWidgets('MediaQuery.removePadding only removes specified padding', (WidgetTester tester) async { @@ -267,13 +247,6 @@ void main() { const EdgeInsets padding = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); - const List<DisplayFeature> displayFeatures = <DisplayFeature>[ - DisplayFeature( - bounds: Rect.zero, - type: DisplayFeatureType.cutout, - state: DisplayFeatureState.unknown, - ), - ]; late MediaQueryData unpadded; await tester.pumpWidget( @@ -291,7 +264,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - displayFeatures: displayFeatures, ), child: Builder( builder: (BuildContext context) { @@ -322,7 +294,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.displayFeatures, displayFeatures); }); testWidgets('MediaQuery.removeViewInsets removes specified viewInsets', (WidgetTester tester) async { @@ -332,13 +303,6 @@ void main() { const EdgeInsets padding = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); - const List<DisplayFeature> displayFeatures = <DisplayFeature>[ - DisplayFeature( - bounds: Rect.zero, - type: DisplayFeatureType.cutout, - state: DisplayFeatureState.unknown, - ), - ]; late MediaQueryData unpadded; await tester.pumpWidget( @@ -356,7 +320,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - displayFeatures: displayFeatures, ), child: Builder( builder: (BuildContext context) { @@ -390,7 +353,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.displayFeatures, displayFeatures); }); testWidgets('MediaQuery.removeViewInsets removes only specified viewInsets', (WidgetTester tester) async { @@ -400,13 +362,6 @@ void main() { const EdgeInsets padding = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); - const List<DisplayFeature> displayFeatures = <DisplayFeature>[ - DisplayFeature( - bounds: Rect.zero, - type: DisplayFeatureType.cutout, - state: DisplayFeatureState.unknown, - ), - ]; late MediaQueryData unpadded; await tester.pumpWidget( @@ -424,7 +379,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - displayFeatures: displayFeatures, ), child: Builder( builder: (BuildContext context) { @@ -455,7 +409,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.displayFeatures, displayFeatures); }); testWidgets('MediaQuery.removeViewPadding removes specified viewPadding', (WidgetTester tester) async { @@ -465,13 +418,6 @@ void main() { const EdgeInsets padding = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); - const List<DisplayFeature> displayFeatures = <DisplayFeature>[ - DisplayFeature( - bounds: Rect.zero, - type: DisplayFeatureType.cutout, - state: DisplayFeatureState.unknown, - ), - ]; late MediaQueryData unpadded; await tester.pumpWidget( @@ -489,7 +435,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - displayFeatures: displayFeatures, ), child: Builder( builder: (BuildContext context) { @@ -523,7 +468,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.displayFeatures, displayFeatures); }); testWidgets('MediaQuery.removeViewPadding removes only specified viewPadding', (WidgetTester tester) async { @@ -533,13 +477,6 @@ void main() { const EdgeInsets padding = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); - const List<DisplayFeature> displayFeatures = <DisplayFeature>[ - DisplayFeature( - bounds: Rect.zero, - type: DisplayFeatureType.cutout, - state: DisplayFeatureState.unknown, - ), - ]; late MediaQueryData unpadded; await tester.pumpWidget( @@ -557,7 +494,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - displayFeatures: displayFeatures, ), child: Builder( builder: (BuildContext context) { @@ -588,7 +524,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.displayFeatures, displayFeatures); }); testWidgets('MediaQuery.textScaleFactorOf', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/modal_barrier_test.dart b/packages/flutter/test/widgets/modal_barrier_test.dart index 563e410d142fd..0470031997d74 100644 --- a/packages/flutter/test/widgets/modal_barrier_test.dart +++ b/packages/flutter/test/widgets/modal_barrier_test.dart @@ -160,10 +160,8 @@ void main() { final List<String> playedSystemSounds = <String>[]; try { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { - if (methodCall.method == 'SystemSound.play') { + if (methodCall.method == 'SystemSound.play') playedSystemSounds.add(methodCall.arguments as String); - } - return null; }); final Widget subject = Stack( @@ -367,60 +365,6 @@ void main() { expect(willPopCalled, isTrue); }); - testWidgets('ModalBarrier will call onDismiss callback', (WidgetTester tester) async { - bool dismissCallbackCalled = false; - final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ - '/': (BuildContext context) => const FirstWidget(), - '/modal': (BuildContext context) => SecondWidget(onDismiss: () { - dismissCallbackCalled = true; - }), - }; - - await tester.pumpWidget(MaterialApp(routes: routes)); - - // Initially the barrier is not visible - expect(find.byKey(const ValueKey<String>('barrier')), findsNothing); - - // Tapping on X routes to the barrier - await tester.tap(find.text('X')); - await tester.pump(); // begin transition - await tester.pump(const Duration(seconds: 1)); // end transition - expect(find.byKey(const ValueKey<String>('barrier')), findsOneWidget); - expect(dismissCallbackCalled, false); - - // Tap on the barrier - await tester.tap(find.byKey(const ValueKey<String>('barrier'))); - await tester.pumpAndSettle(const Duration(seconds: 1)); // end transition - expect(dismissCallbackCalled, true); - }); - - testWidgets('ModalBarrier will not pop when given an onDismiss callback', (WidgetTester tester) async { - final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ - '/': (BuildContext context) => const FirstWidget(), - '/modal': (BuildContext context) => SecondWidget(onDismiss: () {}), - }; - - await tester.pumpWidget(MaterialApp(routes: routes)); - - // Initially the barrier is not visible - expect(find.byKey(const ValueKey<String>('barrier')), findsNothing); - - // Tapping on X routes to the barrier - await tester.tap(find.text('X')); - await tester.pump(); // begin transition - await tester.pump(const Duration(seconds: 1)); // end transition - expect(find.byKey(const ValueKey<String>('barrier')), findsOneWidget); - - // Tap on the barrier - await tester.tap(find.byKey(const ValueKey<String>('barrier'))); - await tester.pumpAndSettle(const Duration(seconds: 1)); // end transition - expect( - find.byKey(const ValueKey<String>('barrier')), - findsOneWidget, - reason: 'The route should not have been dismissed by tapping the barrier, as there was a onDismiss callback given.', - ); - }); - testWidgets('Undismissible ModalBarrier hidden in semantic tree', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(const ModalBarrier(dismissible: false)); @@ -498,15 +442,11 @@ class FirstWidget extends StatelessWidget { } class SecondWidget extends StatelessWidget { - const SecondWidget({ Key? key, this.onDismiss }) : super(key: key); - - final VoidCallback? onDismiss; - + const SecondWidget({ Key? key }) : super(key: key); @override Widget build(BuildContext context) { - return ModalBarrier( - key: const ValueKey<String>('barrier'), - onDismiss: onDismiss, + return const ModalBarrier( + key: ValueKey<String>('barrier'), ); } } diff --git a/packages/flutter/test/widgets/mouse_region_test.dart b/packages/flutter/test/widgets/mouse_region_test.dart index e2282703460e2..8a09b8bec47c8 100644 --- a/packages/flutter/test/widgets/mouse_region_test.dart +++ b/packages/flutter/test/widgets/mouse_region_test.dart @@ -1621,7 +1621,6 @@ void main() { addTearDown(gesture.removePointer); tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, (_) async { logCursors.add('cursor'); - return null; }); final GlobalKey key = GlobalKey(); diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 2198015e79562..0c84e2877355a 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -544,44 +544,6 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Page-based route pop before push finishes', (WidgetTester tester) async { - List<Page<void>> pages = <Page<void>>[const MaterialPage<void>(child: Text('Page 1'))]; - final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>(); - Widget buildNavigator() { - return Navigator( - key: navigator, - pages: pages, - onPopPage: (Route<dynamic> route, dynamic result) { - pages.removeLast(); - return route.didPop(result); - }, - ); - } - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: buildNavigator(), - ), - ); - expect(find.text('Page 1'), findsOneWidget); - pages = pages.toList(); - pages.add(const MaterialPage<void>(child: Text('Page 2'))); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: buildNavigator(), - ), - ); - // This test should finish without crashing. - await tester.pump(); - await tester.pump(); - - navigator.currentState!.pop(); - await tester.pumpAndSettle(); - expect(find.text('Page 1'), findsOneWidget); - }); - testWidgets('Pages update does update overlay correctly', (WidgetTester tester) async { // Regression Test for https://github.com/flutter/flutter/issues/64941. List<Page<void>> pages = const <Page<void>>[ @@ -3007,32 +2969,6 @@ void main() { expect(primaryAnimationOfRouteOne.status, AnimationStatus.dismissed); }); - testWidgets('Pop no animation page does not crash', (WidgetTester tester) async { - // Regression Test for https://github.com/flutter/flutter/issues/86604. - Widget buildNavigator(bool secondPage) { - return Directionality( - textDirection: TextDirection.ltr, - child: Navigator( - pages: <Page<void>>[ - const ZeroDurationPage( - child: Text('page1'), - ), - if (secondPage) - const ZeroDurationPage( - child: Text('page2'), - ), - ], - onPopPage: (Route<dynamic> route, dynamic result) => false, - ), - ); - } - await tester.pumpWidget(buildNavigator(true)); - expect(find.text('page2'), findsOneWidget); - - await tester.pumpWidget(buildNavigator(false)); - expect(find.text('page1'), findsOneWidget); - }); - testWidgets('can work with pageless route', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>(); List<TestPage> myPages = <TestPage>[ @@ -3963,9 +3899,6 @@ class NavigatorObservation { final String? previous; final String? current; final String operation; - - @override - String toString() => 'NavigatorObservation($operation, $current, $previous)'; } class BuilderPage extends Page<void> { @@ -3981,43 +3914,3 @@ class BuilderPage extends Page<void> { ); } } - -class ZeroDurationPage extends Page<void> { - const ZeroDurationPage({required this.child}); - - final Widget child; - - @override - Route<void> createRoute(BuildContext context) { - return ZeroDurationPageRoute(page: this); - } -} - -class ZeroDurationPageRoute extends PageRoute<void> { - ZeroDurationPageRoute({required ZeroDurationPage page}) - : super(settings: page); - - @override - Duration get transitionDuration => Duration.zero; - - ZeroDurationPage get _page => settings as ZeroDurationPage; - - @override - Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) { - return _page.child; - } - - @override - Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { - return child; - } - - @override - bool get maintainState => false; - - @override - Color? get barrierColor => null; - - @override - String? get barrierLabel => null; -} diff --git a/packages/flutter/test/widgets/nested_scroll_view_test.dart b/packages/flutter/test/widgets/nested_scroll_view_test.dart index 8bf26e481ffaa..da5400071d919 100644 --- a/packages/flutter/test/widgets/nested_scroll_view_test.dart +++ b/packages/flutter/test/widgets/nested_scroll_view_test.dart @@ -2491,68 +2491,6 @@ void main() { await tester.fling(find.text('Item 25'), const Offset(0.0, -50.0), 4000.0); await tester.pumpAndSettle(); }); - - testWidgets('NestedScrollViewCoordinator.pointerScroll dispatches correct scroll notifications', (WidgetTester tester) async { - int scrollEnded = 0; - int scrollStarted = 0; - bool isScrolled = false; - - await tester.pumpWidget(MaterialApp( - home: NotificationListener<ScrollNotification>( - onNotification: (ScrollNotification notification) { - if (notification is ScrollStartNotification) { - scrollStarted += 1; - } else if (notification is ScrollEndNotification) { - scrollEnded += 1; - } - return false; - }, - child: Scaffold( - body: NestedScrollView( - headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { - isScrolled = innerBoxIsScrolled; - return <Widget>[ - const SliverAppBar( - expandedHeight: 250.0, - ), - ]; - }, - body: CustomScrollView( - physics: const BouncingScrollPhysics(), - slivers: <Widget>[ - SliverPadding( - padding: const EdgeInsets.all(8.0), - sliver: SliverFixedExtentList( - itemExtent: 48.0, - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return ListTile( - title: Text('Item $index'), - ); - }, - childCount: 30, - ), - ), - ), - ], - ), - ), - ), - ), - )); - - final Offset scrollEventLocation = tester.getCenter(find.byType(NestedScrollView)); - final TestPointer testPointer = TestPointer(1, ui.PointerDeviceKind.mouse); - // Create a hover event so that |testPointer| has a location when generating the scroll. - testPointer.hover(scrollEventLocation); - await tester.sendEventToBinding(testPointer.scroll(const Offset(0.0, 300.0))); - await tester.pumpAndSettle(); - - expect(isScrolled, isTrue); - // There should have been a notification for each nested position (2). - expect(scrollStarted, 2); - expect(scrollEnded, 2); - }); } class TestHeader extends SliverPersistentHeaderDelegate { diff --git a/packages/flutter/test/widgets/page_view_test.dart b/packages/flutter/test/widgets/page_view_test.dart index 0f353f592b29d..7a47333f2b156 100644 --- a/packages/flutter/test/widgets/page_view_test.dart +++ b/packages/flutter/test/widgets/page_view_test.dart @@ -1096,31 +1096,4 @@ void main() { expect(tester.widget<SliverFillViewport>(viewportFinder()).padEnds, false); }); - - testWidgets('PageView - precision error inside RenderSliverFixedExtentBoxAdaptor', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/95101 - - final PageController controller = PageController(initialPage: 152); - await tester.pumpWidget( - Center( - child: SizedBox( - width: 392.72727272727275, - child: Directionality( - textDirection: TextDirection.ltr, - child: PageView.builder( - controller: controller, - itemCount: 366, - itemBuilder: (BuildContext context, int index) { - return const SizedBox(); - }, - ), - ), - ), - ), - ); - - controller.jumpToPage(365); - await tester.pump(); - expect(tester.takeException(), isNull); - }); } diff --git a/packages/flutter/test/widgets/range_maintaining_scroll_physics_test.dart b/packages/flutter/test/widgets/range_maintaining_scroll_physics_test.dart index dd571a406119e..cdb8ea6f6bd8e 100644 --- a/packages/flutter/test/widgets/range_maintaining_scroll_physics_test.dart +++ b/packages/flutter/test/widgets/range_maintaining_scroll_physics_test.dart @@ -230,7 +230,7 @@ void main() { expect(bike2.center, bike1.shift(const Offset(100.0, 0.0)).center); }); - testWidgets('changing the size of the viewport when overscrolled', (WidgetTester tester) async { + testWidgets('Changing the size of the viewport while you are overdragged', (WidgetTester tester) async { Widget build(double height) { return Directionality( textDirection: TextDirection.rtl, @@ -263,82 +263,6 @@ void main() { final Rect newPosition = tester.getRect(find.byType(Placeholder)); expect(oldPosition, newPosition); }); - - testWidgets('inserting and removing an item when overscrolled', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/62890 - - const double itemExtent = 100.0; - final UniqueKey key = UniqueKey(); - final Finder finder = find.byKey(key); - Widget build({required bool twoItems}) { - return Directionality( - textDirection: TextDirection.rtl, - child: ScrollConfiguration( - behavior: const RangeMaintainingTestScrollBehavior(), - child: Align( - child: SizedBox( - width: 100.0, - height: 100.0, - child: ListView( - children: <Widget>[ - SizedBox(height: itemExtent, child: Placeholder(key: key)), - if (twoItems) - const SizedBox(height: itemExtent, child: Placeholder()), - ], - ), - ), - ), - ), - ); - } - - await tester.pumpWidget(build(twoItems: false)); - final ScrollPosition position = tester.state<ScrollableState>(find.byType(Scrollable)).position; - - // overscroll bottom - final TestGesture drag1 = await tester.startGesture(tester.getCenter(finder)); - await tester.pump(); - await drag1.moveBy(const Offset(0.0, -50.0)); - await tester.pump(); - - final double oldOverscroll1 = position.pixels - position.maxScrollExtent; - final Rect oldPosition1 = tester.getRect(finder); - await tester.pumpWidget(build(twoItems: true)); - // verify inserting new item didn't change the position of the first one - expect(oldPosition1, tester.getRect(finder)); - // verify the overscroll changed by the size of the added item - final double newOverscroll1 = position.pixels - position.maxScrollExtent; - expect(oldOverscroll1, isPositive); - expect(newOverscroll1, isNegative); - expect(newOverscroll1, oldOverscroll1 - itemExtent); - - await drag1.up(); - - // verify there's no ballistic animation, because we weren't overscrolled - expect(await tester.pumpAndSettle(), 1); - - // overscroll bottom - final TestGesture drag2 = await tester.startGesture(tester.getCenter(finder)); - await tester.pump(); - await drag2.moveBy(const Offset(0.0, -100.0)); - await tester.pump(); - - final double oldOverscroll2 = position.pixels - position.maxScrollExtent; - // should find nothing because item is not visible - expect(finder, findsNothing); - await tester.pumpWidget(build(twoItems: false)); - // verify removing an item changed the position of the first one, because prior it was not visible - expect(oldPosition1, tester.getRect(finder)); - // verify the overscroll was maintained - final double newOverscroll2 = position.pixels - position.maxScrollExtent; - expect(oldOverscroll2, isPositive); - expect(oldOverscroll2, newOverscroll2); - - await drag2.up(); - - // verify there's a ballistic animation from overscroll - expect(await tester.pumpAndSettle(), 9); - }); } class TabBarDemo extends StatelessWidget { diff --git a/packages/flutter/test/widgets/reorderable_list_test.dart b/packages/flutter/test/widgets/reorderable_list_test.dart index 6e108385309a3..31b189282f580 100644 --- a/packages/flutter/test/widgets/reorderable_list_test.dart +++ b/packages/flutter/test/widgets/reorderable_list_test.dart @@ -7,53 +7,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - // Regression test for https://github.com/flutter/flutter/issues/88191 - testWidgets('Do not crash when dragging with two fingers simultaneously', (WidgetTester tester) async { - final List<int> items = List<int>.generate(3, (int index) => index); - void handleReorder(int fromIndex, int toIndex) { - if (toIndex > fromIndex) { - toIndex -= 1; - } - items.insert(toIndex, items.removeAt(fromIndex)); - } - - await tester.pumpWidget(MaterialApp( - home: ReorderableList( - itemBuilder: (BuildContext context, int index) { - return ReorderableDragStartListener( - index: index, - key: ValueKey<int>(items[index]), - child: SizedBox( - height: 100, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: <Widget>[ - Text('item ${items[index]}'), - ], - ), - ), - ); - }, - itemCount: items.length, - onReorder: handleReorder, - ), - )); - - final TestGesture drag1 = await tester.startGesture(tester.getCenter(find.text('item 0'))); - final TestGesture drag2 = await tester.startGesture(tester.getCenter(find.text('item 0'))); - await tester.pump(kLongPressTimeout); - - await drag1.moveBy(const Offset(0, 100)); - await drag2.moveBy(const Offset(0, 100)); - await tester.pumpAndSettle(); - - await drag1.up(); - await drag2.up(); - await tester.pumpAndSettle(); - - expect(tester.takeException(), isNull); - }); - testWidgets('negative itemCount should assert', (WidgetTester tester) async { final List<int> items = <int>[1, 2, 3]; await tester.pumpWidget(MaterialApp( @@ -641,7 +594,7 @@ void main() { expect(items, orderedEquals(<int>[1, 0, 2, 3, 4])); }); - testWidgets('It should not allow the item to be dragged when enabled is false', (WidgetTester tester) async { + testWidgets('It should allow the item to be dragged when enabled is true', (WidgetTester tester) async { const int itemCount = 5; int onReorderCallCount = 0; final List<int> items = List<int>.generate(itemCount, (int index) => index); @@ -679,7 +632,7 @@ void main() { await tester.pump(kLongPressTimeout); // Drag enough to move down the first item - await drag.moveBy(const Offset(0, 50)); + await drag.moveBy(const Offset(0, 150)); await tester.pump(); await drag.up(); await tester.pumpAndSettle(); @@ -737,7 +690,7 @@ void main() { expect(items, orderedEquals(<int>[1, 0, 2, 3, 4])); }); - testWidgets('It should not allow the item to be dragged when enabled is false', (WidgetTester tester) async { + testWidgets('It should allow the item to be dragged when enabled is true', (WidgetTester tester) async { const int itemCount = 5; int onReorderCallCount = 0; final List<int> items = List<int>.generate(itemCount, (int index) => index); diff --git a/packages/flutter/test/widgets/route_notification_messages_test.dart b/packages/flutter/test/widgets/route_notification_messages_test.dart index b324de1b75bae..58a7dfed88607 100644 --- a/packages/flutter/test/widgets/route_notification_messages_test.dart +++ b/packages/flutter/test/widgets/route_notification_messages_test.dart @@ -57,7 +57,6 @@ void main() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget(MaterialApp( @@ -116,7 +115,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget(Directionality( @@ -167,7 +165,6 @@ void main() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget(MaterialApp( @@ -226,7 +223,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget(MaterialApp( @@ -270,7 +266,6 @@ void main() { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); - return null; }); final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index 0e0e1bf9ec228..12b463cbe4a8b 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -792,7 +792,6 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); - return null; } ); final RouteInformationProvider provider = PlatformRouteInformationProvider( diff --git a/packages/flutter/test/widgets/scroll_activity_test.dart b/packages/flutter/test/widgets/scroll_activity_test.dart index f1a07e431c55c..088eb591d8f98 100644 --- a/packages/flutter/test/widgets/scroll_activity_test.dart +++ b/packages/flutter/test/widgets/scroll_activity_test.dart @@ -13,7 +13,7 @@ List<Widget> children(int n) { } void main() { - testWidgets('Scrolling with list view changes, leaving the overscroll', (WidgetTester tester) async { + testWidgets('Scrolling with list view changes', (WidgetTester tester) async { final ScrollController controller = ScrollController(); await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(30)))); final double thirty = controller.position.maxScrollExtent; @@ -22,21 +22,7 @@ void main() { controller.jumpTo(thirty + 100.0); // past the end await tester.pump(); await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(31)))); - expect(controller.position.pixels, thirty + 100.0); // has the same position, but no longer overscrolled - expect(await tester.pumpAndSettle(), 1); // doesn't have ballistic animation... - expect(controller.position.pixels, thirty + 100.0); // and ends up at the end - }); - - testWidgets('Scrolling with list view changes, remaining overscrolled', (WidgetTester tester) async { - final ScrollController controller = ScrollController(); - await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(30)))); - final double thirty = controller.position.maxScrollExtent; - controller.jumpTo(thirty); - await tester.pump(); - controller.jumpTo(thirty + 200.0); // past the end - await tester.pump(); - await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(31)))); - expect(controller.position.pixels, thirty + 200.0); // has the same position, still overscrolled + expect(controller.position.pixels, thirty + 200.0); // same distance past the end expect(await tester.pumpAndSettle(), 8); // now it goes ballistic... expect(controller.position.pixels, thirty + 100.0); // and ends up at the end }); diff --git a/packages/flutter/test/widgets/scrollbar_test.dart b/packages/flutter/test/widgets/scrollbar_test.dart index ed724df040ff2..c7f3433b42060 100644 --- a/packages/flutter/test/widgets/scrollbar_test.dart +++ b/packages/flutter/test/widgets/scrollbar_test.dart @@ -2038,124 +2038,6 @@ void main() { expect(depths[1], 0); }); - // Regression test for https://github.com/flutter/flutter/issues/92262 - testWidgets('Do not crash when resize from scrollable to non-scrollable.', (WidgetTester tester) async { - final ScrollController scrollController = ScrollController(); - Widget buildFrame(double height) { - return Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(), - child: RawScrollbar( - controller: scrollController, - interactive: true, - isAlwaysShown: true, - child: SingleChildScrollView( - controller: scrollController, - child: Container( - width: 100.0, - height: height, - color: const Color(0xFF000000), - ), - ), - ), - ), - ); - } - await tester.pumpWidget(buildFrame(700.0)); - await tester.pumpAndSettle(); - - await tester.pumpWidget(buildFrame(600.0)); - await tester.pumpAndSettle(); - - // Try to drag the thumb. - final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(798.0, 5.0)); - await tester.pumpAndSettle(); - await dragScrollbarGesture.moveBy(const Offset(0.0, 5.0)); - await tester.pumpAndSettle(); - }); - - testWidgets('Scrollbar thumb can be dragged when the scrollable widget has a negative minScrollExtent', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/95840 - - final ScrollController scrollController = ScrollController(); - final UniqueKey uniqueKey = UniqueKey(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(), - child: ScrollConfiguration( - behavior: const ScrollBehavior().copyWith( - scrollbars: false, - ), - child: PrimaryScrollController( - controller: scrollController, - child: RawScrollbar( - isAlwaysShown: true, - controller: scrollController, - child: CustomScrollView( - center: uniqueKey, - slivers: <Widget>[ - SliverToBoxAdapter( - child: Container( - height: 600.0, - ), - ), - SliverToBoxAdapter( - key: uniqueKey, - child: Container( - height: 600.0, - ), - ), - SliverToBoxAdapter( - child: Container( - height: 600.0, - ), - ), - ], - ), - ), - ), - ), - ), - ), - ); - await tester.pumpAndSettle(); - expect(scrollController.offset, 0.0); - expect( - find.byType(RawScrollbar), - paints - ..rect(rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 600.0)) - ..rect( - rect: const Rect.fromLTRB(794.0, 200.0, 800.0, 400.0), - color: const Color(0x66BCBCBC), - ), - ); - - // Drag the thumb up to scroll up. - const double scrollAmount = -10.0; - final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 300.0)); - await tester.pumpAndSettle(); - await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount)); - await tester.pumpAndSettle(); - await dragScrollbarGesture.up(); - await tester.pumpAndSettle(); - - // The view has scrolled more than it would have by a swipe gesture of the - // same distance. - expect(scrollController.offset, lessThan(scrollAmount * 2)); - expect( - find.byType(RawScrollbar), - paints - ..rect(rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 600.0)) - ..rect( - rect: const Rect.fromLTRB(794.0, 190.0, 800.0, 390.0), - color: const Color(0x66BCBCBC), - ), - ); - }, variant: TargetPlatformVariant.all()); - test('ScrollbarPainter.shouldRepaint returns true when any of the properties changes', () { ScrollbarPainter createPainter({ Color color = const Color(0xFF000000), diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index e9f98b5431ae7..99c47908e7cb3 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -184,6 +184,80 @@ void main() { ); } + testWidgets('can use the desktop cut/copy/paste buttons on desktop', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController( + text: 'blah1 blah2', + ); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: TextFormField( + controller: controller, + ), + ), + ), + ), + ); + + // Initially, the menu is not shown and there is no selection. + expect(find.byType(CupertinoButton), findsNothing); + expect(controller.selection, const TextSelection(baseOffset: -1, extentOffset: -1)); + + final Offset midBlah1 = textOffsetToPosition(tester, 2); + + // Right clicking shows the menu. + final TestGesture gesture = await tester.startGesture( + midBlah1, + kind: PointerDeviceKind.mouse, + buttons: kSecondaryMouseButton, + ); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 5)); + expect(find.text('Copy'), findsOneWidget); + expect(find.text('Cut'), findsOneWidget); + expect(find.text('Paste'), findsOneWidget); + + // Copy the first word. + await tester.tap(find.text('Copy')); + await tester.pumpAndSettle(); + expect(controller.text, 'blah1 blah2'); + expect(controller.selection, const TextSelection(baseOffset: 5, extentOffset: 5)); + expect(find.byType(CupertinoButton), findsNothing); + + // Paste it at the end. + await gesture.down(textOffsetToPosition(tester, controller.text.length)); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(controller.selection, const TextSelection(baseOffset: 11, extentOffset: 11, affinity: TextAffinity.upstream)); + expect(find.text('Cut'), findsNothing); + expect(find.text('Copy'), findsNothing); + expect(find.text('Paste'), findsOneWidget); + await tester.tap(find.text('Paste')); + await tester.pumpAndSettle(); + expect(controller.text, 'blah1 blah2blah1'); + expect(controller.selection, const TextSelection(baseOffset: 16, extentOffset: 16, affinity: TextAffinity.upstream)); + + // Cut the first word. + await gesture.down(midBlah1); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(find.text('Cut'), findsOneWidget); + expect(find.text('Copy'), findsOneWidget); + expect(find.text('Paste'), findsOneWidget); + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 5)); + await tester.tap(find.text('Cut')); + await tester.pumpAndSettle(); + expect(controller.text, ' blah2blah1'); + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 0)); + expect(find.byType(CupertinoButton), findsNothing); + }, variant: TargetPlatformVariant.desktop(), skip: kIsWeb); // [intended] toolbar is handled by the browser. + testWidgets('has expected defaults', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( @@ -4869,91 +4943,4 @@ void main() { matchesGoldenFile('selectable_text_golden.TextSelectionStyle.2.png'), ); }); - - testWidgets('keeps alive when has focus', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: DefaultTabController( - length: 2, - child: Scaffold( - body: NestedScrollView( - headerSliverBuilder: - (BuildContext context, bool innerBoxIsScrolled) { - return <Widget>[ - SliverToBoxAdapter( - child: Container( - height: 200, - color: Colors.black12, - child: const Center(child: Text('Sliver 1')), - ), - ), - const SliverToBoxAdapter( - child: Center( - child: TabBar( - labelColor: Colors.black, - tabs: <Tab>[ - Tab(text: 'Sliver Tab 1'), - Tab(text: 'Sliver Tab 2'), - ], - ), - ) - ), - ]; - }, - body: const TabBarView( - children: <Widget>[ - Padding( - padding: EdgeInsets.only(top: 100.0), - child: Text('Regular Text'), - ), - Padding( - padding: EdgeInsets.only(top: 100.0), - child: SelectableText('Selectable Text'), - ), - ], - ), - ), - ), - ), - ), - ); - - // Without any selection, the offscreen widget is disposed and can't be - // found, for both Text and SelectableText. - expect(find.text('Regular Text', skipOffstage: false), findsOneWidget); - expect(find.byType(SelectableText, skipOffstage: false), findsNothing); - - await tester.tap(find.text('Sliver Tab 2')); - await tester.pumpAndSettle(); - expect(find.text('Regular Text', skipOffstage: false), findsNothing); - expect(find.byType(SelectableText, skipOffstage: false), findsOneWidget); - - await tester.tap(find.text('Sliver Tab 1')); - await tester.pumpAndSettle(); - expect(find.text('Regular Text', skipOffstage: false), findsOneWidget); - expect(find.byType(SelectableText, skipOffstage: false), findsNothing); - - // Switch back to tab 2 and select some text in SelectableText. - await tester.tap(find.text('Sliver Tab 2')); - await tester.pumpAndSettle(); - expect(find.text('Regular Text', skipOffstage: false), findsNothing); - expect(find.byType(SelectableText, skipOffstage: false), findsOneWidget); - - final EditableText editableText = tester.widget(find.byType(EditableText)); - expect(editableText.controller.selection.isValid, isFalse); - await tester.tapAt(textOffsetToPosition(tester, 4)); - await tester.pump(const Duration(milliseconds: 50)); - await tester.tapAt(textOffsetToPosition(tester, 4)); - await tester.pumpAndSettle(); - expect(editableText.controller.selection.isValid, isTrue); - expect(editableText.controller.selection.baseOffset, 0); - expect(editableText.controller.selection.extentOffset, 'Selectable'.length); - - // Switch back to tab 1. The SelectableText remains because it is preserving - // its selection. - await tester.tap(find.text('Sliver Tab 1')); - await tester.pumpAndSettle(); - expect(find.text('Regular Text', skipOffstage: false), findsOneWidget); - expect(find.byType(SelectableText, skipOffstage: false), findsOneWidget); - }); } diff --git a/packages/flutter/test/widgets/semantics_tester.dart b/packages/flutter/test/widgets/semantics_tester.dart index 65a416478103c..03cc46dae732a 100644 --- a/packages/flutter/test/widgets/semantics_tester.dart +++ b/packages/flutter/test/widgets/semantics_tester.dart @@ -823,7 +823,7 @@ class _IncludesNodeWith extends Matcher { if (label != null) 'label "$label"', if (value != null) 'value "$value"', if (hint != null) 'hint "$hint"', - if (textDirection != null) ' (${textDirection!.name})', + if (textDirection != null) ' (${describeEnum(textDirection!)})', if (actions != null) 'actions "${actions!.join(', ')}"', if (flags != null) 'flags "${flags!.join(', ')}"', if (scrollPosition != null) 'scrollPosition "$scrollPosition"', diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart index 39f5090571589..42c3c2da8f987 100644 --- a/packages/flutter/test/widgets/shortcuts_test.dart +++ b/packages/flutter/test/widgets/shortcuts_test.dart @@ -103,7 +103,6 @@ Widget activatorTester( if (hasSecond) TestIntent2: TestAction(onInvoke: (Intent intent) { onInvoke2(intent); - return null; }), }, child: Shortcuts( @@ -464,33 +463,6 @@ void main() { expect(RawKeyboard.instance.keysPressed, isEmpty); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('rejects repeated events if requested', (WidgetTester tester) async { - int invoked = 0; - await tester.pumpWidget(activatorTester( - const SingleActivator( - LogicalKeyboardKey.keyC, - control: true, - includeRepeats: false, - ), - (Intent intent) { invoked += 1; }, - )); - await tester.pump(); - - // LCtrl -> KeyC: Accept - await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); - expect(invoked, 0); - await tester.sendKeyDownEvent(LogicalKeyboardKey.keyC); - expect(invoked, 1); - await tester.sendKeyRepeatEvent(LogicalKeyboardKey.keyC); - expect(invoked, 1); - await tester.sendKeyUpEvent(LogicalKeyboardKey.keyC); - await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); - expect(invoked, 1); - invoked = 0; - - expect(RawKeyboard.instance.keysPressed, isEmpty); - }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('handles Shift-Ctrl-C', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( @@ -541,8 +513,8 @@ void main() { expect(RawKeyboard.instance.keysPressed, isEmpty); }); - group('diagnostics.', () { - test('single key', () { + test('diagnostics.', () { + { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SingleActivator( @@ -555,26 +527,9 @@ void main() { expect(description.length, equals(1)); expect(description[0], equals('keys: Key A')); - }); - - test('no repeats', () { - final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - - const SingleActivator( - LogicalKeyboardKey.keyA, - includeRepeats: false, - ).debugFillProperties(builder); - - final List<String> description = builder.properties.where((DiagnosticsNode node) { - return !node.isFiltered(DiagnosticLevel.info); - }).map((DiagnosticsNode node) => node.toString()).toList(); - - expect(description.length, equals(2)); - expect(description[0], equals('keys: Key A')); - expect(description[1], equals('excluding repeats')); - }); + } - test('combination', () { + { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SingleActivator( @@ -591,7 +546,7 @@ void main() { expect(description.length, equals(1)); expect(description[0], equals('keys: Control + Alt + Meta + Shift + Key A')); - }); + } }); }); @@ -1171,16 +1126,12 @@ void main() { group('CallbackShortcuts', () { testWidgets('trigger on key events', (WidgetTester tester) async { - int invokedA = 0; - int invokedB = 0; + int invoked = 0; await tester.pumpWidget( CallbackShortcuts( bindings: <ShortcutActivator, VoidCallback>{ const SingleActivator(LogicalKeyboardKey.keyA): () { - invokedA += 1; - }, - const SingleActivator(LogicalKeyboardKey.keyB): () { - invokedB += 1; + invoked += 1; }, }, child: const Focus( @@ -1192,20 +1143,9 @@ void main() { await tester.pump(); await tester.sendKeyDownEvent(LogicalKeyboardKey.keyA); - await tester.pump(); - expect(invokedA, equals(1)); - expect(invokedB, equals(0)); + expect(invoked, equals(1)); await tester.sendKeyUpEvent(LogicalKeyboardKey.keyA); - expect(invokedA, equals(1)); - expect(invokedB, equals(0)); - invokedA = 0; - invokedB = 0; - await tester.sendKeyDownEvent(LogicalKeyboardKey.keyB); - expect(invokedA, equals(0)); - expect(invokedB, equals(1)); - await tester.sendKeyUpEvent(LogicalKeyboardKey.keyB); - expect(invokedA, equals(0)); - expect(invokedB, equals(1)); + expect(invoked, equals(1)); }); testWidgets('nested CallbackShortcuts stop propagation', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart deleted file mode 100644 index 7d724fa2677cf..0000000000000 --- a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart +++ /dev/null @@ -1,290 +0,0 @@ -// 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 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../rendering/mock_canvas.dart'; - -const Color green = Color(0xFF00FF00); -const Color yellow = Color(0xFFFFFF00); - -void main() { - testWidgets('SlottedRenderObjectWidget test', (WidgetTester tester) async { - await tester.pumpWidget(buildWidget( - topLeft: Container( - height: 100, - width: 80, - color: yellow, - child: const Text('topLeft'), - ), - bottomRight: Container( - height: 120, - width: 110, - color: green, - child: const Text('bottomRight'), - ), - )); - - expect(find.text('topLeft'), findsOneWidget); - expect(find.text('bottomRight'), findsOneWidget); - expect(tester.getSize(find.byType(_Diagonal)), const Size(80 + 110, 100 + 120)); - expect(find.byType(_Diagonal), paints - ..rect( - rect: const Rect.fromLTWH(0, 0, 80, 100), - color: yellow, - ) - ..rect( - rect: const Rect.fromLTWH(80, 100, 110, 120), - color: green, - ) - ); - - await tester.pumpWidget(buildWidget( - topLeft: Container( - height: 200, - width: 100, - color: yellow, - child: const Text('topLeft'), - ), - bottomRight: Container( - height: 220, - width: 210, - color: green, - child: const Text('bottomRight'), - ), - )); - - expect(find.text('topLeft'), findsOneWidget); - expect(find.text('bottomRight'), findsOneWidget); - expect(tester.getSize(find.byType(_Diagonal)), const Size(100 + 210, 200 + 220)); - expect(find.byType(_Diagonal), paints - ..rect( - rect: const Rect.fromLTWH(0, 0, 100, 200), - color: yellow, - ) - ..rect( - rect: const Rect.fromLTWH(100, 200, 210, 220), - color: green, - ) - ); - - await tester.pumpWidget(buildWidget( - topLeft: Container( - height: 200, - width: 100, - color: yellow, - child: const Text('topLeft'), - ), - bottomRight: Container( - key: UniqueKey(), - height: 230, - width: 220, - color: green, - child: const Text('bottomRight'), - ), - )); - - expect(find.text('topLeft'), findsOneWidget); - expect(find.text('bottomRight'), findsOneWidget); - expect(tester.getSize(find.byType(_Diagonal)), const Size(100 + 220, 200 + 230)); - expect(find.byType(_Diagonal), paints - ..rect( - rect: const Rect.fromLTWH(0, 0, 100, 200), - color: yellow, - ) - ..rect( - rect: const Rect.fromLTWH(100, 200, 220, 230), - color: green, - ) - ); - - await tester.pumpWidget(buildWidget( - topLeft: Container( - height: 200, - width: 100, - color: yellow, - child: const Text('topLeft'), - ), - )); - - expect(find.text('topLeft'), findsOneWidget); - expect(find.text('bottomRight'), findsNothing); - expect(tester.getSize(find.byType(_Diagonal)), const Size(100, 200)); - expect(find.byType(_Diagonal), paints - ..rect( - rect: const Rect.fromLTWH(0, 0, 100, 200), - color: yellow, - ) - ); - - await tester.pumpWidget(buildWidget()); - expect(find.text('topLeft'), findsNothing); - expect(find.text('bottomRight'), findsNothing); - expect(tester.getSize(find.byType(_Diagonal)), Size.zero); - expect(find.byType(_Diagonal), paintsNothing); - - await tester.pumpWidget(Container()); - expect(find.byType(_Diagonal), findsNothing); - }); - - test('nameForSlot', () { - expect(_RenderDiagonal().publicNameForSlot(_DiagonalSlot.bottomRight), 'bottomRight'); - expect(_RenderDiagonal().publicNameForSlot(_DiagonalSlot.topLeft), 'topLeft'); - final _Slot slot = _Slot(); - expect(_RenderTest().publicNameForSlot(slot), slot.toString()); - }); - - testWidgets('debugDescribeChildren', (WidgetTester tester) async { - await tester.pumpWidget(buildWidget( - topLeft: const SizedBox( - height: 100, - width: 80, - ), - bottomRight: const SizedBox( - height: 120, - width: 110, - ), - )); - - expect( - tester.renderObject(find.byType(_Diagonal)).toStringDeep(), - equalsIgnoringHashCodes(r''' -_RenderDiagonal#00000 relayoutBoundary=up1 - │ creator: _Diagonal ← Align ← Directionality ← [root] - │ parentData: offset=Offset(0.0, 0.0) (can use size) - │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0) - │ size: Size(190.0, 220.0) - │ - ├─topLeft: RenderConstrainedBox#00000 relayoutBoundary=up2 - │ creator: SizedBox ← _Diagonal ← Align ← Directionality ← [root] - │ parentData: offset=Offset(0.0, 0.0) (can use size) - │ constraints: BoxConstraints(unconstrained) - │ size: Size(80.0, 100.0) - │ additionalConstraints: BoxConstraints(w=80.0, h=100.0) - │ - └─bottomRight: RenderConstrainedBox#00000 relayoutBoundary=up2 - creator: SizedBox ← _Diagonal ← Align ← Directionality ← [root] - parentData: offset=Offset(80.0, 100.0) (can use size) - constraints: BoxConstraints(unconstrained) - size: Size(110.0, 120.0) - additionalConstraints: BoxConstraints(w=110.0, h=120.0) -''') - ); - }); -} - -Widget buildWidget({Widget? topLeft, Widget? bottomRight}) { - return Directionality( - textDirection: TextDirection.ltr, - child: Align( - alignment: Alignment.topLeft, - child: _Diagonal( - topLeft: topLeft, - bottomRight: bottomRight, - ), - ), - ); -} - -enum _DiagonalSlot { - topLeft, - bottomRight, -} - -class _Diagonal extends RenderObjectWidget with SlottedMultiChildRenderObjectWidgetMixin<_DiagonalSlot> { - const _Diagonal({ - Key? key, - this.topLeft, - this.bottomRight, - }) : super(key: key); - - final Widget? topLeft; - final Widget? bottomRight; - - @override - Iterable<_DiagonalSlot> get slots => _DiagonalSlot.values; - - @override - Widget? childForSlot(_DiagonalSlot slot) { - switch (slot) { - case _DiagonalSlot.topLeft: - return topLeft; - case _DiagonalSlot.bottomRight: - return bottomRight; - } - } - - @override - SlottedContainerRenderObjectMixin<_DiagonalSlot> createRenderObject( - BuildContext context, - ) { - return _RenderDiagonal(); - } -} - -class _RenderDiagonal extends RenderBox with SlottedContainerRenderObjectMixin<_DiagonalSlot> { - RenderBox? get _topLeft => childForSlot(_DiagonalSlot.topLeft); - RenderBox? get _bottomRight => childForSlot(_DiagonalSlot.bottomRight); - - @override - void performLayout() { - const BoxConstraints childConstraints = BoxConstraints(); - - Size topLeftSize = Size.zero; - if (_topLeft != null) { - _topLeft!.layout(childConstraints, parentUsesSize: true); - _positionChild(_topLeft!, Offset.zero); - topLeftSize = _topLeft!.size; - } - - Size bottomRightSize = Size.zero; - if (_bottomRight != null) { - _bottomRight!.layout(childConstraints, parentUsesSize: true); - _positionChild( - _bottomRight!, - Offset(topLeftSize.width, topLeftSize.height), - ); - bottomRightSize = _bottomRight!.size; - } - - size = constraints.constrain(Size( - topLeftSize.width + bottomRightSize.width, - topLeftSize.height + bottomRightSize.height, - )); - } - - void _positionChild(RenderBox child, Offset offset) { - (child.parentData! as BoxParentData).offset = offset; - } - - @override - void paint(PaintingContext context, Offset offset) { - if (_topLeft != null) { - _paintChild(_topLeft!, context, offset); - } - if (_bottomRight != null) { - _paintChild(_bottomRight!, context, offset); - } - } - - void _paintChild(RenderBox child, PaintingContext context, Offset offset) { - final BoxParentData childParentData = child.parentData! as BoxParentData; - context.paintChild(child, childParentData.offset + offset); - } - - String publicNameForSlot(_DiagonalSlot slot) => debugNameForSlot(slot); -} - -class _Slot { - @override - String toString() => describeIdentity(this); -} - -class _RenderTest extends RenderBox with SlottedContainerRenderObjectMixin<_Slot> { - String publicNameForSlot(_Slot slot) => debugNameForSlot(slot); -} diff --git a/packages/flutter/test/widgets/text_editing_action_target_test.dart b/packages/flutter/test/widgets/text_editing_action_target_test.dart new file mode 100644 index 0000000000000..99363055a73f7 --- /dev/null +++ b/packages/flutter/test/widgets/text_editing_action_target_test.dart @@ -0,0 +1,1951 @@ +// 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:io' show Platform; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../rendering/rendering_tester.dart'; +import 'clipboard_utils.dart'; + +class _FakeEditableTextState with TextSelectionDelegate, TextEditingActionTarget { + _FakeEditableTextState({ + required this.textEditingValue, + // Render editable parameters: + this.obscureText = false, + required this.textSpan, + this.textDirection = TextDirection.ltr, + }); + + final TextDirection textDirection; + final TextSpan textSpan; + + RenderEditable? _renderEditable; + RenderEditable get renderEditable { + if (_renderEditable != null) { + return _renderEditable!; + } + _renderEditable = RenderEditable( + backgroundCursorColor: Colors.grey, + selectionColor: Colors.black, + textDirection: textDirection, + cursorColor: Colors.red, + offset: ViewportOffset.zero(), + textSelectionDelegate: this, + startHandleLayerLink: LayerLink(), + endHandleLayerLink: LayerLink(), + text: textSpan, + selection: textEditingValue.selection, + ); + return _renderEditable!; + } + + // Start TextSelectionDelegate + + @override + TextEditingValue textEditingValue; + + @override + void hideToolbar([bool hideHandles = true]) { } + + @override + void userUpdateTextEditingValue(TextEditingValue value, SelectionChangedCause cause) { } + + @override + void bringIntoView(TextPosition position) { } + + // End TextSelectionDelegate + // Start TextEditingActionTarget + + @override + bool get readOnly => false; + + @override + final bool obscureText; + + @override + bool get selectionEnabled => true; + + @override + TextLayoutMetrics get textLayoutMetrics => renderEditable; + + @override + void setSelection(TextSelection selection, SelectionChangedCause cause) { + renderEditable.selection = selection; + textEditingValue = textEditingValue.copyWith( + selection: selection, + ); + } + + @override + void setTextEditingValue(TextEditingValue newValue, SelectionChangedCause cause) { + textEditingValue = newValue; + } + + @override + void debugAssertLayoutUpToDate() {} + + // End TextEditingActionTarget +} + +void main() { + final MockClipboard mockClipboard = MockClipboard(); + // Ensure that all TestRenderingFlutterBinding bindings are initialized. + renderer; + + setUp(() async { + TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler( + SystemChannels.platform, + mockClipboard.handleMethodCall, + ); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler( + SystemChannels.platform, + null, + ); + }); + + test('moveSelectionLeft/RightByLine stays on the current line', () async { + const String text = 'one two three\n\nfour five six'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + + editableTextState.setSelection(const TextSelection.collapsed(offset: 0), SelectionChangedCause.tap); + pumpFrame(); + + // Move to the end of the first line. + editableTextState.moveSelectionRightByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 13); + expect(editableTextState.textEditingValue.selection.affinity, TextAffinity.upstream); + // RenderEditable relies on its parent that passes onSelectionChanged to set + // the selection. + + // Try moveSelectionRightByLine again and nothing happens because we're + // already at the end of a line. + editableTextState.moveSelectionRightByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 13); + expect(editableTextState.textEditingValue.selection.affinity, TextAffinity.upstream); + + // Move back to the start of the line. + editableTextState.moveSelectionLeftByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + expect(editableTextState.textEditingValue.selection.affinity, TextAffinity.downstream); + + // Trying moveSelectionLeftByLine does nothing at the leftmost of the field. + editableTextState.moveSelectionLeftByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + expect(editableTextState.textEditingValue.selection.affinity, TextAffinity.downstream); + + // Move the selection to the empty line. + editableTextState.moveSelectionRightByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 13); + expect(editableTextState.textEditingValue.selection.affinity, TextAffinity.upstream); + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 14); + expect(editableTextState.textEditingValue.selection.affinity, TextAffinity.downstream); + + // Neither moveSelectionLeftByLine nor moveSelectionRightByLine do anything + // here, because we're at both the beginning and end of the line. + editableTextState.moveSelectionLeftByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 14); + expect(editableTextState.textEditingValue.selection.affinity, TextAffinity.downstream); + editableTextState.moveSelectionRightByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 14); + expect(editableTextState.textEditingValue.selection.affinity, TextAffinity.downstream); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('arrow keys and delete handle simple text correctly', () async { + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: 'test', + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: 'test', + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + + editableTextState.setSelection(const TextSelection.collapsed(offset: 0), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 1); + + editableTextState.moveSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'est'); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('arrow keys and delete handle surrogate pairs correctly', () async { + const String text = '0123😆6789'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + + editableTextState.setSelection(const TextSelection.collapsed(offset: 4), SelectionChangedCause.keyboard); + pumpFrame(); + + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 6); + + editableTextState.moveSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 4); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, '01236789'); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('arrow keys and delete handle grapheme clusters correctly', () async { + const String text = '0123👨‍👩‍👦2345'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + + editableTextState.setSelection(const TextSelection.collapsed(offset: 4), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 12); + + editableTextState.moveSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 4); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, '01232345'); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('arrow keys and delete handle surrogate pairs correctly case 2', () async { + const String text = '\u{1F44D}'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + + editableTextState.setSelection(const TextSelection.collapsed(offset: 0), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 2); + + editableTextState.moveSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, ''); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('arrow keys work after detaching the widget and attaching it again', () async { + const String text = 'W Szczebrzeszynie chrząszcz brzmi w trzcinie'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + final PipelineOwner pipelineOwner = PipelineOwner(); + editable.attach(pipelineOwner); + editable.hasFocus = true; + editable.detach(); + layout(editable); + editable.hasFocus = true; + editableTextState.setSelection(const TextSelection.collapsed(offset: 0), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editable.selection?.isCollapsed, true); + expect(editable.selection?.baseOffset, 4); + + editableTextState.moveSelectionLeft(SelectionChangedCause.keyboard); + expect(editable.selection?.isCollapsed, true); + expect(editable.selection?.baseOffset, 3); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'W Sczebrzeszynie chrząszcz brzmi w trzcinie'); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('RenderEditable registers and unregisters raw keyboard listener correctly', () async { + const String text = 'how are you'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + final PipelineOwner pipelineOwner = PipelineOwner(); + editable.attach(pipelineOwner); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'ow are you'); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('arrow keys with selection text', () async { + const String text = '012345'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + + editableTextState.setSelection(const TextSelection(baseOffset: 2, extentOffset: 4), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 4); + + editableTextState.setSelection(const TextSelection(baseOffset: 4, extentOffset: 2), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 4); + + editableTextState.setSelection(const TextSelection(baseOffset: 2, extentOffset: 4), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.moveSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 2); + + editableTextState.setSelection(const TextSelection(baseOffset: 4, extentOffset: 2), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.moveSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 2); + }); + + test('arrow keys with selection text and shift', () async { + const String text = '012345'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + + editableTextState.setSelection(const TextSelection(baseOffset: 2, extentOffset: 4), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.extendSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, false); + expect(editableTextState.textEditingValue.selection.baseOffset, 2); + expect(editableTextState.textEditingValue.selection.extentOffset, 5); + + editableTextState.setSelection(const TextSelection(baseOffset: 4, extentOffset: 2), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.extendSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, false); + expect(editableTextState.textEditingValue.selection.baseOffset, 4); + expect(editableTextState.textEditingValue.selection.extentOffset, 3); + + editableTextState.setSelection(const TextSelection(baseOffset: 2, extentOffset: 4), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.extendSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, false); + expect(editableTextState.textEditingValue.selection.baseOffset, 2); + expect(editableTextState.textEditingValue.selection.extentOffset, 3); + + editableTextState.setSelection(const TextSelection(baseOffset: 4, extentOffset: 2), SelectionChangedCause.tap); + pumpFrame(); + + editableTextState.extendSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, false); + expect(editableTextState.textEditingValue.selection.baseOffset, 4); + expect(editableTextState.textEditingValue.selection.extentOffset, 1); + }); + + test('respects enableInteractiveSelection', () async { + const String text = '012345'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + + editableTextState.setSelection(const TextSelection.collapsed(offset: 2), SelectionChangedCause.tap); + pumpFrame(); + + await simulateKeyDownEvent(LogicalKeyboardKey.shift); + + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 3); + + editableTextState.moveSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 2); + + final LogicalKeyboardKey wordModifier = + Platform.isMacOS ? LogicalKeyboardKey.alt : LogicalKeyboardKey.control; + + await simulateKeyDownEvent(wordModifier); + + editableTextState.moveSelectionRightByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 6); + + editableTextState.moveSelectionLeftByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + + await simulateKeyUpEvent(wordModifier); + await simulateKeyUpEvent(LogicalKeyboardKey.shift); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87681 + + group('delete', () { + test('when as a non-collapsed selection, it should delete a selection', () async { + const String text = 'test'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection(baseOffset: 1, extentOffset: 3), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.delete(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'tt'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 1); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('when as simple text, it should delete the character to the left', () async { + const String text = 'test'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 3), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.delete(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'tet'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 2); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('when has surrogate pairs, it should delete the pair', () async { + const String text = '\u{1F44D}'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 2), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.delete(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, ''); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('when has grapheme clusters, it should delete the grapheme cluster', () async { + const String text = '0123👨‍👩‍👦2345'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 12), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.delete(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, '01232345'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 4); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('when is at the start of the text, it should be a no-op', () async { + const String text = 'test'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.delete(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'test'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('when input has obscured text, it should delete the character to the left', () async { + const String text = 'test'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + obscureText: true, + textSpan: const TextSpan( + text: '****', + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 4), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.delete(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'tes'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 3); + }); + + test('when using cjk characters', () async { + const String text = '用多個塊測試'; + const int offset = 4; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.delete(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, '用多個測試'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 3); + }); + + test('when using rtl', () async { + const String text = 'برنامج أهلا بالعالم'; + const int offset = text.length; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textDirection: TextDirection.rtl, + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.delete(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'برنامج أهلا بالعال'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, text.length - 1); + }); + }); + + group('deleteByWord', () { + test('when cursor is on the middle of a word, it should delete the left part of the word', () async { + const String text = 'test with multiple blocks'; + const int offset = 8; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test h multiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 5); + }); + + test('when includeWhiteSpace is true, it should treat a whiteSpace as a single word', () async { + const String text = 'test with multiple blocks'; + const int offset = 10; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'test withmultiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 9); + }); + + test('when cursor is after a word, it should delete the whole word', () async { + const String text = 'test with multiple blocks'; + const int offset = 9; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test multiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 5); + }); + + test('when cursor is preceeded by white spaces, it should delete the spaces and the next word to the left', () async { + const String text = 'test with multiple blocks'; + const int offset = 12; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test multiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 5); + }); + + test('when cursor is preceeded by tabs spaces', () async { + const String text = 'test with\t\t\tmultiple blocks'; + const int offset = 12; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test multiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 5); + }); + + test('when cursor is preceeded by break line, it should delete the breaking line and the word right before it', () async { + const String text = 'test with\nmultiple blocks'; + const int offset = 10; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test multiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 5); + }); + + test('when using cjk characters', () async { + const String text = '用多個塊測試'; + const int offset = 4; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, '用多個測試'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 3); + }); + + test('when using rtl', () async { + const String text = 'برنامج أهلا بالعالم'; + const int offset = text.length; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textDirection: TextDirection.rtl, + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'برنامج أهلا '); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 12); + }); + + test('when input has obscured text, it should delete everything before the selection', () async { + const int offset = 21; + const String text = 'test with multiple\n\n words'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + obscureText: true, + textSpan: const TextSpan( + text: '****', + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'words'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + }); + }); + + group('deleteByLine', () { + test('when cursor is on last character of a line, it should delete everything to the left', () async { + const String text = 'test with multiple blocks'; + const int offset = text.length; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, ''); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + }); + + test('when cursor is on the middle of a word, it should delete delete everything to the left', () async { + const String text = 'test with multiple blocks'; + const int offset = 8; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'h multiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + }); + + test('when previous character is a breakline, it should preserve it', () async { + const String text = 'test with\nmultiple blocks'; + const int offset = 10; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, text); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when text is multiline, it should delete until the first line break it finds', () async { + const String text = 'test with\n\nMore stuff right here.\nmultiple blocks'; + const int offset = 22; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'test with\n\nright here.\nmultiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 11); + }); + + test('when input has obscured text, it should delete everything before the selection', () async { + const int offset = 21; + const String text = 'test with multiple\n\n words'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + obscureText: true, + textSpan: const TextSpan( + text: '****', + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'words'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + }); + }); + + group('deleteForward', () { + test('when as a non-collapsed selection, it should delete a selection', () async { + const String text = 'test'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection(baseOffset: 1, extentOffset: 3), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'tt'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 1); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('when includeWhiteSpace is true, it should treat a whiteSpace as a single word', () async { + const String text = 'test with multiple blocks'; + const int offset = 9; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'test withmultiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 9); + }); + + test('when at the end of a text, it should be a no-op', () async { + const String text = 'test'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 4), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'test'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 4); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 + + test('when the input has obscured text, it should delete the forward character', () async { + const String text = 'test'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + obscureText: true, + textSpan: const TextSpan( + text: '****', + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: 0), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'est'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + }); + + test('when using cjk characters', () async { + const String text = '用多個塊測試'; + const int offset = 0; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, '多個塊測試'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + }); + + test('when using rtl', () async { + const String text = 'برنامج أهلا بالعالم'; + const int offset = 0; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textDirection: TextDirection.rtl, + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'رنامج أهلا بالعالم'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, 0); + }); + }); + + group('deleteForwardByWord', () { + test('when cursor is on the middle of a word, it should delete the next part of the word', () async { + const String text = 'test with multiple blocks'; + const int offset = 6; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test w multiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when cursor is before a word, it should delete the whole word', () async { + const String text = 'test with multiple blocks'; + const int offset = 10; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test with blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when cursor is preceeded by white spaces, it should delete the spaces and the next word', () async { + const String text = 'test with multiple blocks'; + const int offset = 9; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test with blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when cursor is before tabs, it should delete the tabs and the next word', () async { + const String text = 'test with\t\t\tmultiple blocks'; + const int offset = 9; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test with blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when cursor is followed by break line, it should delete the next word', () async { + const String text = 'test with\n\n\nmultiple blocks'; + const int offset = 9; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test with blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when using cjk characters', () async { + const String text = '用多個塊測試'; + const int offset = 0; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, '多個塊測試'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when using rtl', () async { + const String text = 'برنامج أهلا بالعالم'; + const int offset = 0; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textDirection: TextDirection.rtl, + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, ' أهلا بالعالم'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when input has obscured text, it should delete everything after the selection', () async { + const int offset = 4; + const String text = 'test'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + obscureText: true, + textSpan: const TextSpan( + text: '****', + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard, false); + expect(editableTextState.textEditingValue.text, 'test'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + }); + + group('deleteForwardByLine', () { + test('when cursor is on first character of a line, it should delete everything that follows', () async { + const String text = 'test with multiple blocks'; + const int offset = 4; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'test'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when cursor is on the middle of a word, it should delete delete everything that follows', () async { + const String text = 'test with multiple blocks'; + const int offset = 8; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'test wit'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when next character is a breakline, it should preserve it', () async { + const String text = 'test with\n\n\nmultiple blocks'; + const int offset = 9; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, text); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + + test('when text is multiline, it should delete until the first line break it finds', () async { + const String text = 'test with\n\nMore stuff right here.\nmultiple blocks'; + const int offset = 2; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'te\n\nMore stuff right here.\nmultiple blocks'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87685 + + test('when input has obscured text, it should delete everything after the selection', () async { + const String text = 'test with multiple\n\n words'; + const int offset = 4; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + obscureText: true, + textSpan: const TextSpan( + text: '****', + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: offset), + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + pumpFrame(); + + editableTextState.deleteForwardByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.text, 'test'); + expect(editableTextState.textEditingValue.selection.isCollapsed, true); + expect(editableTextState.textEditingValue.selection.baseOffset, offset); + }); + }); + + group('delete API implementations', () { + // Regression test for: https://github.com/flutter/flutter/issues/80226. + // + // This textSelectionDelegate has different text and selection from the + // render editable. + late _FakeEditableTextState delegate; + + late RenderEditable editable; + + setUp(() { + delegate = _FakeEditableTextState( + textSpan: TextSpan( + text: 'A ' * 50, + style: const TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: 'BBB', + selection: TextSelection.collapsed(offset: 0), + ), + ); + editable = delegate.renderEditable; + }); + + void verifyDoesNotCrashWithInconsistentTextEditingValue(void Function(SelectionChangedCause) method) { + editable = RenderEditable( + text: TextSpan( + text: 'A ' * 50, + ), + startHandleLayerLink: LayerLink(), + endHandleLayerLink: LayerLink(), + textDirection: TextDirection.ltr, + offset: ViewportOffset.fixed(0), + textSelectionDelegate: delegate, + selection: const TextSelection(baseOffset: 0, extentOffset: 50), + ); + + layout(editable, constraints: BoxConstraints.loose(const Size(500.0, 500.0))); + dynamic error; + try { + method(SelectionChangedCause.tap); + } catch (e) { + error = e; + } + expect(error, isNull); + } + + test('delete is not racy and handles composing region correctly', () { + delegate.textEditingValue = const TextEditingValue( + text: 'ABCDEF', + selection: TextSelection.collapsed(offset: 2), + composing: TextRange(start: 1, end: 6), + ); + verifyDoesNotCrashWithInconsistentTextEditingValue(delegate.delete); + final TextEditingValue textEditingValue = editable.textSelectionDelegate.textEditingValue; + expect(textEditingValue.text, 'ACDEF'); + expect(textEditingValue.selection.isCollapsed, isTrue); + expect(textEditingValue.selection.baseOffset, 1); + expect(textEditingValue.composing, const TextRange(start: 1, end: 5)); + }); + + test('deleteForward is not racy and handles composing region correctly', () { + delegate.textEditingValue = const TextEditingValue( + text: 'ABCDEF', + selection: TextSelection.collapsed(offset: 2), + composing: TextRange(start: 2, end: 6), + ); + final TextEditingActionTarget target = delegate; + verifyDoesNotCrashWithInconsistentTextEditingValue(target.deleteForward); + final TextEditingValue textEditingValue = editable.textSelectionDelegate.textEditingValue; + expect(textEditingValue.text, 'ABDEF'); + expect(textEditingValue.selection.isCollapsed, isTrue); + expect(textEditingValue.selection.baseOffset, 2); + expect(textEditingValue.composing, const TextRange(start: 2, end: 5)); + }); + }); + + test("When a selection is needed but it's invalid, nothing is changed", () async { + const String text = 'one two three\n\nfour five six'; + final _FakeEditableTextState editableTextState = _FakeEditableTextState( + textSpan: const TextSpan( + text: text, + style: TextStyle( + height: 1.0, fontSize: 10.0, fontFamily: 'Ahem', + ), + ), + textEditingValue: const TextEditingValue( + text: text, + ), + ); + final RenderEditable editable = editableTextState.renderEditable; + + layout(editable); + editable.hasFocus = true; + + editableTextState.delete(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + expect(editableTextState.textEditingValue.text, text); + + editableTextState.deleteByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + expect(editableTextState.textEditingValue.text, text); + + editableTextState.deleteByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + expect(editableTextState.textEditingValue.text, text); + + editableTextState.deleteForward(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + expect(editableTextState.textEditingValue.text, text); + + editableTextState.deleteForwardByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + expect(editableTextState.textEditingValue.text, text); + + editableTextState.deleteForwardByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + expect(editableTextState.textEditingValue.text, text); + + editableTextState.deleteToEnd(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + expect(editableTextState.textEditingValue.text, text); + + editableTextState.deleteToStart(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + expect(editableTextState.textEditingValue.text, text); + + editableTextState.expandSelectionToEnd(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.expandSelectionToStart(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.expandSelectionLeftByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.expandSelectionRightByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.extendSelectionDown(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.extendSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.extendSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.extendSelectionLeftByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.extendSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.extendSelectionRightByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.extendSelectionLeftByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.extendSelectionRightByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.extendSelectionUp(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.moveSelectionLeftByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.moveSelectionDown(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.moveSelectionLeft(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.moveSelectionLeftByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.moveSelectionRight(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.moveSelectionRightByLine(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.moveSelectionRightByWord(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.moveSelectionUp(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + + editableTextState.copySelection(SelectionChangedCause.keyboard); + ClipboardData? clipboardData = await Clipboard.getData(Clipboard.kTextPlain); + expect(clipboardData?.text, null); + + editableTextState.cutSelection(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + clipboardData = await Clipboard.getData(Clipboard.kTextPlain); + expect(clipboardData?.text, null); + + editableTextState.pasteText(SelectionChangedCause.keyboard); + expect(editableTextState.textEditingValue.selection.isValid, false); + expect(editableTextState.textEditingValue.text, text); + }); + + group('nextCharacter', () { + test('handles normal strings correctly', () { + expect(TextEditingActionTarget.nextCharacter(0, '01234567'), 1); + expect(TextEditingActionTarget.nextCharacter(3, '01234567'), 4); + expect(TextEditingActionTarget.nextCharacter(7, '01234567'), 8); + expect(TextEditingActionTarget.nextCharacter(8, '01234567'), 8); + }); + + test('throws for invalid indices', () { + expect(() => TextEditingActionTarget.nextCharacter(-1, '01234567'), throwsAssertionError); + expect(() => TextEditingActionTarget.nextCharacter(9, '01234567'), throwsAssertionError); + }); + + test('skips spaces in normal strings when includeWhitespace is false', () { + expect(TextEditingActionTarget.nextCharacter(3, '0123 5678', false), 5); + expect(TextEditingActionTarget.nextCharacter(4, '0123 5678', false), 5); + expect(TextEditingActionTarget.nextCharacter(3, '0123 0123', false), 10); + expect(TextEditingActionTarget.nextCharacter(2, '0123 0123', false), 3); + expect(TextEditingActionTarget.nextCharacter(4, '0123 0123', false), 10); + expect(TextEditingActionTarget.nextCharacter(9, '0123 0123', false), 10); + expect(TextEditingActionTarget.nextCharacter(10, '0123 0123', false), 11); + // If the subsequent characters are all whitespace, it returns the length + // of the string. + expect(TextEditingActionTarget.nextCharacter(5, '0123 ', false), 10); + }); + + test('handles surrogate pairs correctly', () { + expect(TextEditingActionTarget.nextCharacter(3, '0123👨👩👦0123'), 4); + expect(TextEditingActionTarget.nextCharacter(4, '0123👨👩👦0123'), 6); + expect(TextEditingActionTarget.nextCharacter(5, '0123👨👩👦0123'), 6); + expect(TextEditingActionTarget.nextCharacter(6, '0123👨👩👦0123'), 8); + expect(TextEditingActionTarget.nextCharacter(7, '0123👨👩👦0123'), 8); + expect(TextEditingActionTarget.nextCharacter(8, '0123👨👩👦0123'), 10); + expect(TextEditingActionTarget.nextCharacter(9, '0123👨👩👦0123'), 10); + expect(TextEditingActionTarget.nextCharacter(10, '0123👨👩👦0123'), 11); + }); + + test('handles extended grapheme clusters correctly', () { + expect(TextEditingActionTarget.nextCharacter(3, '0123👨‍👩‍👦2345'), 4); + expect(TextEditingActionTarget.nextCharacter(4, '0123👨‍👩‍👦2345'), 12); + // Even when extent falls within an extended grapheme cluster, it still + // identifies the whole grapheme cluster. + expect(TextEditingActionTarget.nextCharacter(5, '0123👨‍👩‍👦2345'), 12); + expect(TextEditingActionTarget.nextCharacter(12, '0123👨‍👩‍👦2345'), 13); + }); + }); + + group('previousCharacter', () { + test('handles normal strings correctly', () { + expect(TextEditingActionTarget.previousCharacter(8, '01234567'), 7); + expect(TextEditingActionTarget.previousCharacter(0, '01234567'), 0); + expect(TextEditingActionTarget.previousCharacter(1, '01234567'), 0); + expect(TextEditingActionTarget.previousCharacter(5, '01234567'), 4); + expect(TextEditingActionTarget.previousCharacter(8, '01234567'), 7); + }); + + test('throws for invalid indices', () { + expect(() => TextEditingActionTarget.previousCharacter(-1, '01234567'), throwsAssertionError); + expect(() => TextEditingActionTarget.previousCharacter(9, '01234567'), throwsAssertionError); + }); + + test('skips spaces in normal strings when includeWhitespace is false', () { + expect(TextEditingActionTarget.previousCharacter(5, '0123 0123', false), 3); + expect(TextEditingActionTarget.previousCharacter(10, '0123 0123', false), 3); + expect(TextEditingActionTarget.previousCharacter(11, '0123 0123', false), 10); + expect(TextEditingActionTarget.previousCharacter(9, '0123 0123', false), 3); + expect(TextEditingActionTarget.previousCharacter(4, '0123 0123', false), 3); + expect(TextEditingActionTarget.previousCharacter(3, '0123 0123', false), 2); + // If the previous characters are all whitespace, it returns zero. + expect(TextEditingActionTarget.previousCharacter(3, ' 0123', false), 0); + }); + + test('handles surrogate pairs correctly', () { + expect(TextEditingActionTarget.previousCharacter(11, '0123👨👩👦0123'), 10); + expect(TextEditingActionTarget.previousCharacter(10, '0123👨👩👦0123'), 8); + expect(TextEditingActionTarget.previousCharacter(9, '0123👨👩👦0123'), 8); + expect(TextEditingActionTarget.previousCharacter(8, '0123👨👩👦0123'), 6); + expect(TextEditingActionTarget.previousCharacter(7, '0123👨👩👦0123'), 6); + expect(TextEditingActionTarget.previousCharacter(6, '0123👨👩👦0123'), 4); + expect(TextEditingActionTarget.previousCharacter(5, '0123👨👩👦0123'), 4); + expect(TextEditingActionTarget.previousCharacter(4, '0123👨👩👦0123'), 3); + expect(TextEditingActionTarget.previousCharacter(3, '0123👨👩👦0123'), 2); + }); + + test('handles extended grapheme clusters correctly', () { + expect(TextEditingActionTarget.previousCharacter(13, '0123👨‍👩‍👦2345'), 12); + // Even when extent falls within an extended grapheme cluster, it still + // identifies the whole grapheme cluster. + expect(TextEditingActionTarget.previousCharacter(12, '0123👨‍👩‍👦2345'), 4); + expect(TextEditingActionTarget.previousCharacter(11, '0123👨‍👩‍👦2345'), 4); + expect(TextEditingActionTarget.previousCharacter(5, '0123👨‍👩‍👦2345'), 4); + expect(TextEditingActionTarget.previousCharacter(4, '0123👨‍👩‍👦2345'), 3); + }); + }); +} diff --git a/packages/flutter/test/widgets/text_selection_test.dart b/packages/flutter/test/widgets/text_selection_test.dart index 4b601acdbcc7b..04f7327dde320 100644 --- a/packages/flutter/test/widgets/text_selection_test.dart +++ b/packages/flutter/test/widgets/text_selection_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart' show defaultTargetPlatform; import 'package:flutter/gestures.dart' show PointerDeviceKind, kSecondaryButton; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -507,20 +506,8 @@ void main() { final FakeEditableTextState state = tester.state(find.byType(FakeEditableText)); final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable)); expect(state.showToolbarCalled, isFalse); - - switch (defaultTargetPlatform) { - case TargetPlatform.iOS: - case TargetPlatform.macOS: - expect(renderEditable.selectWordEdgeCalled, isTrue); - break; - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: - expect(renderEditable.selectPositionAtCalled, isTrue); - break; - } - }, variant: TargetPlatformVariant.all()); + expect(renderEditable.selectWordEdgeCalled, isTrue); + }); testWidgets('test TextSelectionGestureDetectorBuilder double tap', (WidgetTester tester) async { await pumpTextSelectionGestureDetectorBuilder(tester); diff --git a/packages/flutter/test/widgets/ticker_mode_test.dart b/packages/flutter/test/widgets/ticker_mode_test.dart index 8c1c089acd560..60a82730233bb 100644 --- a/packages/flutter/test/widgets/ticker_mode_test.dart +++ b/packages/flutter/test/widgets/ticker_mode_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -99,191 +98,36 @@ void main() { expect(outerTickCount, 0); expect(innerTickCount, 0); }); - - testWidgets('Changing TickerMode does not rebuild widgets with SingleTickerProviderStateMixin', (WidgetTester tester) async { - Widget widgetUnderTest({required bool tickerEnabled}) { - return TickerMode( - enabled: tickerEnabled, - child: const _TickingWidget(), - ); - } - _TickingWidgetState state() => tester.state<_TickingWidgetState>(find.byType(_TickingWidget)); - - await tester.pumpWidget(widgetUnderTest(tickerEnabled: true)); - expect(state().ticker.isTicking, isTrue); - expect(state().buildCount, 1); - - await tester.pumpWidget(widgetUnderTest(tickerEnabled: false)); - expect(state().ticker.isTicking, isFalse); - expect(state().buildCount, 1); - - await tester.pumpWidget(widgetUnderTest(tickerEnabled: true)); - expect(state().ticker.isTicking, isTrue); - expect(state().buildCount, 1); - }); - - testWidgets('Changing TickerMode does not rebuild widgets with TickerProviderStateMixin', (WidgetTester tester) async { - Widget widgetUnderTest({required bool tickerEnabled}) { - return TickerMode( - enabled: tickerEnabled, - child: const _MultiTickingWidget(), - ); - } - _MultiTickingWidgetState state() => tester.state<_MultiTickingWidgetState>(find.byType(_MultiTickingWidget)); - - await tester.pumpWidget(widgetUnderTest(tickerEnabled: true)); - expect(state().ticker.isTicking, isTrue); - expect(state().buildCount, 1); - - await tester.pumpWidget(widgetUnderTest(tickerEnabled: false)); - expect(state().ticker.isTicking, isFalse); - expect(state().buildCount, 1); - - await tester.pumpWidget(widgetUnderTest(tickerEnabled: true)); - expect(state().ticker.isTicking, isTrue); - expect(state().buildCount, 1); - }); - - testWidgets('Moving widgets with SingleTickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { - final GlobalKey tickingWidgetKey = GlobalKey(); - Widget widgetUnderTest({required LocalKey tickerModeKey, required bool tickerEnabled}) { - return TickerMode( - key: tickerModeKey, - enabled: tickerEnabled, - child: _TickingWidget(key: tickingWidgetKey), - ); - } - // Using different local keys to simulate changing TickerMode ancestors. - await tester.pumpWidget(widgetUnderTest(tickerEnabled: true, tickerModeKey: UniqueKey())); - final State tickerModeState = tester.state(find.byType(TickerMode)); - final _TickingWidgetState tickingState = tester.state<_TickingWidgetState>(find.byType(_TickingWidget)); - expect(tickingState.ticker.isTicking, isTrue); - - await tester.pumpWidget(widgetUnderTest(tickerEnabled: false, tickerModeKey: UniqueKey())); - expect(tester.state(find.byType(TickerMode)), isNot(same(tickerModeState))); - expect(tickingState, same(tester.state<_TickingWidgetState>(find.byType(_TickingWidget)))); - expect(tickingState.ticker.isTicking, isFalse); - }); - - testWidgets('Moving widgets with TickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { - final GlobalKey tickingWidgetKey = GlobalKey(); - Widget widgetUnderTest({required LocalKey tickerModeKey, required bool tickerEnabled}) { - return TickerMode( - key: tickerModeKey, - enabled: tickerEnabled, - child: _MultiTickingWidget(key: tickingWidgetKey), - ); - } - // Using different local keys to simulate changing TickerMode ancestors. - await tester.pumpWidget(widgetUnderTest(tickerEnabled: true, tickerModeKey: UniqueKey())); - final State tickerModeState = tester.state(find.byType(TickerMode)); - final _MultiTickingWidgetState tickingState = tester.state<_MultiTickingWidgetState>(find.byType(_MultiTickingWidget)); - expect(tickingState.ticker.isTicking, isTrue); - - await tester.pumpWidget(widgetUnderTest(tickerEnabled: false, tickerModeKey: UniqueKey())); - expect(tester.state(find.byType(TickerMode)), isNot(same(tickerModeState))); - expect(tickingState, same(tester.state<_MultiTickingWidgetState>(find.byType(_MultiTickingWidget)))); - expect(tickingState.ticker.isTicking, isFalse); - }); - - testWidgets('Ticking widgets in old route do not rebuild when new route is pushed', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp( - routes: <String, WidgetBuilder>{ - '/foo' : (BuildContext context) => const Text('New route'), - }, - home: Row( - children: const <Widget>[ - _TickingWidget(), - _MultiTickingWidget(), - Text('Old route'), - ], - ), - )); - - _MultiTickingWidgetState multiTickingState() => tester.state<_MultiTickingWidgetState>(find.byType(_MultiTickingWidget, skipOffstage: false)); - _TickingWidgetState tickingState() => tester.state<_TickingWidgetState>(find.byType(_TickingWidget, skipOffstage: false)); - - expect(find.text('Old route'), findsOneWidget); - expect(find.text('New route'), findsNothing); - - expect(multiTickingState().ticker.isTicking, isTrue); - expect(multiTickingState().buildCount, 1); - expect(tickingState().ticker.isTicking, isTrue); - expect(tickingState().buildCount, 1); - - tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/foo'); - await tester.pumpAndSettle(); - expect(find.text('Old route'), findsNothing); - expect(find.text('New route'), findsOneWidget); - - expect(multiTickingState().ticker.isTicking, isFalse); - expect(multiTickingState().buildCount, 1); - expect(tickingState().ticker.isTicking, isFalse); - expect(tickingState().buildCount, 1); - }); } class _TickingWidget extends StatefulWidget { - const _TickingWidget({Key? key, this.onTick}) : super(key: key); + const _TickingWidget({required this.onTick}); - final VoidCallback? onTick; + final VoidCallback onTick; @override State<_TickingWidget> createState() => _TickingWidgetState(); } class _TickingWidgetState extends State<_TickingWidget> with SingleTickerProviderStateMixin { - late Ticker ticker; - int buildCount = 0; - - @override - void initState() { - super.initState(); - ticker = createTicker((Duration _) { - widget.onTick?.call(); - })..start(); - } - - @override - Widget build(BuildContext context) { - buildCount += 1; - return Container(); - } - - @override - void dispose() { - ticker.dispose(); - super.dispose(); - } -} - -class _MultiTickingWidget extends StatefulWidget { - const _MultiTickingWidget({Key? key}) : super(key: key); - - @override - State<_MultiTickingWidget> createState() => _MultiTickingWidgetState(); -} - -class _MultiTickingWidgetState extends State<_MultiTickingWidget> with TickerProviderStateMixin { - late Ticker ticker; - int buildCount = 0; + late Ticker _ticker; @override void initState() { super.initState(); - ticker = createTicker((Duration _) { + _ticker = createTicker((Duration _) { + widget.onTick(); })..start(); } @override Widget build(BuildContext context) { - buildCount += 1; return Container(); } @override void dispose() { - ticker.dispose(); + _ticker.dispose(); super.dispose(); } } diff --git a/packages/flutter/test/widgets/title_test.dart b/packages/flutter/test/widgets/title_test.dart index 71dbf6f9e1c79..2fe657d406424 100644 --- a/packages/flutter/test/widgets/title_test.dart +++ b/packages/flutter/test/widgets/title_test.dart @@ -38,7 +38,6 @@ void main() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); - return null; }); await tester.pumpWidget(Title( diff --git a/packages/flutter/test/widgets/transform_test.dart b/packages/flutter/test/widgets/transform_test.dart index 7c2a3d8963556..aa0027fc0905d 100644 --- a/packages/flutter/test/widgets/transform_test.dart +++ b/packages/flutter/test/widgets/transform_test.dart @@ -393,11 +393,6 @@ void main() { skip: isBrowser, // due to https://github.com/flutter/flutter/issues/49857 ); - List<double> extractMatrix(ui.ImageFilter? filter) { - final List<String> numbers = filter.toString().split('[').last.split(']').first.split(','); - return numbers.map<double>((String str) => double.parse(str.trim())).toList(); - } - testWidgets('Transform.translate with FilterQuality produces filter layer', (WidgetTester tester) async { await tester.pumpWidget( Transform.translate( @@ -407,13 +402,6 @@ void main() { ), ); expect(tester.layers.whereType<ImageFilterLayer>().length, 1); - final ImageFilterLayer layer = tester.layers.whereType<ImageFilterLayer>().first; - expect(extractMatrix(layer.imageFilter), <double>[ - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 25.0, 25.0, 0.0, 1.0] - ); }); testWidgets('Transform.scale with FilterQuality produces filter layer', (WidgetTester tester) async { @@ -425,13 +413,6 @@ void main() { ), ); expect(tester.layers.whereType<ImageFilterLayer>().length, 1); - final ImageFilterLayer layer = tester.layers.whereType<ImageFilterLayer>().first; - expect(extractMatrix(layer.imageFilter), <double>[ - 3.14159, 0.0, 0.0, 0.0, - 0.0, 3.14159, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - -856.636, -642.477, 0.0, 1.0] - ); }); testWidgets('Transform.rotate with FilterQuality produces filter layer', (WidgetTester tester) async { @@ -443,35 +424,6 @@ void main() { ), ); expect(tester.layers.whereType<ImageFilterLayer>().length, 1); - final ImageFilterLayer layer = tester.layers.whereType<ImageFilterLayer>().first; - expect(extractMatrix(layer.imageFilter), <dynamic>[ - moreOrLessEquals(0.7071067811865476), moreOrLessEquals(0.7071067811865475), 0.0, 0.0, - moreOrLessEquals(-0.7071067811865475), moreOrLessEquals(0.7071067811865476), 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - moreOrLessEquals(329.28932188134524), moreOrLessEquals(-194.97474683058329), 0.0, 1.0] - ); - }); - - testWidgets('Offset Transform.rotate with FilterQuality produces filter layer', (WidgetTester tester) async { - await tester.pumpWidget( - SizedBox(width: 400, height: 400, - child: Center( - child: Transform.rotate( - angle: math.pi / 4, - filterQuality: FilterQuality.low, - child: const SizedBox(width: 100, height: 100), - ), - ), - ), - ); - expect(tester.layers.whereType<ImageFilterLayer>().length, 1); - final ImageFilterLayer layer = tester.layers.whereType<ImageFilterLayer>().first; - expect(extractMatrix(layer.imageFilter), <dynamic>[ - moreOrLessEquals(0.7071067811865476), moreOrLessEquals(0.7071067811865475), 0.0, 0.0, - moreOrLessEquals(-0.7071067811865475), moreOrLessEquals(0.7071067811865476), 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - moreOrLessEquals(329.28932188134524), moreOrLessEquals(-194.97474683058329), 0.0, 1.0] - ); }); testWidgets('Transform layers update to match child and filterQuality', (WidgetTester tester) async { @@ -553,93 +505,6 @@ void main() { matchesGoldenFile('transform_golden.BitmapRotate.png'), ); }); - - testWidgets("Transform.scale() does not accept all three 'scale', 'scaleX' and 'scaleY' parameters to be non-null", (WidgetTester tester) async { - await expectLater(() { - tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: Transform.scale( - scale: 1.0, - scaleX: 1.0, - scaleY: 1.0, - child: const SizedBox( - height: 100, - width: 100, - ), - ), - ))); - }, throwsAssertionError); - }); - - testWidgets("Transform.scale() needs at least one of 'scale', 'scaleX' and 'scaleY' to be non-null, otherwise throws AssertionError", (WidgetTester tester) async { - await expectLater(() { - tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: Transform.scale( - child: const SizedBox( - height: 100, - width: 100, - ), - ), - ))); - }, throwsAssertionError); - }); - - testWidgets("Transform.scale() scales widget uniformly with 'scale' parameter", (WidgetTester tester) async { - const double _scale = 1.5; - const double _height = 100; - const double _width = 150; - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: SizedBox( - height: 400, - width: 400, - child: Center( - child: Transform.scale( - scale: _scale, - child: Container( - height: _height, - width: _width, - decoration: const BoxDecoration(), - ), - ), - ), - ))); - - const Size _target = Size(_width * _scale, _height * _scale); - - expect(tester.getBottomRight(find.byType(Container)), _target.bottomRight(tester.getTopLeft(find.byType(Container)))); - }); - - testWidgets("Transform.scale() scales widget according to 'scaleX' and 'scaleY'", (WidgetTester tester) async { - const double _scaleX = 1.5; - const double _scaleY = 1.2; - const double _height = 100; - const double _width = 150; - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: SizedBox( - height: 400, - width: 400, - child: Center( - child: Transform.scale( - scaleX: _scaleX, - scaleY: _scaleY, - child: Container( - height: _height, - width: _width, - decoration: const BoxDecoration(), - ), - ), - ), - ))); - - const Size _target = Size(_width * _scaleX, _height * _scaleY); - - expect(tester.getBottomRight(find.byType(Container)), _target.bottomRight(tester.getTopLeft(find.byType(Container)))); - }); } class TestRectPainter extends CustomPainter { diff --git a/packages/flutter/test_fixes/material.dart b/packages/flutter/test_fixes/material.dart index 73c1f71f012d0..4aa084c9fa211 100644 --- a/packages/flutter/test_fixes/material.dart +++ b/packages/flutter/test_fixes/material.dart @@ -500,25 +500,4 @@ void main() { AppBarTheme appBarTheme = AppBarTheme(); appBarTheme.color; - - // Changes made in https://github.com/flutter/flutter/pull/93396 - ThemeData themeData = ThemeData(); - themeData = ThemeData(primaryColorBrightness: Brightness.dark); - themeData = ThemeData.raw(primaryColorBrightness: Brightness.dark); - themeData = themeData.copyWith(primaryColorBrightness: Brightness.dark); - themeData.primaryColorBrightness; // Removing field reference not supported. - - // Changes made in https://github.com/flutter/flutter/pull/93427 - ColorScheme colorScheme = ColorScheme(); - colorScheme = ColorScheme(primaryVariant: Colors.black, secondaryVariant: Colors.white); - colorScheme = ColorScheme.light(primaryVariant: Colors.black, secondaryVariant: Colors.white); - colorScheme = ColorScheme.dark(primaryVariant: Colors.black, secondaryVariant: Colors.white); - colorScheme = ColorScheme.highContrastLight(primaryVariant: Colors.black, secondaryVariant: Colors.white); - colorScheme = ColorScheme.highContrastDark(primaryVariant: Colors.black, secondaryVariant: Colors.white); - colorScheme = colorScheme.copyWith(primaryVariant: Colors.black, secondaryVariant: Colors.white); - colorScheme.primaryVariant; - colorScheme.secondaryVariant; - - // Changes made in https://github.com/flutter/flutter/pull/96115 - Icon icon = Icons.pie_chart_outlined; } diff --git a/packages/flutter/test_fixes/material.dart.expect b/packages/flutter/test_fixes/material.dart.expect index 2cfc8bf955b62..1c1f84d4e2c5b 100644 --- a/packages/flutter/test_fixes/material.dart.expect +++ b/packages/flutter/test_fixes/material.dart.expect @@ -473,25 +473,4 @@ void main() { AppBarTheme appBarTheme = AppBarTheme(); appBarTheme.backgroundColor; - - // Changes made in https://github.com/flutter/flutter/pull/93396 - ThemeData themeData = ThemeData(); - themeData = ThemeData(); - themeData = ThemeData.raw(); - themeData = themeData.copyWith(); - themeData.primaryColorBrightness; // Removing field reference not supported. - - // Changes made in https://github.com/flutter/flutter/pull/93427 - ColorScheme colorScheme = ColorScheme(); - colorScheme = ColorScheme(); - colorScheme = ColorScheme.light(); - colorScheme = ColorScheme.dark(); - colorScheme = ColorScheme.highContrastLight(); - colorScheme = ColorScheme.highContrastDark(); - colorScheme = colorScheme.copyWith(); - colorScheme.primaryContainer; - colorScheme.secondaryContainer; - - // Changes made in https://github.com/flutter/flutter/pull/96115 - Icon icon = Icons.pie_chart_outline; } diff --git a/packages/flutter/test_private/pubspec.yaml b/packages/flutter/test_private/pubspec.yaml index 37a30e2fce8ac..210476e14ff4e 100644 --- a/packages/flutter/test_private/pubspec.yaml +++ b/packages/flutter/test_private/pubspec.yaml @@ -7,7 +7,7 @@ environment: dependencies: # To update these, use "flutter update-packages --force-upgrade". meta: 1.7.0 - path: 1.8.1 + path: 1.8.0 process: 4.2.4 process_runner: 4.1.2 @@ -15,6 +15,6 @@ dependencies: async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 695a +# PUBSPEC CHECKSUM: 475a diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index eac02b6a6dd9b..942ed24f354ed 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -22,14 +22,13 @@ dependencies: charcode: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_goldens: @@ -37,7 +36,7 @@ dev_dependencies: fake_async: 1.2.0 file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 8477 +# PUBSPEC CHECKSUM: 7714 diff --git a/packages/flutter/test_profile/README.md b/packages/flutter/test_profile/README.md deleted file mode 100644 index 9ce3dd47ab83b..0000000000000 --- a/packages/flutter/test_profile/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This folder contains unit tests that are run with `kProfileMode` set to true. This can be used for unit testing code that is guarded by this boolean, such as in cases where debug code is intentionally ellided for performance or code size reasons. The unit tests are still run in the VM and are not otherwise precompiled. - -To run these test from the command line, use the command: `flutter test --dart-define=dart.vm.profile=true test_release/` diff --git a/packages/flutter/test_profile/basic_test.dart b/packages/flutter/test_profile/basic_test.dart deleted file mode 100644 index 5b17379dcdc12..0000000000000 --- a/packages/flutter/test_profile/basic_test.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('Can build widget tree in profile mode with asserts enabled', (WidgetTester tester) async { - await tester.pumpWidget(const MaterialApp(home: Scaffold(body: Center(child: Text('Hello World'))))); - - expect(tester.takeException(), isNull); - }); -} diff --git a/packages/flutter/test_release/diagnostics_test.dart b/packages/flutter/test_release/diagnostics_test.dart index a253670d04ad9..038137d5b80af 100644 --- a/packages/flutter/test_release/diagnostics_test.dart +++ b/packages/flutter/test_release/diagnostics_test.dart @@ -31,7 +31,7 @@ class TestDiagnosticsNode extends DiagnosticsNode { } @override - String toDescription({TextTreeConfiguration? parentConfiguration}) { + String? toDescription({TextTreeConfiguration? parentConfiguration}) { return 'Test Description'; } diff --git a/packages/flutter_driver/lib/src/driver/gc_summarizer.dart b/packages/flutter_driver/lib/src/driver/gc_summarizer.dart deleted file mode 100644 index 2779e782fc79b..0000000000000 --- a/packages/flutter_driver/lib/src/driver/gc_summarizer.dart +++ /dev/null @@ -1,59 +0,0 @@ -// 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 'timeline.dart'; - -/// GC related timeline events. -/// -/// All these events occur only on the UI thread and are non overlapping. -const Set<String> kGCRootEvents = <String>{ - 'CollectNewGeneration', - 'CollectOldGeneration', - 'EvacuateNewGeneration', - 'StartConcurrentMark', -}; - -/// Summarizes [TimelineEvents]s corresponding to [kGCRootEvents] category. -/// -/// A sample event (some fields have been omitted for brevity): -/// ``` -/// { -/// "name": "StartConcurrentMarking", -/// "cat": "GC", -/// "ts": 3240710599608, -/// } -/// ``` -/// This class provides methods to compute the total time spend in GC on -/// the UI thread. -class GCSummarizer { - GCSummarizer._(this.totalGCTimeMillis); - - /// Creates a [GCSummarizer] given the timeline events. - static GCSummarizer fromEvents(List<TimelineEvent> gcEvents) { - double totalGCTimeMillis = 0; - TimelineEvent? lastGCBeginEvent; - - for (final TimelineEvent event in gcEvents) { - if (!kGCRootEvents.contains(event.name)) { - continue; - } - if (event.phase == 'B') { - lastGCBeginEvent = event; - } else if (lastGCBeginEvent != null) { - // These events must not overlap. - assert(event.name == lastGCBeginEvent.name, - 'Expected "${lastGCBeginEvent.name}" got "${event.name}"'); - final double st = lastGCBeginEvent.timestampMicros!.toDouble(); - final double end = event.timestampMicros!.toDouble(); - lastGCBeginEvent = null; - totalGCTimeMillis += (end - st) / 1000; - } - } - - return GCSummarizer._(totalGCTimeMillis); - } - - /// Total time spent doing GC on the UI thread. - final double totalGCTimeMillis; -} diff --git a/packages/flutter_driver/lib/src/driver/timeline_summary.dart b/packages/flutter_driver/lib/src/driver/timeline_summary.dart index 73af4ae637aa3..d766c7196ded3 100644 --- a/packages/flutter_driver/lib/src/driver/timeline_summary.dart +++ b/packages/flutter_driver/lib/src/driver/timeline_summary.dart @@ -9,7 +9,6 @@ import 'package:file/file.dart'; import 'package:path/path.dart' as path; import 'common.dart'; -import 'gc_summarizer.dart'; import 'percentile_utils.dart'; import 'profiling_summarizer.dart'; import 'raster_cache_summarizer.dart'; @@ -219,7 +218,6 @@ class TimelineSummary { final VsyncFrameLagSummarizer vsyncFrameLagSummarizer = _vsyncFrameLagSummarizer(); final Map<String, dynamic> profilingSummary = _profilingSummarizer().summarize(); final RasterCacheSummarizer rasterCacheSummarizer = _rasterCacheSummarizer(); - final GCSummarizer gcSummarizer = _gcSummarizer(); final Map<String, dynamic> timelineSummary = <String, dynamic>{ 'average_frame_build_time_millis': computeAverageFrameBuildTimeMillis(), @@ -270,7 +268,6 @@ class TimelineSummary { '90th_percentile_picture_cache_memory': rasterCacheSummarizer.computePercentilePictureMemory(90.0), '99th_percentile_picture_cache_memory': rasterCacheSummarizer.computePercentilePictureMemory(99.0), 'worst_picture_cache_memory': rasterCacheSummarizer.computeWorstPictureMemory(), - 'total_ui_gc_time': gcSummarizer.totalGCTimeMillis, }; timelineSummary.addAll(profilingSummary); @@ -435,6 +432,4 @@ class TimelineSummary { VsyncFrameLagSummarizer _vsyncFrameLagSummarizer() => VsyncFrameLagSummarizer(_extractEventsWithNames(kVsyncTimelineEventNames)); RasterCacheSummarizer _rasterCacheSummarizer() => RasterCacheSummarizer(_extractNamedEvents(kRasterCacheEvent)); - - GCSummarizer _gcSummarizer() => GCSummarizer.fromEvents(_extractEventsWithNames(kGCRootEvents)); } diff --git a/packages/flutter_driver/lib/src/extension/extension.dart b/packages/flutter_driver/lib/src/extension/extension.dart index 44e57ec4a260f..c5578c9cdf824 100644 --- a/packages/flutter_driver/lib/src/extension/extension.dart +++ b/packages/flutter_driver/lib/src/extension/extension.dart @@ -366,12 +366,11 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory, final Command command = deserializeCommand(params, this); assert(WidgetsBinding.instance!.isRootWidgetAttached || !command.requiresRootWidgetAttached, 'No root widget is attached; have you remembered to call runApp()?'); - Future<Result> responseFuture = handleCommand(command, _prober, this); - if (command.timeout != null) { - responseFuture = responseFuture.timeout(command.timeout!); - } - final Result response = await responseFuture; - return _makeResponse(response.toJson()); + Future<Result?> responseFuture = handleCommand(command, _prober, this); + if (command.timeout != null) + responseFuture = responseFuture.timeout(command.timeout ?? Duration.zero); + final Result? response = await responseFuture; + return _makeResponse(response?.toJson()); } on TimeoutException catch (error, stackTrace) { final String message = 'Timeout while executing $commandKind: $error\n$stackTrace'; _log(message); diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 2ad8d31f35f2b..eb4ef3f9cd5a3 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_driver description: Integration and performance test API for Flutter applications -homepage: https://flutter.dev +homepage: http://flutter.dev environment: sdk: ">=2.12.0-0 <3.0.0" @@ -13,12 +13,12 @@ dependencies: sdk: flutter fuchsia_remote_debug_protocol: sdk: flutter - path: 1.8.1 + path: 1.8.0 meta: 1.7.0 - vm_service: 7.5.0 + vm_service: 7.3.0 webdriver: 3.0.0 - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,8 +27,7 @@ dependencies: collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,16 +35,16 @@ dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: fake_async: 1.2.0 - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -55,11 +54,12 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -68,10 +68,10 @@ dev_dependencies: shelf_web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c2d1 +# PUBSPEC CHECKSUM: 093a diff --git a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart index 38131e7af99a7..b7456cf8ada4f 100644 --- a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart +++ b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart @@ -95,36 +95,37 @@ void main() { 'ts': timeStamp, }; - List<Map<String, dynamic>> _genGC(String name, int count, int startTime, int timeDiff) { - int ts = startTime; - bool begin = true; - final List<Map<String, dynamic>> ret = <Map<String, dynamic>>[]; - for (int i = 0; i < count; i++) { - ret.add(<String, dynamic>{ - 'name': name, - 'cat': 'GC', - 'tid': 19695, - 'pid': 19650, - 'ts': ts, - 'tts': ts, - 'ph': begin ? 'B' : 'E', - 'args': <String, dynamic>{ - 'isolateGroupId': 'isolateGroups/10824099774666259225', - }, - }); - ts = ts + timeDiff; - begin = !begin; - } - return ret; - } - - List<Map<String, dynamic>> newGenGC(int count, int startTime, int timeDiff) { - return _genGC('CollectNewGeneration', count, startTime, timeDiff); - } - - List<Map<String, dynamic>> oldGenGC(int count, int startTime, int timeDiff) { - return _genGC('CollectOldGeneration', count, startTime, timeDiff); - } + List<Map<String, dynamic>> newGenGC(int count) => List<Map<String, dynamic>>.filled( + count, + <String, dynamic>{ + 'name': 'CollectNewGeneration', + 'cat': 'GC', + 'tid': 19695, + 'pid': 19650, + 'ts': 358849612473, + 'tts': 476761, + 'ph': 'B', + 'args': <String, dynamic>{ + 'isolateGroupId': 'isolateGroups/10824099774666259225', + }, + }, + ); + + List<Map<String, dynamic>> oldGenGC(int count) => List<Map<String, dynamic>>.filled( + count, + <String, dynamic>{ + 'name': 'CollectOldGeneration', + 'cat': 'GC', + 'tid': 19695, + 'pid': 19650, + 'ts': 358849612473, + 'tts': 476761, + 'ph': 'B', + 'args': <String, dynamic>{ + 'isolateGroupId': 'isolateGroups/10824099774666259225', + }, + }, + ); List<Map<String, dynamic>> rasterizeTimeSequenceInMillis(List<int> sequence) { final List<Map<String, dynamic>> result = <Map<String, dynamic>>[]; @@ -419,8 +420,8 @@ void main() { begin(1000), end(19000), begin(19000), end(29000), begin(29000), end(49000), - ...newGenGC(4, 10, 100), - ...oldGenGC(5, 10000, 100), + ...newGenGC(4), + ...oldGenGC(5), frameBegin(1000), frameEnd(18000), frameBegin(19000), frameEnd(28000), frameBegin(29000), frameEnd(48000), @@ -466,7 +467,6 @@ void main() { '90th_percentile_picture_cache_memory': 0.0, '99th_percentile_picture_cache_memory': 0.0, 'worst_picture_cache_memory': 0.0, - 'total_ui_gc_time': 0.4, }, ); }); @@ -526,8 +526,8 @@ void main() { lagBegin(1000, 4), lagEnd(2000, 4), lagBegin(1200, 12), lagEnd(2400, 12), lagBegin(4200, 8), lagEnd(9400, 8), - ...newGenGC(4, 10, 100), - ...oldGenGC(5, 10000, 100), + ...newGenGC(4), + ...oldGenGC(5), cpuUsage(5000, 20), cpuUsage(5010, 60), memoryUsage(6000, 20, 40), memoryUsage(6100, 30, 45), platformVsync(7000), vsyncCallback(7500), @@ -581,7 +581,6 @@ void main() { '90th_percentile_picture_cache_memory': 0.0, '99th_percentile_picture_cache_memory': 0.0, 'worst_picture_cache_memory': 0.0, - 'total_ui_gc_time': 0.4, }); }); }); diff --git a/packages/flutter_goldens/lib/flutter_goldens.dart b/packages/flutter_goldens/lib/flutter_goldens.dart index 664141487514e..e2bd6603317b7 100644 --- a/packages/flutter_goldens/lib/flutter_goldens.dart +++ b/packages/flutter_goldens/lib/flutter_goldens.dart @@ -227,12 +227,12 @@ class FlutterPostSubmitFileComparator extends FlutterGoldenFileComparator { goldens ??= SkiaGoldClient(baseDirectory); await goldens.auth(); + await goldens.imgtestInit(); return FlutterPostSubmitFileComparator(baseDirectory.uri, goldens); } @override Future<bool> compare(Uint8List imageBytes, Uri golden) async { - await skiaClient.imgtestInit(); golden = _addPrefix(golden); await update(golden, imageBytes); final File goldenFile = getGoldenFile(golden); @@ -309,15 +309,16 @@ class FlutterPreSubmitFileComparator extends FlutterGoldenFileComparator { goldens ??= SkiaGoldClient(baseDirectory); await goldens.auth(); - return FlutterPreSubmitFileComparator( - baseDirectory.uri, - goldens, platform: platform, - ); - } + await goldens.tryjobInit(); + return FlutterPreSubmitFileComparator( + baseDirectory.uri, + goldens, + platform: platform, + ); + } @override Future<bool> compare(Uint8List imageBytes, Uri golden) async { - await skiaClient.tryjobInit(); golden = _addPrefix(golden); await update(golden, imageBytes); final File goldenFile = getGoldenFile(golden); diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index e989b665c4278..66c59e8b59a59 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: path: ../flutter_goldens_client file: 6.1.2 meta: 1.7.0 - platform: 3.1.0 + platform: 3.0.2 process: 4.2.4 async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -25,15 +25,14 @@ dependencies: crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c666 +# PUBSPEC CHECKSUM: db03 diff --git a/packages/flutter_goldens/test/flutter_goldens_test.dart b/packages/flutter_goldens/test/flutter_goldens_test.dart index c5d22cc5f72d3..551e72c740938 100644 --- a/packages/flutter_goldens/test/flutter_goldens_test.dart +++ b/packages/flutter_goldens/test/flutter_goldens_test.dart @@ -2,6 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(gspencergoog): Remove this tag once this test's state leaks/test +// dependencies have been fixed. +// https://github.com/flutter/flutter/issues/85160 +// Fails with "flutter test --test-randomize-ordering-seed=123" +@Tags(<String>['no-shuffle']) + // See also dev/automated_tests/flutter_test/flutter_gold_test.dart import 'dart:async'; @@ -29,6 +35,13 @@ const List<int> _kTestPngBytes = 120, 1, 99, 97, 0, 2, 0, 0, 25, 0, 5, 144, 240, 54, 245, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]; +// 1x1 colored pixel +const List<int> _kFailPngBytes = +<int>[137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, + 1, 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, 13, 73, 68, 65, 84, + 120, 1, 99, 249, 207, 240, 255, 63, 0, 7, 18, 3, 2, 164, 147, 160, 197, 0, + 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]; + void main() { late MemoryFileSystem fs; late FakePlatform platform; @@ -100,7 +113,7 @@ void main() { httpClient: fakeHttpClient, ); - process.fallbackProcessResult = ProcessResult(123, 1, 'Fallback failure', 'Fallback failure'); + process.fallbackProcessResult = ProcessResult(123, 1, 'fail', 'fail'); expect( skiaClient.auth(), @@ -125,6 +138,8 @@ void main() { httpClient: fakeHttpClient, ); + process.fallbackProcessResult = ProcessResult(123, 1, 'fail', 'fail'); + const RunInvocation gitInvocation = RunInvocation( <String>['git', 'rev-parse', 'HEAD'], '/flutter', @@ -143,8 +158,7 @@ void main() { null, ); process.processResults[gitInvocation] = ProcessResult(12345678, 0, '12345678', ''); - process.processResults[goldctlInvocation] = ProcessResult(123, 1, 'Expected failure', 'Expected failure'); - process.fallbackProcessResult = ProcessResult(123, 1, 'Fallback failure', 'Fallback failure'); + process.processResults[goldctlInvocation] = ProcessResult(123, 1, 'fail', 'fail'); expect( skiaClient.imgtestInit(), @@ -152,151 +166,6 @@ void main() { ); }); - test('Only calls init once', () async { - platform = FakePlatform( - environment: <String, String>{ - 'FLUTTER_ROOT': _kFlutterRoot, - 'GOLDCTL' : 'goldctl', - }, - operatingSystem: 'macos' - ); - - skiaClient = SkiaGoldClient( - workDirectory, - fs: fs, - process: process, - platform: platform, - httpClient: fakeHttpClient, - ); - - const RunInvocation gitInvocation = RunInvocation( - <String>['git', 'rev-parse', 'HEAD'], - '/flutter', - ); - const RunInvocation goldctlInvocation = RunInvocation( - <String>[ - 'goldctl', - 'imgtest', 'init', - '--instance', 'flutter', - '--work-dir', '/workDirectory/temp', - '--commit', '1234', - '--keys-file', '/workDirectory/keys.json', - '--failure-file', '/workDirectory/failures.json', - '--passfail', - ], - null, - ); - process.processResults[gitInvocation] = ProcessResult(1234, 0, '1234', ''); - process.processResults[goldctlInvocation] = ProcessResult(5678, 0, '5678', ''); - process.fallbackProcessResult = ProcessResult(123, 1, 'Fallback failure', 'Fallback failure'); - - // First call - await skiaClient.imgtestInit(); - - // Remove fake process result. - // If the init call is executed again, the fallback process will throw. - process.processResults.remove(goldctlInvocation); - - // Second call - await skiaClient.imgtestInit(); - }); - - test('Only calls tryjob init once', () async { - platform = FakePlatform( - environment: <String, String>{ - 'FLUTTER_ROOT': _kFlutterRoot, - 'GOLDCTL' : 'goldctl', - 'SWARMING_TASK_ID' : '4ae997b50dfd4d11', - 'LOGDOG_STREAM_PREFIX' : 'buildbucket/cr-buildbucket.appspot.com/8885996262141582672', - 'GOLD_TRYJOB' : 'refs/pull/49815/head', - }, - operatingSystem: 'macos' - ); - - skiaClient = SkiaGoldClient( - workDirectory, - fs: fs, - process: process, - platform: platform, - httpClient: fakeHttpClient, - ); - - const RunInvocation gitInvocation = RunInvocation( - <String>['git', 'rev-parse', 'HEAD'], - '/flutter', - ); - const RunInvocation goldctlInvocation = RunInvocation( - <String>[ - 'goldctl', - 'imgtest', 'init', - '--instance', 'flutter', - '--work-dir', '/workDirectory/temp', - '--commit', '1234', - '--keys-file', '/workDirectory/keys.json', - '--failure-file', '/workDirectory/failures.json', - '--passfail', - '--crs', 'github', - '--patchset_id', '1234', - '--changelist', '49815', - '--cis', 'buildbucket', - '--jobid', '8885996262141582672', - ], - null, - ); - process.processResults[gitInvocation] = ProcessResult(1234, 0, '1234', ''); - process.processResults[goldctlInvocation] = ProcessResult(5678, 0, '5678', ''); - process.fallbackProcessResult = ProcessResult(123, 1, 'Fallback failure', 'Fallback failure'); - - // First call - await skiaClient.tryjobInit(); - - // Remove fake process result. - // If the init call is executed again, the fallback process will throw. - process.processResults.remove(goldctlInvocation); - - // Second call - await skiaClient.tryjobInit(); - }); - - test('throws for error state from imgtestAdd', () { - final File goldenFile = fs.file('/workDirectory/temp/golden_file_test.png') - ..createSync(recursive: true); - platform = FakePlatform( - environment: <String, String>{ - 'FLUTTER_ROOT': _kFlutterRoot, - 'GOLDCTL' : 'goldctl', - }, - operatingSystem: 'macos' - ); - - skiaClient = SkiaGoldClient( - workDirectory, - fs: fs, - process: process, - platform: platform, - httpClient: fakeHttpClient, - ); - - const RunInvocation goldctlInvocation = RunInvocation( - <String>[ - 'goldctl', - 'imgtest', 'add', - '--work-dir', '/workDirectory/temp', - '--test-name', 'golden_file_test', - '--png-file', '/workDirectory/temp/golden_file_test.png', - '--passfail', - ], - null, - ); - process.processResults[goldctlInvocation] = ProcessResult(123, 1, 'Expected failure', 'Expected failure'); - process.fallbackProcessResult = ProcessResult(123, 1, 'Fallback failure', 'Fallback failure'); - - expect( - skiaClient.imgtestAdd('golden_file_test', goldenFile), - throwsException, - ); - }); - test('correctly inits tryjob for luci', () async { platform = FakePlatform( environment: <String, String>{ @@ -432,7 +301,7 @@ void main() { }); group('FlutterGoldenFileComparator', () { - late FlutterGoldenFileComparator comparator; + late FlutterPostSubmitFileComparator comparator; setUp(() { final Directory basedir = fs.directory('flutter/test/library/') @@ -467,10 +336,9 @@ void main() { }); group('Post-Submit', () { - late FakeSkiaGoldClient fakeSkiaClient; + final FakeSkiaGoldClient fakeSkiaClient = FakeSkiaGoldClient(); setUp(() { - fakeSkiaClient = FakeSkiaGoldClient(); final Directory basedir = fs.directory('flutter/test/library/') ..createSync(recursive: true); comparator = FlutterPostSubmitFileComparator( @@ -481,24 +349,6 @@ void main() { ); }); - test('calls init during compare', () { - expect(fakeSkiaClient.initCalls, 0); - comparator.compare( - Uint8List.fromList(_kTestPngBytes), - Uri.parse('flutter.golden_test.1.png'), - ); - expect(fakeSkiaClient.initCalls, 1); - }); - - test('does not call init in during construction', () { - expect(fakeSkiaClient.initCalls, 0); - FlutterPostSubmitFileComparator.fromDefaultComparator( - platform, - goldens: fakeSkiaClient, - ); - expect(fakeSkiaClient.initCalls, 0); - }); - group('correctly determines testing environment', () { test('returns true for configured Luci', () { platform = FakePlatform( @@ -565,38 +415,6 @@ void main() { }); group('Pre-Submit', () { - late FakeSkiaGoldClient fakeSkiaClient; - - setUp(() { - fakeSkiaClient = FakeSkiaGoldClient(); - final Directory basedir = fs.directory('flutter/test/library/') - ..createSync(recursive: true); - comparator = FlutterPreSubmitFileComparator( - basedir.uri, - fakeSkiaClient, - fs: fs, - platform: platform, - ); - }); - - test('calls init during compare', () { - expect(fakeSkiaClient.tryInitCalls, 0); - comparator.compare( - Uint8List.fromList(_kTestPngBytes), - Uri.parse('flutter.golden_test.1.png'), - ); - expect(fakeSkiaClient.tryInitCalls, 1); - }); - - test('does not call init in during construction', () { - expect(fakeSkiaClient.tryInitCalls, 0); - FlutterPostSubmitFileComparator.fromDefaultComparator( - platform, - goldens: fakeSkiaClient, - ); - expect(fakeSkiaClient.tryInitCalls, 0); - }); - group('correctly determines testing environment', () { test('returns true for Luci', () { platform = FakePlatform( @@ -755,6 +573,22 @@ void main() { ); }); + test('compare properly awaits validation & output before failing.', () async { + final Completer<bool> completer = Completer<bool>(); + final Future<bool> result = comparator.compare( + Uint8List.fromList(_kFailPngBytes), + Uri.parse('flutter.golden_test.1.png'), + ); + bool shouldThrow = true; + result.then((_) { + if (shouldThrow) + fail('Compare completed before validation completed!'); + }); + await Future<void>.value(); + shouldThrow = false; + completer.complete(Future<bool>.value(false)); + }); + test('returns FlutterSkippingGoldenFileComparator when network connection is unavailable', () async { final FakeDirectory fakeDirectory = FakeDirectory(); fakeDirectory.existsSyncValue = true; @@ -777,8 +611,6 @@ void main() { baseDirectory: fakeDirectory, ); expect(comparator.runtimeType, FlutterSkippingFileComparator); - // reset property or it will carry on to other tests - fakeSkiaClient.getExpectationForTestThrowable = null; }); }); }); @@ -838,8 +670,8 @@ class FakeProcessManager extends Fake implements ProcessManager { Map<String, String>? environment, bool includeParentEnvironment = true, bool runInShell = false, - Encoding? stdoutEncoding = systemEncoding, - Encoding? stderrEncoding = systemEncoding, + Encoding stdoutEncoding = systemEncoding, + Encoding stderrEncoding = systemEncoding, }) async { workingDirectories.add(workingDirectory); final ProcessResult? result = processResults[RunInvocation(command.cast<String>(), workingDirectory)]; @@ -863,21 +695,6 @@ class FakeSkiaGoldClient extends Fake implements SkiaGoldClient { return expectationForTestValues[testName] ?? ''; } - @override - Future<void> auth() async {} - - int initCalls = 0; - @override - Future<void> imgtestInit() async => initCalls += 1; - @override - Future<bool> imgtestAdd(String testName, File goldenFile) async => true; - - int tryInitCalls = 0; - @override - Future<void> tryjobInit() async => tryInitCalls += 1; - @override - Future<bool> tryjobAdd(String testName, File goldenFile) async => true; - Map<String, List<int>> imageBytesValues = <String, List<int>>{}; @override Future<List<int>> getImageBytes(String imageHash) async => imageBytesValues[imageHash]!; diff --git a/packages/flutter_goldens_client/lib/skia_client.dart b/packages/flutter_goldens_client/lib/skia_client.dart index d79f220a15f56..396d2e2f4af59 100644 --- a/packages/flutter_goldens_client/lib/skia_client.dart +++ b/packages/flutter_goldens_client/lib/skia_client.dart @@ -109,24 +109,12 @@ class SkiaGoldClient { } } - /// Signals if this client is initialized for uploading images to the Gold - /// service. - /// - /// Since Flutter framework tests are executed in parallel, and in random - /// order, this will signal is this instance of the Gold client has been - /// initialized. - bool _initialized = false; - /// Executes the `imgtest init` command in the goldctl tool. /// /// The `imgtest` command collects and uploads test results to the Skia Gold /// backend, the `init` argument initializes the current test. Used by the /// [FlutterPostSubmitFileComparator]. Future<void> imgtestInit() async { - // This client has already been intialized - if (_initialized) - return; - final File keys = workDirectory.childFile('keys.json'); final File failures = workDirectory.childFile('failures.json'); @@ -159,7 +147,6 @@ class SkiaGoldClient { final io.ProcessResult result = await process.run(imgtestInitCommand); if (result.exitCode != 0) { - _initialized = false; final StringBuffer buf = StringBuffer() ..writeln('Skia Gold imgtest init failed.') ..writeln('An error occurred when initializing golden file test with ') @@ -170,7 +157,6 @@ class SkiaGoldClient { ..writeln('stderr: ${result.stderr}'); throw Exception(buf.toString()); } - _initialized = true; } /// Executes the `imgtest add` command in the goldctl tool. @@ -191,51 +177,28 @@ class SkiaGoldClient { .path, '--test-name', cleanTestName(testName), '--png-file', goldenFile.path, - '--passfail', ]; final io.ProcessResult result = await process.run(imgtestCommand); if (result.exitCode != 0) { - // If an unapproved image has made it to post-submit, throw to close the - // tree. - final StringBuffer buf = StringBuffer() - ..writeln('Skia Gold received an unapproved image in post-submit ') - ..writeln('testing. Golden file images in flutter/flutter are triaged ') - ..writeln('in pre-submit during code review for the given PR.') - ..writeln() - ..writeln('Visit https://flutter-gold.skia.org/ to view and approve ') - ..writeln('the image(s), or revert the associated change. For more ') - ..writeln('information, visit the wiki: ') - ..writeln('https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter') - ..writeln() - ..writeln('Debug information for Gold:') - ..writeln('stdout: ${result.stdout}') - ..writeln('stderr: ${result.stderr}'); - throw Exception(buf.toString()); + // We do not want to throw for non-zero exit codes here, as an intentional + // change or new golden file test expect non-zero exit codes. Logging here + // is meant to help debugging in CI when an unexpected result occurs. + // See also: https://github.com/flutter/flutter/issues/91285 + print('goldctl imgtest add stdout: ${result.stdout}'); // ignore: avoid_print + print('goldctl imgtest add stderr: ${result.stderr}'); // ignore: avoid_print } return true; } - /// Signals if this client is initialized for uploading tryjobs to the Gold - /// service. - /// - /// Since Flutter framework tests are executed in parallel, and in random - /// order, this will signal is this instance of the Gold client has been - /// initialized for tryjobs. - bool _tryjobInitialized = false; - /// Executes the `imgtest init` command in the goldctl tool for tryjobs. /// /// The `imgtest` command collects and uploads test results to the Skia Gold /// backend, the `init` argument initializes the current tryjob. Used by the /// [FlutterPreSubmitFileComparator]. Future<void> tryjobInit() async { - // This client has already been initialized - if (_tryjobInitialized) - return; - final File keys = workDirectory.childFile('keys.json'); final File failures = workDirectory.childFile('failures.json'); @@ -271,7 +234,6 @@ class SkiaGoldClient { final io.ProcessResult result = await process.run(imgtestInitCommand); if (result.exitCode != 0) { - _tryjobInitialized = false; final StringBuffer buf = StringBuffer() ..writeln('Skia Gold tryjobInit failure.') ..writeln('An error occurred when initializing golden file tryjob with ') @@ -282,7 +244,6 @@ class SkiaGoldClient { ..writeln('stderr: ${result.stderr}'); throw Exception(buf.toString()); } - _tryjobInitialized = true; } /// Executes the `imgtest add` command in the goldctl tool for tryjobs. diff --git a/packages/flutter_goldens_client/pubspec.yaml b/packages/flutter_goldens_client/pubspec.yaml index e383ad08ae16b..0edccc28fa9d3 100644 --- a/packages/flutter_goldens_client/pubspec.yaml +++ b/packages/flutter_goldens_client/pubspec.yaml @@ -7,16 +7,16 @@ dependencies: # To update these, use "flutter update-packages --force-upgrade". crypto: 3.0.1 file: 6.1.2 - platform: 3.1.0 + platform: 3.0.2 process: 4.2.4 collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 67fc +# PUBSPEC CHECKSUM: 45fc diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb index 759c6a00f027e..927982870fd51 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb @@ -31,5 +31,5 @@ "selectAllButtonLabel": "Вибрати все", "tabSemanticsLabel": "Вкладка $tabIndex з $tabCount", "modalBarrierDismissLabel": "Закрити", - "searchTextFieldPlaceholderLabel": "Шукайте" + "searchTextFieldPlaceholderLabel": "Пошук" } diff --git a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart index 23a232b0fe263..b2edf17832713 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart @@ -12656,7 +12656,7 @@ class CupertinoLocalizationUk extends GlobalCupertinoLocalizations { String get postMeridiemAbbreviation => 'пп'; @override - String get searchTextFieldPlaceholderLabel => 'Шукайте'; + String get searchTextFieldPlaceholderLabel => 'Пошук'; @override String get selectAllButtonLabel => 'Вибрати все'; diff --git a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart index 4bae28a1a9a80..4868677cbbb0c 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart @@ -14348,7 +14348,7 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations { String get firstPageTooltip => 'Бірінші бет'; @override - String get hideAccountsLabel => 'Аккаунттарды жасыру'; + String get hideAccountsLabel => 'Есептік жазбаларды жасыру'; @override String get inputDateModeButtonLabel => 'Мәтін енгізуге ауысу'; @@ -14504,13 +14504,13 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations { String? get selectedRowCountTitleZero => 'Тармақ таңдалмаған'; @override - String get showAccountsLabel => 'Аккаунттарды көрсету'; + String get showAccountsLabel => 'Есептік жазбаларды көрсету'; @override String get showMenuTooltip => 'Мәзірді көрсету'; @override - String get signedInLabel => 'Аккаунтқа кірген'; + String get signedInLabel => 'Есептік жазбаға кірген'; @override String get tabLabelRaw => r'$tabCount/$tabIndex қойынды'; @@ -19496,10 +19496,10 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations { String? get selectedRowCountTitleZero => null; @override - String get showAccountsLabel => 'Accounts tonen'; + String get showAccountsLabel => 'Accounts weergeven'; @override - String get showMenuTooltip => 'Menu tonen'; + String get showMenuTooltip => 'Menu weergeven'; @override String get signedInLabel => 'Ingelogd'; @@ -21152,7 +21152,7 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Fechar'; @override - String get collapsedIconTapHint => 'Abrir'; + String get collapsedIconTapHint => 'Expandir'; @override String get continueButtonLabel => 'CONTINUAR'; @@ -21529,9 +21529,6 @@ class MaterialLocalizationPtPt extends MaterialLocalizationPt { @override String get expandedIconTapHint => 'Reduzir'; - @override - String get collapsedIconTapHint => 'Expandir'; - @override String? get remainingTextFieldCharacterCountOne => 'Resta 1 caráter'; diff --git a/packages/flutter_localizations/lib/src/l10n/material_kk.arb b/packages/flutter_localizations/lib/src/l10n/material_kk.arb index 892737b084aa7..957054b6de2ba 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kk.arb @@ -36,9 +36,9 @@ "timePickerHourModeAnnouncement": "Сағаттарды таңдаңыз", "timePickerMinuteModeAnnouncement": "Минуттарды таңдаңыз", "modalBarrierDismissLabel": "Жабу", - "signedInLabel": "Аккаунтқа кірген", - "hideAccountsLabel": "Аккаунттарды жасыру", - "showAccountsLabel": "Аккаунттарды көрсету", + "signedInLabel": "Есептік жазбаға кірген", + "hideAccountsLabel": "Есептік жазбаларды жасыру", + "showAccountsLabel": "Есептік жазбаларды көрсету", "drawerLabel": "Навигация мәзірі", "popupMenuLabel": "Қалқымалы терезе мәзірі", "dialogLabel": "Диалогтық терезе", diff --git a/packages/flutter_localizations/lib/src/l10n/material_nl.arb b/packages/flutter_localizations/lib/src/l10n/material_nl.arb index 6f9b420b27cc1..5309bf1e86c46 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nl.arb @@ -11,7 +11,7 @@ "previousPageTooltip": "Vorige pagina", "firstPageTooltip": "Eerste pagina", "lastPageTooltip": "Laatste pagina", - "showMenuTooltip": "Menu tonen", + "showMenuTooltip": "Menu weergeven", "aboutListTileTitle": "Over $applicationName", "licensesPageTitle": "Licenties", "pageRowsInfoTitle": "$firstRow-$lastRow van $rowCount", @@ -35,7 +35,7 @@ "timePickerMinuteModeAnnouncement": "Minuten selecteren", "signedInLabel": "Ingelogd", "hideAccountsLabel": "Accounts verbergen", - "showAccountsLabel": "Accounts tonen", + "showAccountsLabel": "Accounts weergeven", "modalBarrierDismissLabel": "Sluiten", "drawerLabel": "Navigatiemenu", "popupMenuLabel": "Pop-upmenu", diff --git a/packages/flutter_localizations/lib/src/l10n/material_pt.arb b/packages/flutter_localizations/lib/src/l10n/material_pt.arb index b45eb99bf3b81..c0de0eb5f994d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pt.arb @@ -51,7 +51,7 @@ "reorderItemLeft": "Mover para a esquerda", "reorderItemRight": "Mover para a direita", "expandedIconTapHint": "Recolher", - "collapsedIconTapHint": "Abrir", + "collapsedIconTapHint": "Expandir", "remainingTextFieldCharacterCountZero": "TBD", "remainingTextFieldCharacterCountOne": "1 caractere restante", "remainingTextFieldCharacterCountOther": "$remainingCount caracteres restantes", diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index 84522a5cd39c4..ffe86fdbfe83a 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -13,9 +13,8 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -33,6 +32,6 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: efb6 +# PUBSPEC CHECKSUM: 0152 diff --git a/packages/flutter_localizations/test/basics_test.dart b/packages/flutter_localizations/test/basics_test.dart index 58376a6c1eea5..69914700bde83 100644 --- a/packages/flutter_localizations/test/basics_test.dart +++ b/packages/flutter_localizations/test/basics_test.dart @@ -37,7 +37,7 @@ void main() { ], localizationsDelegates: <LocalizationsDelegate<dynamic>>[ _DummyLocalizationsDelegate(), - ...GlobalMaterialLocalizations.delegates, + GlobalMaterialLocalizations.delegate, ], home: PageView(), ) @@ -52,7 +52,9 @@ void main() { // Regression test for https://github.com/flutter/flutter/pull/16782 await tester.pumpWidget( MaterialApp( - localizationsDelegates: GlobalMaterialLocalizations.delegates, + localizationsDelegates: const <LocalizationsDelegate<dynamic>>[ + GlobalMaterialLocalizations.delegate, + ], supportedLocales: const <Locale>[ Locale('es', 'ES'), Locale('zh'), diff --git a/packages/flutter_localizations/test/material/date_picker_test.dart b/packages/flutter_localizations/test/material/date_picker_test.dart index bcbe59deb0a91..5872eba389559 100644 --- a/packages/flutter_localizations/test/material/date_picker_test.dart +++ b/packages/flutter_localizations/test/material/date_picker_test.dart @@ -13,7 +13,7 @@ void main() { late DateTime initialDate; setUp(() { - firstDate = DateTime(2001); + firstDate = DateTime(2001, DateTime.january); lastDate = DateTime(2031, DateTime.december, 31); initialDate = DateTime(2016, DateTime.january, 15); }); diff --git a/packages/flutter_localizations/test/material/date_time_test.dart b/packages/flutter_localizations/test/material/date_time_test.dart index 9db3e8c1838b4..0c5c9dc2e8f8d 100644 --- a/packages/flutter_localizations/test/material/date_time_test.dart +++ b/packages/flutter_localizations/test/material/date_time_test.dart @@ -35,7 +35,9 @@ void main() { await tester.pumpWidget(MaterialApp( supportedLocales: <Locale>[locale], locale: locale, - localizationsDelegates: GlobalMaterialLocalizations.delegates, + localizationsDelegates: const <LocalizationsDelegate<dynamic>>[ + GlobalMaterialLocalizations.delegate, + ], home: Builder(builder: (BuildContext context) { completer.complete(MaterialLocalizations.of(context).formatHour(timeOfDay)); return Container(); @@ -80,7 +82,9 @@ void main() { await tester.pumpWidget(MaterialApp( supportedLocales: <Locale>[locale], locale: locale, - localizationsDelegates: GlobalMaterialLocalizations.delegates, + localizationsDelegates: const <LocalizationsDelegate<dynamic>>[ + GlobalMaterialLocalizations.delegate, + ], home: Builder(builder: (BuildContext context) { completer.complete(MaterialLocalizations.of(context).formatTimeOfDay(timeOfDay)); return Container(); @@ -122,7 +126,9 @@ void main() { await tester.pumpWidget(MaterialApp( supportedLocales: <Locale>[locale], locale: locale, - localizationsDelegates: GlobalMaterialLocalizations.delegates, + localizationsDelegates: const <LocalizationsDelegate<dynamic>>[ + GlobalMaterialLocalizations.delegate, + ], home: Builder(builder: (BuildContext context) { final MaterialLocalizations localizations = MaterialLocalizations.of(context); completer.complete(<DateType, String>{ @@ -178,9 +184,12 @@ void main() { await tester.pumpWidget(MaterialApp( locale: const Locale('en', 'US'), - localizationsDelegates: GlobalMaterialLocalizations.delegates, + localizationsDelegates: const <LocalizationsDelegate<dynamic>>[ + GlobalMaterialLocalizations.delegate, + ], home: Builder(builder: (BuildContext context) { dateFormat = DateFormat('EEE, d MMM yyyy HH:mm:ss', 'en_US'); + return Container(); }), )); diff --git a/packages/flutter_localizations/test/override_test.dart b/packages/flutter_localizations/test/override_test.dart index 511b6a15b3089..f977bb111bab0 100644 --- a/packages/flutter_localizations/test/override_test.dart +++ b/packages/flutter_localizations/test/override_test.dart @@ -175,10 +175,9 @@ void main() { await tester.pumpWidget( buildFrame( - delegates: <LocalizationsDelegate<dynamic>>[ + delegates: <FooMaterialLocalizationsDelegate>[ const FooMaterialLocalizationsDelegate(supportedLanguage: 'fr', backButtonTooltip: 'FR'), const FooMaterialLocalizationsDelegate(supportedLanguage: 'de', backButtonTooltip: 'DE'), - GlobalCupertinoLocalizations.delegate, ], supportedLocales: const <Locale>[ Locale('en'), @@ -212,9 +211,8 @@ void main() { buildFrame( // Accept whatever locale we're given localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale, - delegates: <LocalizationsDelegate<dynamic>>[ + delegates: <FooMaterialLocalizationsDelegate>[ const FooMaterialLocalizationsDelegate(supportedLanguage: 'allLanguages'), - GlobalCupertinoLocalizations.delegate, ], buildContent: (BuildContext context) { // Should always be 'foo', no matter what the locale is @@ -242,9 +240,8 @@ void main() { await tester.pumpWidget( buildFrame( - delegates: <LocalizationsDelegate<dynamic>>[ + delegates: <FooMaterialLocalizationsDelegate>[ const FooMaterialLocalizationsDelegate(), - GlobalCupertinoLocalizations.delegate, ], // supportedLocales not specified, so all locales resolve to 'en' buildContent: (BuildContext context) { @@ -300,7 +297,6 @@ void main() { // Yiddish was ji (ISO-639) is yi (ISO-639-1) await tester.binding.setLocale('ji', 'IL'); await tester.pump(); - expect(tester.takeException(), "Warning: This application's locale, yi_IL, is not supported by all of its localization delegates."); expect(tester.widget<Text>(find.byKey(textKey)).data, 'yi_IL'); // Indonesian was in (ISO-639) is id (ISO-639-1) diff --git a/packages/flutter_localizations/test/text_test.dart b/packages/flutter_localizations/test/text_test.dart index b0501f048bac6..4ddc9d43c2171 100644 --- a/packages/flutter_localizations/test/text_test.dart +++ b/packages/flutter_localizations/test/text_test.dart @@ -22,7 +22,9 @@ void main() { return const Text('Next'); }, }, - localizationsDelegates: GlobalMaterialLocalizations.delegates, + localizationsDelegates: const <LocalizationsDelegate<dynamic>>[ + GlobalMaterialLocalizations.delegate, + ], supportedLocales: const <Locale>[ Locale('en', 'US'), Locale('es', 'ES'), @@ -106,7 +108,9 @@ void main() { return const Text('Next'); }, }, - localizationsDelegates: GlobalMaterialLocalizations.delegates, + localizationsDelegates: const <LocalizationsDelegate<dynamic>>[ + GlobalMaterialLocalizations.delegate, + ], supportedLocales: const <Locale>[ Locale('en', 'US'), Locale('es', 'ES'), diff --git a/packages/flutter_test/lib/src/accessibility.dart b/packages/flutter_test/lib/src/accessibility.dart index 150bf454f9594..63506e2487ac6 100644 --- a/packages/flutter_test/lib/src/accessibility.dart +++ b/packages/flutter_test/lib/src/accessibility.dart @@ -95,9 +95,6 @@ class MinimumTapTargetGuideline extends AccessibilityGuideline { && !data.hasAction(ui.SemanticsAction.tap)) || data.hasFlag(ui.SemanticsFlag.isHidden)) return result; - // Skip links https://www.w3.org/WAI/WCAG21/Understanding/target-size.html - if (data.hasFlag(ui.SemanticsFlag.isLink)) - return result; Rect paintBounds = node.rect; SemanticsNode? current = node; while (current != null) { @@ -212,10 +209,7 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { Future<Evaluation> evaluateNode(SemanticsNode node) async { Evaluation result = const Evaluation.pass(); - if (node.isInvisible || - node.isMergedIntoParent || - node.hasFlag(ui.SemanticsFlag.isHidden) || - (node.hasFlag(ui.SemanticsFlag.hasEnabledState) && !node.hasFlag(ui.SemanticsFlag.isEnabled))) + if (node.isInvisible || node.isMergedIntoParent || node.hasFlag(ui.SemanticsFlag.isHidden)) return result; final SemanticsData data = node.getSemanticsData(); final List<SemanticsNode> children = <SemanticsNode>[]; diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index d3f5cac9cad30..1a8cf7927c77a 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -1391,7 +1391,6 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { Completer<void>? _pendingFrame; bool _expectingFrame = false; - bool _expectingFrameToReassemble = false; bool _viewNeedsPaint = false; bool _runningAsyncTasks = false; @@ -1427,19 +1426,12 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { super.scheduleForcedFrame(); } - @override - Future<void> reassembleApplication() { - _expectingFrameToReassemble = true; - return super.reassembleApplication(); - } - bool? _doDrawThisFrame; @override void handleBeginFrame(Duration? rawTimeStamp) { assert(_doDrawThisFrame == null); if (_expectingFrame || - _expectingFrameToReassemble || (framePolicy == LiveTestWidgetsFlutterBindingFramePolicy.fullyLive) || (framePolicy == LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive) || (framePolicy == LiveTestWidgetsFlutterBindingFramePolicy.benchmark) || @@ -1458,7 +1450,6 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { super.handleDrawFrame(); _doDrawThisFrame = null; _viewNeedsPaint = false; - _expectingFrameToReassemble = false; if (_expectingFrame) { // set during pump assert(_pendingFrame != null); _pendingFrame!.complete(); // unlocks the test API diff --git a/packages/flutter_test/lib/src/event_simulation.dart b/packages/flutter_test/lib/src/event_simulation.dart index 1761b4c98b8e8..07eac0b9a9303 100644 --- a/packages/flutter_test/lib/src/event_simulation.dart +++ b/packages/flutter_test/lib/src/event_simulation.dart @@ -688,15 +688,15 @@ class KeyEventSimulator { result.complete(false); return; } - final Map<String, Object?> decoded = SystemChannels.keyEvent.codec.decodeMessage(data)! as Map<String, dynamic>; - result.complete(decoded['handled']! as bool); + final Map<String, dynamic> decoded = SystemChannels.keyEvent.codec.decodeMessage(data) as Map<String, dynamic>; + result.complete(decoded['handled'] as bool); } ); return result.future; }); } - static final Map<String, PhysicalKeyboardKey> _debugNameToPhysicalKey = (() { + static late final Map<String, PhysicalKeyboardKey> _debugNameToPhysicalKey = (() { final Map<String, PhysicalKeyboardKey> result = <String, PhysicalKeyboardKey>{}; for (final PhysicalKeyboardKey key in PhysicalKeyboardKey.knownPhysicalKeys) { final String? debugName = key.debugName; diff --git a/packages/flutter_test/lib/src/frame_timing_summarizer.dart b/packages/flutter_test/lib/src/frame_timing_summarizer.dart index c6e3c464b8552..55bb67b97f36a 100644 --- a/packages/flutter_test/lib/src/frame_timing_summarizer.dart +++ b/packages/flutter_test/lib/src/frame_timing_summarizer.dart @@ -294,21 +294,16 @@ class FrameTimingSummarizer { }; } -/// Returns the 100*p-th percentile of [data]. -/// -/// [data] must be sorted in ascending order. +// The following helper functions require data sorted + +// return the 100*p-th percentile of the data T _findPercentile<T>(List<T> data, double p) { assert(p >= 0 && p <= 1); return data[((data.length - 1) * p).round()]; } -/// Returns the number of elements in [data] that exceed [threshold]. -/// -/// [data] must be sorted in ascending order. +// return the number of items in data that > threshold int _countExceed<T extends Comparable<T>>(List<T> data, T threshold) { - final int exceedsThresholdIndex = data.indexWhere((T datum) => datum.compareTo(threshold) > 0); - if (exceedsThresholdIndex == -1) { - return 0; - } - return data.length - exceedsThresholdIndex; + return data.length - + data.indexWhere((T datum) => datum.compareTo(threshold) > 0); } diff --git a/packages/flutter_test/lib/src/goldens.dart b/packages/flutter_test/lib/src/goldens.dart index 3ca05fa36456f..a969fd5eedea7 100644 --- a/packages/flutter_test/lib/src/goldens.dart +++ b/packages/flutter_test/lib/src/goldens.dart @@ -8,7 +8,7 @@ import 'dart:ui'; import 'package:path/path.dart' as path; import 'package:test_api/test_api.dart'; // ignore: deprecated_member_use -import '_goldens_io.dart' if (dart.library.html) '_goldens_web.dart' as goldens; +import '_goldens_io.dart' if (dart.library.html) '_goldens_web.dart' as _goldens; /// Compares image pixels against a golden image file. /// @@ -94,7 +94,7 @@ abstract class GoldenFileComparator { /// Returns a [ComparisonResult] to describe the pixel differential of the /// [test] and [master] image bytes provided. static Future<ComparisonResult> compareLists(List<int> test, List<int> master) { - return goldens.compareLists(test, master); + return _goldens.compareLists(test, master); } } diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart index 0ef04f61d9778..5ee8c49575d34 100644 --- a/packages/flutter_test/lib/src/window.dart +++ b/packages/flutter_test/lib/src/window.dart @@ -134,20 +134,6 @@ class TestWindow implements ui.SingletonFlutterWindow { onMetricsChanged?.call(); } - @override - List<ui.DisplayFeature> get displayFeatures => _displayFeaturesTestValue ?? _window.displayFeatures; - List<ui.DisplayFeature>? _displayFeaturesTestValue; - /// Hides the real displayFeatures and reports the given [displayFeaturesTestValue] instead. - set displayFeaturesTestValue(List<ui.DisplayFeature> displayFeaturesTestValue) { // ignore: avoid_setters_without_getters - _displayFeaturesTestValue = displayFeaturesTestValue; - onMetricsChanged?.call(); - } - /// Deletes any existing test padding and returns to using the real padding. - void clearDisplayFeaturesTestValue() { - _displayFeaturesTestValue = null; - onMetricsChanged?.call(); - } - @override ui.WindowPadding get systemGestureInsets => _systemGestureInsetsTestValue ?? _window.systemGestureInsets; ui.WindowPadding? _systemGestureInsetsTestValue; @@ -441,7 +427,6 @@ class TestWindow implements ui.SingletonFlutterWindow { clearLocaleTestValue(); clearLocalesTestValue(); clearPaddingTestValue(); - clearDisplayFeaturesTestValue(); clearPhysicalSizeTestValue(); clearSemanticsEnabledTestValue(); clearTextScaleFactorTestValue(); diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index 0fec8bc146ea2..945fe55a65d18 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -12,10 +12,10 @@ dependencies: # We depend on very specific internal implementation details of the # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. - test_api: 0.4.9 + test_api: 0.4.3 # Used by golden file comparator - path: 1.8.1 + path: 1.8.0 # Testing utilities for dealing with async calls and time. fake_async: 1.2.0 @@ -35,7 +35,6 @@ dependencies: charcode: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -46,4 +45,4 @@ dependencies: dev_dependencies: file: 6.1.2 -# PUBSPEC CHECKSUM: ac70 +# PUBSPEC CHECKSUM: c20c diff --git a/packages/flutter_test/test/accessibility_test.dart b/packages/flutter_test/test/accessibility_test.dart index fa12a47bcdb84..9690dab1161a3 100644 --- a/packages/flutter_test/test/accessibility_test.dart +++ b/packages/flutter_test/test/accessibility_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -177,29 +176,6 @@ void main() { expect(result.passed, true); handle.dispose(); }); - - testWidgets('Disabled button is excluded from text contrast guideline', (WidgetTester tester) async { - // Regression test https://github.com/flutter/flutter/issues/94428 - final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget( - _boilerplate( - ElevatedButton( - onPressed: null, - child: Container( - width: 200.0, - height: 200.0, - color: Colors.yellow, - child: const Text( - 'this is a test', - style: TextStyle(fontSize: 14.0, color: Colors.yellowAccent), - ), - ), - ), - ) - ); - await expectLater(tester, meetsGuideline(textContrastGuideline)); - handle.dispose(); - }); }); group('custom minimum contrast guideline', () { @@ -542,35 +518,6 @@ void main() { expect(overlappingRightResult.passed, true); handle.dispose(); }); - - testWidgets('Does not fail on links', (WidgetTester tester) async { - Widget textWithLink() { - return Builder( - builder: (BuildContext context) { - return RichText( - text: TextSpan( - children: <InlineSpan>[ - const TextSpan( - text: 'See examples at ', - ), - TextSpan( - text: 'flutter repo', - recognizer: TapGestureRecognizer() - ..onTap = () { }, - ), - ], - ), - ); - }, - ); - } - - final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(_boilerplate(textWithLink())); - - await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); - handle.dispose(); - }); }); group('Labeled tappable node guideline', () { diff --git a/packages/flutter_test/test/frame_timing_summarizer_test.dart b/packages/flutter_test/test/frame_timing_summarizer_test.dart index 0f1130093660a..d58548a37f04e 100644 --- a/packages/flutter_test/test/frame_timing_summarizer_test.dart +++ b/packages/flutter_test/test/frame_timing_summarizer_test.dart @@ -7,135 +7,51 @@ import 'dart:ui'; import 'package:flutter_test/flutter_test.dart'; void main() { - group(FrameTimingSummarizer, () { - test('calculates all fields', () { - List<int> vsyncTimes = <int>[ - for (int i = 0; i < 100; i += 1) 100 * (i + 1), - ]; - List<int> buildTimes = <int>[ - for (int i = 0; i < 100; i += 1) vsyncTimes[i] + 1000 * (i + 1), - ]; - List<int> rasterTimes = <int>[ - for (int i = 0; i < 100; i += 1) 1000 * (i + 1) + 1000, - ]; - // reversed to make sure sort is working. - buildTimes = buildTimes.reversed.toList(); - rasterTimes = rasterTimes.reversed.toList(); - vsyncTimes = vsyncTimes.reversed.toList(); - final List<FrameTiming> inputData = <FrameTiming>[ - for (int i = 0; i < 100; i += 1) - FrameTiming( - vsyncStart: 0, - buildStart: vsyncTimes[i], - buildFinish: buildTimes[i], - rasterStart: 500, - rasterFinish: rasterTimes[i], - // Wall time should not be used in any profiling metrics. - // It is primarily to correlate with external tools' measurement. - rasterFinishWallTime: 0, - ), - ]; - - final FrameTimingSummarizer summary = FrameTimingSummarizer(inputData); - expect(summary.averageFrameBuildTime.inMicroseconds, 50500); - expect(summary.p90FrameBuildTime.inMicroseconds, 90000); - expect(summary.p99FrameBuildTime.inMicroseconds, 99000); - expect(summary.worstFrameBuildTime.inMicroseconds, 100000); - expect(summary.missedFrameBuildBudget, 84); - - expect(summary.averageFrameRasterizerTime.inMicroseconds, 51000); - expect(summary.p90FrameRasterizerTime.inMicroseconds, 90500); - expect(summary.p99FrameRasterizerTime.inMicroseconds, 99500); - expect(summary.worstFrameRasterizerTime.inMicroseconds, 100500); - expect(summary.missedFrameRasterizerBudget, 85); - expect(summary.frameBuildTime.length, 100); - - expect(summary.averageVsyncOverhead.inMicroseconds, 5050); - expect(summary.p90VsyncOverhead.inMicroseconds, 9000); - expect(summary.p99VsyncOverhead.inMicroseconds, 9900); - expect(summary.worstVsyncOverhead.inMicroseconds, 10000); - }); - - group('missed budget count', () { - test('when single element missed budget', () { - final FrameTimingSummarizer summary = FrameTimingSummarizer(<FrameTiming>[ - FrameTiming( - buildStart: 0, - buildFinish: (kBuildBudget + const Duration(microseconds: 1)).inMicroseconds, - vsyncStart: 0, - rasterStart: 0, - rasterFinish: 0, - rasterFinishWallTime: 0, - ), - ]); - expect(summary.missedFrameBuildBudget, 1); - }); - - test('when single element within budget', () { - final FrameTimingSummarizer summary = FrameTimingSummarizer(<FrameTiming>[ - FrameTiming( - buildStart: 0, - buildFinish: 0, - vsyncStart: 0, - rasterStart: 0, - rasterFinish: 0, - rasterFinishWallTime: 0, - ), - ]); - expect(summary.missedFrameBuildBudget, 0); - }); - - test('when single element exactly within budget', () { - final FrameTimingSummarizer summary = FrameTimingSummarizer(<FrameTiming>[ - FrameTiming( - buildStart: 0, - buildFinish: kBuildBudget.inMicroseconds, - vsyncStart: 0, - rasterStart: 0, - rasterFinish: 0, - rasterFinishWallTime: 0, - ), - ]); - expect(summary.missedFrameBuildBudget, 0); - }); - - test('when many missed budget', () { - final FrameTimingSummarizer summary = FrameTimingSummarizer(<FrameTiming>[ - FrameTiming( - buildStart: 0, - buildFinish: 0, - vsyncStart: 0, - rasterStart: 0, - rasterFinish: 0, - rasterFinishWallTime: 0, - ), - FrameTiming( - buildStart: 0, - buildFinish: kBuildBudget.inMicroseconds, - vsyncStart: 0, - rasterStart: 0, - rasterFinish: 0, - rasterFinishWallTime: 0, - ), - FrameTiming( - buildStart: 0, - buildFinish: (kBuildBudget + const Duration(microseconds: 1)).inMicroseconds, - vsyncStart: 0, - rasterStart: 0, - rasterFinish: 0, - rasterFinishWallTime: 0, - ), - FrameTiming( - buildStart: 0, - buildFinish: (kBuildBudget + const Duration(microseconds: 2)).inMicroseconds, - vsyncStart: 0, - rasterStart: 0, - rasterFinish: 0, - rasterFinishWallTime: 0, - ), - ]); - expect(summary.missedFrameBuildBudget, 2); - }); - }); + test('Test FrameTimingSummarizer', () { + List<int> vsyncTimes = <int>[ + for (int i = 0; i < 100; i += 1) 100 * (i + 1), + ]; + List<int> buildTimes = <int>[ + for (int i = 0; i < 100; i += 1) vsyncTimes[i] + 1000 * (i + 1), + ]; + List<int> rasterTimes = <int>[ + for (int i = 0; i < 100; i += 1) 1000 * (i + 1) + 1000, + ]; + // reversed to make sure sort is working. + buildTimes = buildTimes.reversed.toList(); + rasterTimes = rasterTimes.reversed.toList(); + vsyncTimes = vsyncTimes.reversed.toList(); + final List<FrameTiming> inputData = <FrameTiming>[ + for (int i = 0; i < 100; i += 1) + FrameTiming( + vsyncStart: 0, + buildStart: vsyncTimes[i], + buildFinish: buildTimes[i], + rasterStart: 500, + rasterFinish: rasterTimes[i], + // Wall time should not be used in any profiling metrics. + // It is primarily to correlate with external tools' measurement. + rasterFinishWallTime: 0, + ), + ]; + + final FrameTimingSummarizer summary = FrameTimingSummarizer(inputData); + expect(summary.averageFrameBuildTime.inMicroseconds, 50500); + expect(summary.p90FrameBuildTime.inMicroseconds, 90000); + expect(summary.p99FrameBuildTime.inMicroseconds, 99000); + expect(summary.worstFrameBuildTime.inMicroseconds, 100000); + expect(summary.missedFrameBuildBudget, 84); + + expect(summary.averageFrameRasterizerTime.inMicroseconds, 51000); + expect(summary.p90FrameRasterizerTime.inMicroseconds, 90500); + expect(summary.p99FrameRasterizerTime.inMicroseconds, 99500); + expect(summary.worstFrameRasterizerTime.inMicroseconds, 100500); + expect(summary.missedFrameRasterizerBudget, 85); + expect(summary.frameBuildTime.length, 100); + + expect(summary.averageVsyncOverhead.inMicroseconds, 5050); + expect(summary.p90VsyncOverhead.inMicroseconds, 9000); + expect(summary.p99VsyncOverhead.inMicroseconds, 9900); + expect(summary.worstVsyncOverhead.inMicroseconds, 10000); }); } diff --git a/packages/flutter_test/test/live_binding_test.dart b/packages/flutter_test/test/live_binding_test.dart index e56f19aaf3563..7af380bb41dc6 100644 --- a/packages/flutter_test/test/live_binding_test.dart +++ b/packages/flutter_test/test/live_binding_test.dart @@ -94,10 +94,4 @@ void main() { expect(widgetCenter.dx, windowCenterX); expect(widgetCenter.dy, windowCenterY); }); - - testWidgets("reassembleApplication doesn't get stuck", (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/79150 - - await expectLater(tester.binding.reassembleApplication(), completes); - }, timeout: const Timeout(Duration(seconds: 30))); } diff --git a/packages/flutter_test/test/widget_tester_test.dart b/packages/flutter_test/test/widget_tester_test.dart index afd0445b0245a..ae3b2820d5af5 100644 --- a/packages/flutter_test/test/widget_tester_test.dart +++ b/packages/flutter_test/test/widget_tester_test.dart @@ -809,9 +809,11 @@ class _SingleTickerTestState extends State<_SingleTickerTest> with SingleTickerP class _AlwaysAnimating extends StatefulWidget { const _AlwaysAnimating({ + this.child, required this.onPaint, }); + final Widget? child; final VoidCallback onPaint; @override @@ -844,6 +846,7 @@ class _AlwaysAnimatingState extends State<_AlwaysAnimating> with SingleTickerPro builder: (BuildContext context, Widget? child) { return CustomPaint( painter: _AlwaysRepaint(widget.onPaint), + child: widget.child, ); }, ); diff --git a/packages/flutter_test/test/window_test.dart b/packages/flutter_test/test/window_test.dart index efb02ca1fa8c9..553fb8f0bed8a 100644 --- a/packages/flutter_test/test/window_test.dart +++ b/packages/flutter_test/test/window_test.dart @@ -2,6 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(gspencergoog): Remove this tag once this test's state leaks/test +// dependencies have been fixed. +// https://github.com/flutter/flutter/issues/85160 +// Fails with "flutter test --test-randomize-ordering-seed=123" +@Tags(<String>['no-shuffle']) + import 'dart:ui' as ui show window; import 'dart:ui' show Size, Locale, WindowPadding, AccessibilityFeatures, Brightness; @@ -187,13 +193,11 @@ void main() { }); testWidgets('TestWindow sends fake locales when WidgetsBindingObserver notifiers are called', (WidgetTester tester) async { - final List<Locale> defaultLocales = WidgetsBinding.instance!.window.locales; final TestObserver observer = TestObserver(); retrieveTestBinding(tester).addObserver(observer); final List<Locale> expectedValue = <Locale>[const Locale('fake_language_code')]; retrieveTestBinding(tester).window.localesTestValue = expectedValue; expect(observer.locales, equals(expectedValue)); - retrieveTestBinding(tester).window.localesTestValue = defaultLocales; }); } diff --git a/packages/flutter_tools/bin/fuchsia_asset_builder.dart b/packages/flutter_tools/bin/fuchsia_asset_builder.dart index d787a42850961..1884823bf25df 100644 --- a/packages/flutter_tools/bin/fuchsia_asset_builder.dart +++ b/packages/flutter_tools/bin/fuchsia_asset_builder.dart @@ -6,7 +6,6 @@ import 'package:args/args.dart'; import 'package:flutter_tools/src/asset.dart' hide defaultManifestPath; -import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/file_system.dart' as libfs; import 'package:flutter_tools/src/base/io.dart'; @@ -17,7 +16,7 @@ import 'package:flutter_tools/src/bundle_builder.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/context_runner.dart'; import 'package:flutter_tools/src/devfs.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/reporting/reporting.dart'; const String _kOptionPackages = 'packages'; @@ -71,7 +70,8 @@ Future<void> run(List<String> args) async { ); if (assets == null) { - throwToolExit('Unable to find assets.', exitCode: 1); + print('Unable to find assets.'); + exit(1); } final List<Future<void>> calls = <Future<void>>[]; diff --git a/packages/flutter_tools/bin/fuchsia_tester.dart b/packages/flutter_tools/bin/fuchsia_tester.dart index 5b2c30940e063..072f93054562c 100644 --- a/packages/flutter_tools/bin/fuchsia_tester.dart +++ b/packages/flutter_tools/bin/fuchsia_tester.dart @@ -17,7 +17,7 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/context_runner.dart'; import 'package:flutter_tools/src/device.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/test/coverage_collector.dart'; diff --git a/packages/flutter_tools/bin/podhelper.rb b/packages/flutter_tools/bin/podhelper.rb index 7f11888644936..97e073dd84a63 100644 --- a/packages/flutter_tools/bin/podhelper.rb +++ b/packages/flutter_tools/bin/podhelper.rb @@ -255,8 +255,7 @@ def flutter_install_plugin_pods(application_path = nil, relative_symlink_dir, pl plugin_pods.each do |plugin_hash| plugin_name = plugin_hash['name'] plugin_path = plugin_hash['path'] - has_native_build = plugin_hash.fetch('native_build', true) - if (plugin_name && plugin_path && has_native_build) + if (plugin_name && plugin_path) symlink = File.join(symlink_plugins_dir, plugin_name) File.symlink(plugin_path, symlink) diff --git a/packages/flutter_tools/bin/xcode_backend.dart b/packages/flutter_tools/bin/xcode_backend.dart index 37ad2a4fd022f..04f86e5d2000f 100644 --- a/packages/flutter_tools/bin/xcode_backend.dart +++ b/packages/flutter_tools/bin/xcode_backend.dart @@ -190,7 +190,6 @@ class Context { runSync( 'rsync', <String>[ - '-8', // Avoid mangling filenames with encodings that do not match the current locale. '-av', '--delete', '--filter', diff --git a/packages/flutter_tools/gradle/app_plugin_loader.gradle b/packages/flutter_tools/gradle/app_plugin_loader.gradle index ed92e8ef7c1d1..f722ea8b5cacf 100644 --- a/packages/flutter_tools/gradle/app_plugin_loader.gradle +++ b/packages/flutter_tools/gradle/app_plugin_loader.gradle @@ -23,12 +23,6 @@ assert object.plugins.android instanceof List object.plugins.android.each { androidPlugin -> assert androidPlugin.name instanceof String assert androidPlugin.path instanceof String - // Skip plugins that have no native build (such as a Dart-only implementation - // of a federated plugin). - def needsBuild = androidPlugin.containsKey('native_build') ? androidPlugin['native_build'] : true - if (!needsBuild) { - return - } def pluginDirectory = new File(androidPlugin.path, 'android') assert pluginDirectory.exists() include ":${androidPlugin.name}" diff --git a/packages/flutter_tools/gradle/flutter.gradle b/packages/flutter_tools/gradle/flutter.gradle index aaaa8e6bed4a0..68113a94c9da1 100644 --- a/packages/flutter_tools/gradle/flutter.gradle +++ b/packages/flutter_tools/gradle/flutter.gradle @@ -137,16 +137,14 @@ class FlutterPlugin implements Plugin<Project> { this.project = project def rootProject = project.rootProject - if (isFlutterAppProject()) { - rootProject.tasks.register('generateLockfiles') { - rootProject.subprojects.each { subproject -> - def gradlew = (OperatingSystem.current().isWindows()) ? - "${rootProject.projectDir}/gradlew.bat" : "${rootProject.projectDir}/gradlew" - rootProject.exec { - workingDir rootProject.projectDir - executable gradlew - args ":${subproject.name}:dependencies", "--write-locks" - } + rootProject.tasks.register('generateLockfiles') { + rootProject.subprojects.each { subproject -> + def gradlew = (OperatingSystem.current().isWindows()) ? + "${rootProject.projectDir}/gradlew.bat" : "${rootProject.projectDir}/gradlew" + rootProject.exec { + workingDir rootProject.projectDir + executable gradlew + args ":${subproject.name}:dependencies", "--write-locks" } } } @@ -399,40 +397,12 @@ class FlutterPlugin implements Plugin<Project> { "io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion" ) } - // Wait until the Android plugin loaded. pluginProject.afterEvaluate { - if (pluginProject.android.compileSdkVersion > project.android.compileSdkVersion) { - project.logger.quiet("Warning: The plugin ${pluginName} requires Android SDK version ${pluginProject.android.compileSdkVersion.substring(8)}.") - } project.android.buildTypes.all addEmbeddingDependencyToPlugin } } - /** Prints error message and fix for any plugin compileSdkVersion that are higher than the project. */ - private void detectLowCompileSdkVersion() { - project.afterEvaluate { - int projectCompileSdkVersion = project.android.compileSdkVersion.substring(8) as int - int maxPluginCompileSdkVersion = projectCompileSdkVersion - int numProcessedPlugins = getPluginList().size() - - getPluginList().each { plugin -> - Project pluginProject = project.rootProject.findProject(plugin.key) - pluginProject.afterEvaluate { - int pluginCompileSdkVersion = pluginProject.android.compileSdkVersion.substring(8) as int - maxPluginCompileSdkVersion = Math.max(pluginCompileSdkVersion, maxPluginCompileSdkVersion) - - numProcessedPlugins-- - if (numProcessedPlugins == 0) { - if (maxPluginCompileSdkVersion > projectCompileSdkVersion) { - project.logger.error("One or more plugins require a higher Android SDK version.\nFix this issue by adding the following to ${project.projectDir}${File.separator}build.gradle:\nandroid {\n compileSdkVersion ${maxPluginCompileSdkVersion}\n ...\n}\n") - } - } - } - } - } - } - /** * Returns `true` if the given path contains an `android/build.gradle` file. */ @@ -963,7 +933,6 @@ class FlutterPlugin implements Plugin<Project> { } } configurePlugins() - detectLowCompileSdkVersion() return } // Flutter host module project (Add-to-app). @@ -1015,7 +984,6 @@ class FlutterPlugin implements Plugin<Project> { } } configurePlugins() - detectLowCompileSdkVersion() } } diff --git a/packages/flutter_tools/gradle/module_plugin_loader.gradle b/packages/flutter_tools/gradle/module_plugin_loader.gradle index d0b7287522230..ebce1091fc535 100644 --- a/packages/flutter_tools/gradle/module_plugin_loader.gradle +++ b/packages/flutter_tools/gradle/module_plugin_loader.gradle @@ -20,12 +20,6 @@ if (pluginsFile.exists()) { object.plugins.android.each { androidPlugin -> assert androidPlugin.name instanceof String assert androidPlugin.path instanceof String - // Skip plugins that have no native build (such as a Dart-only - // implementation of a federated plugin). - def needsBuild = androidPlugin.containsKey('native_build') ? androidPlugin['native_build'] : true - if (!needsBuild) { - return - } def pluginDirectory = new File(androidPlugin.path, 'android') assert pluginDirectory.exists() include ":${androidPlugin.name}" diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index a1b891d8104a4..de2ce3c944e70 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -50,7 +50,7 @@ import 'src/commands/update_packages.dart'; import 'src/commands/upgrade.dart'; import 'src/devtools_launcher.dart'; import 'src/features.dart'; -import 'src/globals.dart' as globals; +import 'src/globals_null_migrated.dart' as globals; // Files in `isolated` are intentionally excluded from google3 tooling. import 'src/isolated/mustache_template.dart'; import 'src/isolated/resident_web_runner.dart'; diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart index c32ff13b5b1e5..4c4bb76d7a88e 100644 --- a/packages/flutter_tools/lib/runner.dart +++ b/packages/flutter_tools/lib/runner.dart @@ -19,7 +19,7 @@ import 'src/base/logger.dart'; import 'src/base/process.dart'; import 'src/context_runner.dart'; import 'src/doctor.dart'; -import 'src/globals.dart' as globals; +import 'src/globals_null_migrated.dart' as globals; import 'src/reporting/crash_reporting.dart'; import 'src/runner/flutter_command.dart'; import 'src/runner/flutter_command_runner.dart'; @@ -39,7 +39,7 @@ Future<int> run( // Remove the verbose option; for help and doctor, users don't need to see // verbose logs. args = List<String>.of(args); - args.removeWhere((String option) => option == '-vv' || option == '-v' || option == '--verbose'); + args.removeWhere((String option) => option == '-v' || option == '--verbose'); } return runInContext<int>(() async { @@ -149,18 +149,11 @@ Future<int> _handleToolError( globals.printError('Oops; flutter has exited unexpectedly: "$error".'); try { - final BufferLogger logger = BufferLogger( - terminal: globals.terminal, - outputPreferences: globals.outputPreferences, - ); - - final DoctorText doctorText = DoctorText(logger); - final CrashDetails details = CrashDetails( command: _crashCommand(args), error: error, stackTrace: stackTrace, - doctorText: doctorText, + doctorText: await _doctorText(), ); final File file = await _createLocalCrashReport(details); await globals.crashReporter.informUser(details, file); @@ -206,7 +199,7 @@ Future<File> _createLocalCrashReport(CrashDetails details) async { buffer.writeln('```\n${details.stackTrace}```\n'); buffer.writeln('## flutter doctor\n'); - buffer.writeln('```\n${await details.doctorText.text}```'); + buffer.writeln('```\n${details.doctorText}```'); try { crashFile.writeAsStringSync(buffer.toString()); @@ -228,6 +221,22 @@ Future<File> _createLocalCrashReport(CrashDetails details) async { return crashFile; } +Future<String> _doctorText() async { + try { + final BufferLogger logger = BufferLogger( + terminal: globals.terminal, + outputPreferences: globals.outputPreferences, + ); + + final Doctor doctor = Doctor(logger: logger); + await doctor.diagnose(showColor: false); + + return logger.statusText; + } on Exception catch (error, trace) { + return 'encountered exception: $error\n\n${trace.toString().trim()}\n'; + } +} + Future<int> _exit(int code) async { // Prints the welcome message if needed. globals.flutterUsage.printWelcome(); diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart index a7e37b223ad26..76c8ab41047f3 100644 --- a/packages/flutter_tools/lib/src/android/android_device.dart +++ b/packages/flutter_tools/lib/src/android/android_device.dart @@ -362,7 +362,7 @@ class AndroidDevice extends Device { } String _getSourceSha1(AndroidApk apk) { - final File shaFile = _fileSystem.file('${apk.applicationPackage.path}.sha1'); + final File shaFile = _fileSystem.file('${apk.file.path}.sha1'); return shaFile.existsSync() ? shaFile.readAsStringSync() : ''; } @@ -435,13 +435,13 @@ class AndroidDevice extends Device { AndroidApk app, { String? userIdentifier, }) async { - if (!app.applicationPackage.existsSync()) { - _logger.printError('"${_fileSystem.path.relative(app.applicationPackage.path)}" does not exist.'); + if (!app.file.existsSync()) { + _logger.printError('"${_fileSystem.path.relative(app.file.path)}" does not exist.'); return false; } final Status status = _logger.startProgress( - 'Installing ${_fileSystem.path.relative(app.applicationPackage.path)}...', + 'Installing ${_fileSystem.path.relative(app.file.path)}...', ); final RunResult installResult = await _processUtils.run( adbCommandForDevice(<String>[ @@ -450,7 +450,7 @@ class AndroidDevice extends Device { '-r', if (userIdentifier != null) ...<String>['--user', userIdentifier], - app.applicationPackage.path + app.file.path ])); status.stop(); // Some versions of adb exit with exit code 0 even on failure :( @@ -543,7 +543,6 @@ class AndroidDevice extends Device { return LaunchResult.failed(); } - AndroidApk? builtPackage = package; AndroidArch androidArch; switch (devicePlatform) { case TargetPlatform.android_arm: @@ -588,18 +587,18 @@ class AndroidDevice extends Device { ); // Package has been built, so we can get the updated application ID and // activity name from the .apk. - builtPackage = await ApplicationPackageFactory.instance! - .getPackageForPlatform(devicePlatform, buildInfo: debuggingOptions.buildInfo) as AndroidApk?; + package = await ApplicationPackageFactory.instance! + .getPackageForPlatform(devicePlatform, buildInfo: debuggingOptions.buildInfo) as AndroidApk; } // There was a failure parsing the android project information. - if (builtPackage == null) { + if (package == null) { throwToolExit('Problem building Android application: see above error(s).'); } - _logger.printTrace("Stopping app '${builtPackage.name}' on $name."); - await stopApp(builtPackage, userIdentifier: userIdentifier); + _logger.printTrace("Stopping app '${package.name}' on $name."); + await stopApp(package, userIdentifier: userIdentifier); - if (!await installApp(builtPackage, userIdentifier: userIdentifier)) { + if (!await installApp(package, userIdentifier: userIdentifier)) { return LaunchResult.failed(); } @@ -630,6 +629,7 @@ class AndroidDevice extends Device { 'shell', 'am', 'start', '-a', 'android.intent.action.RUN', '-f', '0x20000000', // FLAG_ACTIVITY_SINGLE_TOP + '--ez', 'enable-background-compilation', 'true', '--ez', 'enable-dart-profiling', 'true', if (traceStartup) ...<String>['--ez', 'trace-startup', 'true'], @@ -673,7 +673,7 @@ class AndroidDevice extends Device { if (userIdentifier != null) ...<String>['--user', userIdentifier], ], - builtPackage.launchActivity, + package.launchActivity, ]; final String result = (await runAdbCheckedAsync(cmd)).stdout; // This invocation returns 0 even when it fails. @@ -682,7 +682,7 @@ class AndroidDevice extends Device { return LaunchResult.failed(); } - _package = builtPackage; + _package = package; if (!debuggingOptions.debuggingEnabled) { return LaunchResult.succeeded(); } diff --git a/packages/flutter_tools/lib/src/android/android_emulator.dart b/packages/flutter_tools/lib/src/android/android_emulator.dart index 45f1d2925704a..72e636ccb4f1b 100644 --- a/packages/flutter_tools/lib/src/android/android_emulator.dart +++ b/packages/flutter_tools/lib/src/android/android_emulator.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'dart:async'; import 'package:meta/meta.dart'; @@ -21,11 +23,11 @@ import 'android_sdk.dart'; class AndroidEmulators extends EmulatorDiscovery { AndroidEmulators({ - AndroidSdk? androidSdk, - required AndroidWorkflow androidWorkflow, - required FileSystem fileSystem, - required Logger logger, - required ProcessManager processManager, + @required AndroidSdk androidSdk, + @required AndroidWorkflow androidWorkflow, + @required FileSystem fileSystem, + @required Logger logger, + @required ProcessManager processManager, }) : _androidSdk = androidSdk, _androidWorkflow = androidWorkflow, _fileSystem = fileSystem, @@ -34,7 +36,7 @@ class AndroidEmulators extends EmulatorDiscovery { _processUtils = ProcessUtils(logger: logger, processManager: processManager); final AndroidWorkflow _androidWorkflow; - final AndroidSdk? _androidSdk; + final AndroidSdk _androidSdk; final FileSystem _fileSystem; final Logger _logger; final ProcessManager _processManager; @@ -48,14 +50,14 @@ class AndroidEmulators extends EmulatorDiscovery { @override bool get canLaunchAnything => _androidWorkflow.canListEmulators - && _androidSdk?.getAvdManagerPath() != null; + && _androidSdk.getAvdManagerPath() != null; @override Future<List<Emulator>> get emulators => _getEmulatorAvds(); /// Return the list of available emulator AVDs. Future<List<AndroidEmulator>> _getEmulatorAvds() async { - final String? emulatorPath = _androidSdk?.emulatorPath; + final String emulatorPath = _androidSdk?.emulatorPath; if (emulatorPath == null) { return <AndroidEmulator>[]; } @@ -80,7 +82,7 @@ class AndroidEmulators extends EmulatorDiscovery { AndroidEmulator _loadEmulatorInfo(String id) { id = id.trim(); - final String? avdPath = _androidSdk?.getAvdPath(); + final String avdPath = _androidSdk.getAvdPath(); final AndroidEmulator androidEmulatorWithoutProperties = AndroidEmulator( id, processManager: _processManager, @@ -95,11 +97,10 @@ class AndroidEmulators extends EmulatorDiscovery { return androidEmulatorWithoutProperties; } final Map<String, String> ini = parseIniLines(iniFile.readAsLinesSync()); - final String? path = ini['path']; - if (path == null) { + if (ini['path'] == null) { return androidEmulatorWithoutProperties; } - final File configFile = _fileSystem.file(_fileSystem.path.join(path, 'config.ini')); + final File configFile = _fileSystem.file(_fileSystem.path.join(ini['path'], 'config.ini')); if (!configFile.existsSync()) { return androidEmulatorWithoutProperties; } @@ -116,20 +117,20 @@ class AndroidEmulators extends EmulatorDiscovery { class AndroidEmulator extends Emulator { AndroidEmulator(String id, { - Map<String, String>? properties, - required Logger logger, - AndroidSdk? androidSdk, - required ProcessManager processManager, + Map<String, String> properties, + @required Logger logger, + @required AndroidSdk androidSdk, + @required ProcessManager processManager, }) : _properties = properties, _logger = logger, _androidSdk = androidSdk, _processUtils = ProcessUtils(logger: logger, processManager: processManager), super(id, properties != null && properties.isNotEmpty); - final Map<String, String>? _properties; + final Map<String, String> _properties; final Logger _logger; final ProcessUtils _processUtils; - final AndroidSdk? _androidSdk; + final AndroidSdk _androidSdk; // Android Studio uses the ID with underscores replaced with spaces // for the name if displayname is not set so we do the same. @@ -137,7 +138,7 @@ class AndroidEmulator extends Emulator { String get name => _prop('avd.ini.displayname') ?? id.replaceAll('_', ' ').trim(); @override - String? get manufacturer => _prop('hw.device.manufacturer'); + String get manufacturer => _prop('hw.device.manufacturer'); @override Category get category => Category.mobile; @@ -145,16 +146,12 @@ class AndroidEmulator extends Emulator { @override PlatformType get platformType => PlatformType.android; - String? _prop(String name) => _properties != null ? _properties![name] : null; + String _prop(String name) => _properties != null ? _properties[name] : null; @override - Future<void> launch({@visibleForTesting Duration? startupDuration, bool coldBoot = false}) async { - final String? emulatorPath = _androidSdk?.emulatorPath; - if (emulatorPath == null) { - throw Exception('Emulator is missing from the Android SDK'); - } + Future<void> launch({@visibleForTesting Duration startupDuration, bool coldBoot = false}) async { final List<String> command = <String>[ - emulatorPath, + _androidSdk.emulatorPath, '-avd', id, if (coldBoot) diff --git a/packages/flutter_tools/lib/src/android/android_sdk.dart b/packages/flutter_tools/lib/src/android/android_sdk.dart index 3c5c2acb255dd..ba3d01f6384cc 100644 --- a/packages/flutter_tools/lib/src/android/android_sdk.dart +++ b/packages/flutter_tools/lib/src/android/android_sdk.dart @@ -9,7 +9,7 @@ import '../base/platform.dart'; import '../base/process.dart'; import '../base/version.dart'; import '../convert.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import 'android_studio.dart'; // ANDROID_HOME is deprecated. @@ -198,7 +198,7 @@ class AndroidSdk { } } - for (final String searchPath in searchPaths) { + for (final String searchPath in searchPaths.whereType<String>()) { if (globals.fs.directory(searchPath).existsSync()) { return searchPath; } diff --git a/packages/flutter_tools/lib/src/android/android_studio.dart b/packages/flutter_tools/lib/src/android/android_studio.dart index 3a1b0629129d5..18f5678c4fe51 100644 --- a/packages/flutter_tools/lib/src/android/android_studio.dart +++ b/packages/flutter_tools/lib/src/android/android_studio.dart @@ -8,7 +8,7 @@ import '../base/process.dart'; import '../base/utils.dart'; import '../base/version.dart'; import '../convert.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../ios/plist_parser.dart'; import 'android_studio_validator.dart'; diff --git a/packages/flutter_tools/lib/src/android/application_package.dart b/packages/flutter_tools/lib/src/android/application_package.dart index 224d32007075d..ba0d439c0079e 100644 --- a/packages/flutter_tools/lib/src/android/application_package.dart +++ b/packages/flutter_tools/lib/src/android/application_package.dart @@ -21,13 +21,13 @@ import 'android_sdk.dart'; import 'gradle.dart'; /// An application package created from an already built Android APK. -class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackage { +class AndroidApk extends ApplicationPackage { AndroidApk({ required String id, - required this.applicationPackage, + required this.file, required this.versionCode, required this.launchActivity, - }) : assert(applicationPackage != null), + }) : assert(file != null), assert(launchActivity != null), super(id: id); @@ -80,14 +80,14 @@ class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackag return AndroidApk( id: packageName, - applicationPackage: apk, + file: apk, versionCode: data.versionCode == null ? null : int.tryParse(data.versionCode!), launchActivity: '${data.packageName}/${data.launchableActivityName}', ); } - @override - final FileSystemEntity applicationPackage; + /// Path to the actual apk file. + final File file; /// The path to the activity that should be launched. final String launchActivity; @@ -197,14 +197,17 @@ class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackag return AndroidApk( id: packageId, - applicationPackage: apkFile, + file: apkFile, versionCode: null, launchActivity: launchActivity, ); } @override - String get name => applicationPackage.basename; + File get packagesFile => file; + + @override + String get name => file.basename; } abstract class _Entry { diff --git a/packages/flutter_tools/lib/src/android/deferred_components_prebuild_validator.dart b/packages/flutter_tools/lib/src/android/deferred_components_prebuild_validator.dart index f11236be927d9..8d7cbba462269 100644 --- a/packages/flutter_tools/lib/src/android/deferred_components_prebuild_validator.dart +++ b/packages/flutter_tools/lib/src/android/deferred_components_prebuild_validator.dart @@ -9,7 +9,7 @@ import '../base/error_handling_io.dart'; import '../base/file_system.dart'; import '../base/logger.dart'; import '../base/platform.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../template.dart'; import 'deferred_components_validator.dart'; diff --git a/packages/flutter_tools/lib/src/android/gradle_errors.dart b/packages/flutter_tools/lib/src/android/gradle_errors.dart index 4aeac61f6993c..997c715f16821 100644 --- a/packages/flutter_tools/lib/src/android/gradle_errors.dart +++ b/packages/flutter_tools/lib/src/android/gradle_errors.dart @@ -8,7 +8,7 @@ import '../base/error_handling_io.dart'; import '../base/file_system.dart'; import '../base/process.dart'; import '../base/terminal.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import 'android_studio.dart'; @@ -76,11 +76,8 @@ final List<GradleHandledError> gradleErrors = <GradleHandledError>[ lockFileDepMissing, multidexErrorHandler, incompatibleKotlinVersionHandler, - minCompileSdkVersionHandler, ]; -const String _boxTitle = 'Flutter Fix'; - // Multidex error message. @visibleForTesting final GradleHandledError multidexErrorHandler = GradleHandledError( @@ -166,9 +163,9 @@ final GradleHandledError multidexErrorHandler = GradleHandledError( } } } else { - globals.printBox( + globals.printStatus( 'Flutter multidex handling is disabled. If you wish to let the tool configure multidex, use the --mutidex flag.', - title: _boxTitle, + indent: 4, ); } return GradleBuildStatus.exit; @@ -188,11 +185,11 @@ final GradleHandledError permissionDeniedErrorHandler = GradleHandledError( required bool usesAndroidX, required bool multidexEnabled, }) async { - globals.printBox( - '${globals.logger.terminal.warningMark} Gradle does not have execution permission.\n' + globals.printStatus('${globals.logger.terminal.warningMark} Gradle does not have execution permission.', emphasis: true); + globals.printStatus( 'You should change the ownership of the project directory to your user, ' 'or move the project to a directory with execute permissions.', - title: _boxTitle, + indent: 4, ); return GradleBuildStatus.exit; }, @@ -255,12 +252,9 @@ final GradleHandledError r8FailureHandler = GradleHandledError( required bool usesAndroidX, required bool multidexEnabled, }) async { - globals.printBox( - '${globals.logger.terminal.warningMark} The shrinker may have failed to optimize the Java bytecode.\n' - 'To disable the shrinker, pass the `--no-shrink` flag to this command.\n' - 'To learn more, see: https://developer.android.com/studio/build/shrink-code', - title: _boxTitle, - ); + globals.printStatus('${globals.logger.terminal.warningMark} The shrinker may have failed to optimize the Java bytecode.', emphasis: true); + globals.printStatus('To disable the shrinker, pass the `--no-shrink` flag to this command.', indent: 4); + globals.printStatus('To learn more, see: https://developer.android.com/studio/build/shrink-code', indent: 4); return GradleBuildStatus.exit; }, eventLabel: 'r8', @@ -286,13 +280,12 @@ final GradleHandledError licenseNotAcceptedHandler = GradleHandledError( final RegExp licenseFailure = RegExp(licenseNotAcceptedMatcher, multiLine: true); assert(licenseFailure != null); final Match? licenseMatch = licenseFailure.firstMatch(line); - globals.printBox( + globals.printStatus( '${globals.logger.terminal.warningMark} Unable to download needed Android SDK components, as the ' - 'following licenses have not been accepted: ' + 'following licenses have not been accepted:\n' '${licenseMatch?.group(1)}\n\n' 'To resolve this, please run the following command in a Terminal:\n' - 'flutter doctor --android-licenses', - title: _boxTitle, + 'flutter doctor --android-licenses' ); return GradleBuildStatus.exit; }, @@ -351,23 +344,21 @@ final GradleHandledError flavorUndefinedHandler = GradleHandledError( } } } - final String errorMessage = '${globals.logger.terminal.warningMark} Gradle project does not define a task suitable for the requested build.'; - final File buildGradle = project.directory.childDirectory('android').childDirectory('app').childFile('build.gradle'); + globals.printStatus( + '\n${globals.logger.terminal.warningMark} Gradle project does not define a task suitable ' + 'for the requested build.' + ); if (productFlavors.isEmpty) { - globals.printBox( - '$errorMessage\n\n' - 'The ${buildGradle.absolute.path} file does not define ' + globals.printStatus( + 'The android/app/build.gradle file does not define ' 'any custom product flavors. ' - 'You cannot use the --flavor option.', - title: _boxTitle, + 'You cannot use the --flavor option.' ); } else { - globals.printBox( - '$errorMessage\n\n' - 'The ${buildGradle.absolute.path} file defines product ' - 'flavors: ${productFlavors.join(', ')}. ' - 'You must specify a --flavor option to select one of them.', - title: _boxTitle, + globals.printStatus( + 'The android/app/build.gradle file defines product ' + 'flavors: ${productFlavors.join(', ')} ' + 'You must specify a --flavor option to select one of them.' ); } return GradleBuildStatus.exit; @@ -398,7 +389,7 @@ final GradleHandledError minSdkVersion = GradleHandledError( final Match? minSdkVersionMatch = _minSdkVersionPattern.firstMatch(line); assert(minSdkVersionMatch?.groupCount == 3); - final String textInBold = globals.logger.terminal.bolden( + final String bold = globals.logger.terminal.bolden( 'Fix this issue by adding the following to the file ${gradleFile.path}:\n' 'android {\n' ' defaultConfig {\n' @@ -406,12 +397,12 @@ final GradleHandledError minSdkVersion = GradleHandledError( ' }\n' '}\n' ); - globals.printBox( + globals.printStatus( + '\n' 'The plugin ${minSdkVersionMatch?.group(3)} requires a higher Android SDK version.\n' - '$textInBold\n' + '$bold\n' "Note that your app won't be available to users running Android SDKs below ${minSdkVersionMatch?.group(2)}.\n" - 'Alternatively, try to find a version of this plugin that supports these lower versions of the Android SDK.', - title: _boxTitle, + 'Alternatively, try to find a version of this plugin that supports these lower versions of the Android SDK.' ); return GradleBuildStatus.exit; }, @@ -435,7 +426,7 @@ final GradleHandledError transformInputIssue = GradleHandledError( .childDirectory('android') .childDirectory('app') .childFile('build.gradle'); - final String textInBold = globals.logger.terminal.bolden( + final String bold = globals.logger.terminal.bolden( 'Fix this issue by adding the following to the file ${gradleFile.path}:\n' 'android {\n' ' lintOptions {\n' @@ -443,10 +434,10 @@ final GradleHandledError transformInputIssue = GradleHandledError( ' }\n' '}' ); - globals.printBox( + globals.printStatus( + '\n' 'This issue appears to be https://github.com/flutter/flutter/issues/58247.\n' - '$textInBold', - title: _boxTitle, + '$bold' ); return GradleBuildStatus.exit; }, @@ -468,14 +459,14 @@ final GradleHandledError lockFileDepMissing = GradleHandledError( final File gradleFile = project.directory .childDirectory('android') .childFile('build.gradle'); - final String textInBold = globals.logger.terminal.bolden( + final String bold = globals.logger.terminal.bolden( 'To regenerate the lockfiles run: `./gradlew :generateLockfiles` in ${gradleFile.path}\n' - 'To remove dependency locking, remove the `dependencyLocking` from ${gradleFile.path}' + 'To remove dependency locking, remove the `dependencyLocking` from ${gradleFile.path}\n' ); - globals.printBox( + globals.printStatus( + '\n' 'You need to update the lockfile, or disable Gradle dependency locking.\n' - '$textInBold', - title: _boxTitle, + '$bold' ); return GradleBuildStatus.exit; }, @@ -496,44 +487,17 @@ final GradleHandledError incompatibleKotlinVersionHandler = GradleHandledError( final File gradleFile = project.directory .childDirectory('android') .childFile('build.gradle'); - globals.printBox( - '${globals.logger.terminal.warningMark} Your project requires a newer version of the Kotlin Gradle plugin.\n' - 'Find the latest version on https://kotlinlang.org/docs/gradle.html#plugin-and-versions, then update ${gradleFile.path}:\n' + globals.printStatus( + '${globals.logger.terminal.warningMark} Your project requires a newer version of the Kotlin Gradle plugin.', + emphasis: true, + ); + globals.printStatus( + 'Find the latest version on https://kotlinlang.org/docs/gradle.html#plugin-and-versions, ' + 'then update ${gradleFile.path}:\n' "ext.kotlin_version = '<latest-version>'", - title: _boxTitle, + indent: 4, ); return GradleBuildStatus.exit; }, eventLabel: 'incompatible-kotlin-version', ); - -final RegExp _minCompileSdkVersionPattern = RegExp(r'The minCompileSdk \(([0-9]+)\) specified in a'); - -@visibleForTesting -final GradleHandledError minCompileSdkVersionHandler = GradleHandledError( - test: _minCompileSdkVersionPattern.hasMatch, - handler: ({ - required String line, - required FlutterProject project, - required bool usesAndroidX, - required bool multidexEnabled, - }) async { - final Match? minSdkVersionMatch = _minCompileSdkVersionPattern.firstMatch(line); - assert(minSdkVersionMatch?.groupCount == 1); - - final File gradleFile = project.directory - .childDirectory('android') - .childDirectory('app') - .childFile('build.gradle'); - globals.printBox( - '${globals.logger.terminal.warningMark} Your project requires a higher compileSdkVersion.\n' - 'Fix this issue by bumping the compileSdkVersion in ${gradleFile.path}:\n' - 'android {\n' - ' compileSdkVersion ${minSdkVersionMatch?.group(1)}\n' - '}', - title: _boxTitle, - ); - return GradleBuildStatus.exit; - }, - eventLabel: 'min-compile-sdk-version', -); diff --git a/packages/flutter_tools/lib/src/android/gradle_utils.dart b/packages/flutter_tools/lib/src/android/gradle_utils.dart index b768241f42b93..9f5d7680ed522 100644 --- a/packages/flutter_tools/lib/src/android/gradle_utils.dart +++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart @@ -14,22 +14,12 @@ import '../base/utils.dart'; import '../base/version.dart'; import '../build_info.dart'; import '../cache.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import 'android_sdk.dart'; -// These are the versions used in the project templates. -// -// In general, Flutter aims to default to the latest version. -// However, this currently requires to migrate existing integration tests to the latest supported values. -// -// For more information about the latest version, check: -// https://developer.android.com/studio/releases/gradle-plugin#updating-gradle -// https://kotlinlang.org/docs/gradle.html#plugin-and-versions -const String templateDefaultGradleVersion = '6.7'; -const String templateAndroidGradlePluginVersion = '4.1.0'; -const String templateKotlinGradlePluginVersion = '1.6.10'; +const String _defaultGradleVersion = '6.7'; final RegExp _androidPluginRegExp = RegExp(r'com\.android\.tools\.build:gradle:(\d+\.\d+\.\d+)'); @@ -119,14 +109,14 @@ distributionUrl=https\\://services.gradle.org/distributions/gradle-$gradleVersio String getGradleVersionForAndroidPlugin(Directory directory, Logger logger) { final File buildFile = directory.childFile('build.gradle'); if (!buildFile.existsSync()) { - logger.printTrace("$buildFile doesn't exist, assuming Gradle version: $templateDefaultGradleVersion"); - return templateDefaultGradleVersion; + logger.printTrace("$buildFile doesn't exist, assuming AGP version: $_defaultGradleVersion"); + return _defaultGradleVersion; } final String buildFileContent = buildFile.readAsStringSync(); final Iterable<Match> pluginMatches = _androidPluginRegExp.allMatches(buildFileContent); if (pluginMatches.isEmpty) { - logger.printTrace("$buildFile doesn't provide an AGP version, assuming Gradle version: $templateDefaultGradleVersion"); - return templateDefaultGradleVersion; + logger.printTrace("$buildFile doesn't provide an AGP version, assuming AGP version: $_defaultGradleVersion"); + return _defaultGradleVersion; } final String? androidPluginVersion = pluginMatches.first.group(1); logger.printTrace('$buildFile provides AGP version: $androidPluginVersion'); diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart index 100c6901ee03f..2dc7cda70d8e2 100644 --- a/packages/flutter_tools/lib/src/application_package.dart +++ b/packages/flutter_tools/lib/src/application_package.dart @@ -10,10 +10,10 @@ abstract class ApplicationPackageFactory { static ApplicationPackageFactory? get instance => context.get<ApplicationPackageFactory>(); /// Create an [ApplicationPackage] for the given platform. - Future<ApplicationPackage?> getPackageForPlatform( + Future<ApplicationPackage> getPackageForPlatform( TargetPlatform platform, { - BuildInfo? buildInfo, - File? applicationBinary, + BuildInfo buildInfo, + File applicationBinary, }); } @@ -28,15 +28,8 @@ abstract class ApplicationPackage { String? get displayName => name; + File? get packagesFile => null; + @override String toString() => displayName ?? id; } - -/// An interface for application package that is created from prebuilt binary. -abstract class PrebuiltApplicationPackage implements ApplicationPackage { - /// The application bundle of the prebuilt application. - /// - /// The same ApplicationPackage should be able to be recreated by passing - /// the file to [FlutterApplicationPackageFactory.getPackageForPlatform]. - FileSystemEntity get applicationPackage; -} diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index c1b5cc7beeba3..7e348bba872a1 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -12,7 +12,7 @@ import 'base/platform.dart'; import 'base/utils.dart'; import 'build_info.dart'; import 'cache.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; enum Artifact { /// The tool which compiles a dart kernel file into native code. diff --git a/packages/flutter_tools/lib/src/base/common.dart b/packages/flutter_tools/lib/src/base/common.dart index be5c4723eca7a..b0115473f6d2e 100644 --- a/packages/flutter_tools/lib/src/base/common.dart +++ b/packages/flutter_tools/lib/src/base/common.dart @@ -6,7 +6,7 @@ /// where the tool should exit with a clear message to the user /// and no stack trace unless the --verbose option is specified. /// For example: network errors. -Never throwToolExit(String? message, { int? exitCode }) { +Never throwToolExit(String message, { int? exitCode }) { throw ToolExit(message, exitCode: exitCode); } diff --git a/packages/flutter_tools/lib/src/base/error_handling_io.dart b/packages/flutter_tools/lib/src/base/error_handling_io.dart index 3bdd3c037f64b..331246ee9c2da 100644 --- a/packages/flutter_tools/lib/src/base/error_handling_io.dart +++ b/packages/flutter_tools/lib/src/base/error_handling_io.dart @@ -662,8 +662,8 @@ class ErrorHandlingProcessManager extends ProcessManager { Map<String, String>? environment, bool includeParentEnvironment = true, bool runInShell = false, - Encoding? stdoutEncoding = io.systemEncoding, - Encoding? stderrEncoding = io.systemEncoding, + Encoding stdoutEncoding = io.systemEncoding, + Encoding stderrEncoding = io.systemEncoding, }) { return _run(() { return _delegate.run( @@ -705,8 +705,8 @@ class ErrorHandlingProcessManager extends ProcessManager { Map<String, String>? environment, bool includeParentEnvironment = true, bool runInShell = false, - Encoding? stdoutEncoding = io.systemEncoding, - Encoding? stderrEncoding = io.systemEncoding, + Encoding stdoutEncoding = io.systemEncoding, + Encoding stderrEncoding = io.systemEncoding, }) { return _runSync(() { return _delegate.runSync( diff --git a/packages/flutter_tools/lib/src/base/logger.dart b/packages/flutter_tools/lib/src/base/logger.dart index c4ba1e2845220..4c605b0ee3526 100644 --- a/packages/flutter_tools/lib/src/base/logger.dart +++ b/packages/flutter_tools/lib/src/base/logger.dart @@ -3,12 +3,10 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:math'; import 'package:meta/meta.dart'; import '../convert.dart'; -import 'common.dart'; import 'io.dart'; import 'terminal.dart' show Terminal, TerminalColor, OutputPreferences; import 'utils.dart'; @@ -30,41 +28,22 @@ class StopwatchFactory { typedef VoidCallback = void Function(); abstract class Logger { - /// Whether or not this logger should print [printTrace] messages. bool get isVerbose => false; - /// If true, silences the logger output. bool quiet = false; - /// If true, this logger supports color output. bool get supportsColor; - /// If true, this logger is connected to a terminal. bool get hasTerminal; - /// If true, then [printError] has been called at least once for this logger - /// since the last time it was set to false. - bool hadErrorOutput = false; - - /// If true, then [printWarning] has been called at least once for this logger - /// since the last time it was reset to false. - bool hadWarningOutput = false; - - /// Causes [checkForFatalLogs] to call [throwToolExit] when it is called if - /// [hadWarningOutput] is true. - bool fatalWarnings = false; - - /// Returns the terminal attached to this logger. Terminal get terminal; OutputPreferences get _outputPreferences; /// Display an error `message` to the user. Commands should use this if they - /// fail in some way. Errors are typically followed shortly by a call to - /// [throwToolExit] to terminate the run. + /// fail in some way. /// - /// The `message` argument is printed to the stderr in [TerminalColor.red] by - /// default. + /// The `message` argument is printed to the stderr in red by default. /// /// The `stackTrace` argument is the stack trace that will be printed if /// supplied. @@ -95,41 +74,10 @@ abstract class Logger { bool? wrap, }); - /// Display a warning `message` to the user. Commands should use this if they - /// important information to convey to the user that is not fatal. - /// - /// The `message` argument is printed to the stderr in [TerminalColor.cyan] by - /// default. - /// - /// The `emphasis` argument will cause the output message be printed in bold text. - /// - /// The `color` argument will print the message in the supplied color instead - /// of the default of cyan. Colors will not be printed if the output terminal - /// doesn't support them. - /// - /// The `indent` argument specifies the number of spaces to indent the overall - /// message. If wrapping is enabled in [outputPreferences], then the wrapped - /// lines will be indented as well. - /// - /// If `hangingIndent` is specified, then any wrapped lines will be indented - /// by this much more than the first line, if wrapping is enabled in - /// [outputPreferences]. - /// - /// If `wrap` is specified, then it overrides the - /// `outputPreferences.wrapText` setting. - void printWarning( - String message, { - bool? emphasis, - TerminalColor? color, - int? indent, - int? hangingIndent, - bool? wrap, - }); - /// Display normal output of the command. This should be used for things like /// progress messages, success messages, or just normal command output. /// - /// The `message` argument is printed to the stdout. + /// The `message` argument is printed to the stderr in red by default. /// /// The `stackTrace` argument is the stack trace that will be printed if /// supplied. @@ -164,32 +112,6 @@ abstract class Logger { bool? wrap, }); - /// Display the [message] inside a box. - /// - /// For example, this is the generated output: - /// - /// ┌─ [title] ─┐ - /// │ [message] │ - /// └───────────┘ - /// - /// If a terminal is attached, the lines in [message] are automatically wrapped based on - /// the available columns. - /// - /// Use this utility only to highlight a message in the logs. - /// - /// This is particularly useful when the message can be easily missed because of clutter - /// generated by other commands invoked by the tool. - /// - /// One common use case is to provide actionable steps in a Flutter app when a Gradle - /// error is printed. - /// - /// In the future, this output can be integrated with an IDE like VS Code to display a - /// notification, and allow the user to trigger an action. e.g. run a migration. - void printBox( - String message, { - String? title, - }); - /// Use this for verbose tracing output. Users can turn this output on in order /// to help diagnose issues with the toolchain or with their setup. void printTrace(String message); @@ -222,21 +144,9 @@ abstract class Logger { /// Clears all output. void clear(); - - /// If [fatalWarnings] is set, causes the logger to check if - /// [hadWarningOutput] is true, and then to call [throwToolExit] if so. - /// - /// The [fatalWarnings] flag can be set from the command line with the - /// "--fatal-warnings" option on commands that support it. - void checkForFatalLogs() { - if (fatalWarnings && (hadWarningOutput || hadErrorOutput)) { - throwToolExit('Logger received ${hadErrorOutput ? 'error' : 'warning'} output ' - 'during the run, and "--fatal-warnings" is enabled.'); - } - } } -/// A [Logger] that forwards all methods to another logger. +/// A [Logger] that forwards all methods to another one. /// /// Classes can derive from this to add functionality to an existing [Logger]. class DelegatingLogger implements Logger { @@ -264,24 +174,6 @@ class DelegatingLogger implements Logger { @override bool get isVerbose => _delegate.isVerbose; - @override - bool get hadErrorOutput => _delegate.hadErrorOutput; - - @override - set hadErrorOutput(bool value) => _delegate.hadErrorOutput = value; - - @override - bool get hadWarningOutput => _delegate.hadWarningOutput; - - @override - set hadWarningOutput(bool value) => _delegate.hadWarningOutput = value; - - @override - bool get fatalWarnings => _delegate.fatalWarnings; - - @override - set fatalWarnings(bool value) => _delegate.fatalWarnings = value; - @override void printError(String message, { StackTrace? stackTrace, @@ -302,24 +194,6 @@ class DelegatingLogger implements Logger { ); } - @override - void printWarning(String message, { - bool? emphasis, - TerminalColor? color, - int? indent, - int? hangingIndent, - bool? wrap, - }) { - _delegate.printWarning( - message, - emphasis: emphasis, - color: color, - indent: indent, - hangingIndent: hangingIndent, - wrap: wrap, - ); - } - @override void printStatus(String message, { bool? emphasis, @@ -339,13 +213,6 @@ class DelegatingLogger implements Logger { ); } - @override - void printBox(String message, { - String? title, - }) { - _delegate.printBox(message, title: title); - } - @override void printTrace(String message) { _delegate.printTrace(message); @@ -377,9 +244,6 @@ class DelegatingLogger implements Logger { @override void clear() => _delegate.clear(); - - @override - void checkForFatalLogs() => _delegate.checkForFatalLogs(); } /// If [logger] is a [DelegatingLogger], walks the delegate chain and returns @@ -439,7 +303,6 @@ class StdoutLogger extends Logger { int? hangingIndent, bool? wrap, }) { - hadErrorOutput = true; _status?.pause(); message = wrapText(message, indent: indent, @@ -458,31 +321,6 @@ class StdoutLogger extends Logger { _status?.resume(); } - @override - void printWarning( - String message, { - bool? emphasis, - TerminalColor? color, - int? indent, - int? hangingIndent, - bool? wrap, - }) { - hadWarningOutput = true; - _status?.pause(); - message = wrapText(message, - indent: indent, - hangingIndent: hangingIndent, - shouldWrap: wrap ?? _outputPreferences.wrapText, - columnWidth: _outputPreferences.wrapColumn, - ); - if (emphasis == true) { - message = terminal.bolden(message); - } - message = terminal.color(message, color ?? TerminalColor.cyan); - writeToStdErr('$message\n'); - _status?.resume(); - } - @override void printStatus( String message, { @@ -513,21 +351,6 @@ class StdoutLogger extends Logger { _status?.resume(); } - @override - void printBox(String message, { - String? title, - }) { - _status?.pause(); - _generateBox( - title: title, - message: message, - wrapColumn: _outputPreferences.wrapColumn, - terminal: terminal, - write: writeToStdOut, - ); - _status?.resume(); - } - @protected void writeToStdOut(String message) => _stdio.stdoutWrite(message); @@ -607,77 +430,6 @@ class StdoutLogger extends Logger { } } -typedef _Writter = void Function(String message); - -/// Wraps the message in a box, and writes the bytes by calling [write]. -/// -/// Example output: -/// -/// ┌─ [title] ─┐ -/// │ [message] │ -/// └───────────┘ -/// -/// When [title] is provided, the box will have a title above it. -/// -/// The box width never exceeds [wrapColumn]. -/// -/// If [wrapColumn] is not provided, the default value is 100. -void _generateBox({ - required String message, - required int wrapColumn, - required _Writter write, - required Terminal terminal, - String? title, -}) { - const int kPaddingLeftRight = 1; - const int kEdges = 2; - - final int maxTextWidthPerLine = wrapColumn - kEdges - kPaddingLeftRight * 2; - final List<String> lines = wrapText(message, shouldWrap: true, columnWidth: maxTextWidthPerLine).split('\n'); - final List<int> lineWidth = lines.map((String line) => _getColumnSize(line)).toList(); - final int maxColumnSize = lineWidth.reduce((int currLen, int maxLen) => max(currLen, maxLen)); - final int textWidth = min(maxColumnSize, maxTextWidthPerLine); - final int textWithPaddingWidth = textWidth + kPaddingLeftRight * 2; - - write('\n'); - - // Write `┌─ [title] ─┐`. - write('┌'); - write('─'); - if (title == null) { - write('─' * (textWithPaddingWidth - 1)); - } else { - write(' ${terminal.bolden(title)} '); - write('─' * (textWithPaddingWidth - title.length - 3)); - } - write('┐'); - write('\n'); - - // Write `│ [message] │`. - for (int lineIdx = 0; lineIdx < lines.length; lineIdx++) { - write('│'); - write(' ' * kPaddingLeftRight); - write(lines[lineIdx]); - final int remainingSpacesToEnd = textWidth - lineWidth[lineIdx]; - write(' ' * (remainingSpacesToEnd + kPaddingLeftRight)); - write('│'); - write('\n'); - } - - // Write `└───────────┘`. - write('└'); - write('─' * textWithPaddingWidth); - write('┘'); - write('\n'); -} - -final RegExp _ansiEscapePattern = RegExp('\x1B\\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x7E]'); - -int _getColumnSize(String line) { - // Remove ANSI escape characters from the string. - return line.replaceAll(_ansiEscapePattern, '').length; -} - /// A [StdoutLogger] which replaces Unicode characters that cannot be printed to /// the Windows console with alternative symbols. /// @@ -730,6 +482,7 @@ class BufferLogger extends Logger { _outputPreferences = outputPreferences ?? OutputPreferences.test(), _stopwatchFactory = const StopwatchFactory(); + @override final OutputPreferences _outputPreferences; @@ -745,13 +498,11 @@ class BufferLogger extends Logger { bool get supportsColor => terminal.supportsColor; final StringBuffer _error = StringBuffer(); - final StringBuffer _warning = StringBuffer(); final StringBuffer _status = StringBuffer(); final StringBuffer _trace = StringBuffer(); final StringBuffer _events = StringBuffer(); String get errorText => _error.toString(); - String get warningText => _warning.toString(); String get statusText => _status.toString(); String get traceText => _trace.toString(); String get eventText => _events.toString(); @@ -769,7 +520,6 @@ class BufferLogger extends Logger { int? hangingIndent, bool? wrap, }) { - hadErrorOutput = true; _error.writeln(terminal.color( wrapText(message, indent: indent, @@ -781,27 +531,6 @@ class BufferLogger extends Logger { )); } - @override - void printWarning( - String message, { - bool? emphasis, - TerminalColor? color, - int? indent, - int? hangingIndent, - bool? wrap, - }) { - hadWarningOutput = true; - _warning.writeln(terminal.color( - wrapText(message, - indent: indent, - hangingIndent: hangingIndent, - shouldWrap: wrap ?? _outputPreferences.wrapText, - columnWidth: _outputPreferences.wrapColumn, - ), - color ?? TerminalColor.cyan, - )); - } - @override void printStatus( String message, { @@ -829,19 +558,6 @@ class BufferLogger extends Logger { } } - @override - void printBox(String message, { - String? title, - }) { - _generateBox( - title: title, - message: message, - wrapColumn: _outputPreferences.wrapColumn, - terminal: terminal, - write: _status.write, - ); - } - @override void printTrace(String message) => _trace.writeln(message); @@ -909,7 +625,6 @@ class VerboseLogger extends DelegatingLogger { int? hangingIndent, bool? wrap, }) { - hadErrorOutput = true; _emit( _LogType.error, wrapText(message, @@ -922,29 +637,6 @@ class VerboseLogger extends DelegatingLogger { ); } - @override - void printWarning( - String message, { - StackTrace? stackTrace, - bool? emphasis, - TerminalColor? color, - int? indent, - int? hangingIndent, - bool? wrap, - }) { - hadWarningOutput = true; - _emit( - _LogType.warning, - wrapText(message, - indent: indent, - hangingIndent: hangingIndent, - shouldWrap: wrap ?? _outputPreferences.wrapText, - columnWidth: _outputPreferences.wrapColumn, - ), - stackTrace, - ); - } - @override void printStatus( String message, { @@ -963,23 +655,6 @@ class VerboseLogger extends DelegatingLogger { )); } - @override - void printBox(String message, { - String? title, - }) { - String composedMessage = ''; - _generateBox( - title: title, - message: message, - wrapColumn: _outputPreferences.wrapColumn, - terminal: terminal, - write: (String line) { - composedMessage += line; - }, - ); - _emit(_LogType.status, composedMessage); - } - @override void printTrace(String message) { _emit(_LogType.trace, message); @@ -1032,25 +707,15 @@ class VerboseLogger extends DelegatingLogger { final String indent = ''.padLeft(prefix.length); final String indentMessage = message.replaceAll('\n', '\n$indent'); - switch (type) { - case _LogType.error: - super.printError(prefix + terminal.bolden(indentMessage)); - if (stackTrace != null) { - super.printError(indent + stackTrace.toString().replaceAll('\n', '\n$indent')); - } - break; - case _LogType.warning: - super.printWarning(prefix + terminal.bolden(indentMessage)); - break; - case _LogType.status: - super.printStatus(prefix + terminal.bolden(indentMessage)); - break; - case _LogType.trace: - // This seems wrong, since there is a 'printTrace' to call on the - // superclass, but it's actually the entire point of this logger: to - // make things more verbose than they normally would be. - super.printStatus(prefix + indentMessage); - break; + if (type == _LogType.error) { + super.printError(prefix + terminal.bolden(indentMessage)); + if (stackTrace != null) { + super.printError(indent + stackTrace.toString().replaceAll('\n', '\n$indent')); + } + } else if (type == _LogType.status) { + super.printStatus(prefix + terminal.bolden(indentMessage)); + } else { + super.printStatus(prefix + indentMessage); } } @@ -1071,7 +736,6 @@ class PrefixedErrorLogger extends DelegatingLogger { int? hangingIndent, bool? wrap, }) { - hadErrorOutput = true; if (message.trim().isNotEmpty == true) { message = 'ERROR: $message'; } @@ -1087,7 +751,7 @@ class PrefixedErrorLogger extends DelegatingLogger { } } -enum _LogType { error, warning, status, trace } +enum _LogType { error, status, trace } typedef SlowWarningCallback = String Function(); @@ -1156,7 +820,7 @@ abstract class Status { } } -/// A [Status] that shows nothing. +/// A [SilentStatus] shows nothing. class SilentStatus extends Status { SilentStatus({ required Stopwatch stopwatch, diff --git a/packages/flutter_tools/lib/src/base/os.dart b/packages/flutter_tools/lib/src/base/os.dart index d3bb74083548b..aae9e2da71fa8 100644 --- a/packages/flutter_tools/lib/src/base/os.dart +++ b/packages/flutter_tools/lib/src/base/os.dart @@ -184,22 +184,20 @@ class _PosixUtils extends OperatingSystemUtils { @override void chmod(FileSystemEntity entity, String mode) { - // Errors here are silently ignored (except when tracing). try { final ProcessResult result = _processManager.runSync( <String>['chmod', mode, entity.path], ); if (result.exitCode != 0) { _logger.printTrace( - 'Error trying to run "chmod $mode ${entity.path}":\n' - ' exit code: ${result.exitCode}\n' - ' stdout: ${result.stdout.toString().trimRight()}\n' - ' stderr: ${result.stderr.toString().trimRight()}' + 'Error trying to run chmod on ${entity.absolute.path}' + '\nstdout: ${result.stdout}' + '\nstderr: ${result.stderr}', ); } } on ProcessException catch (error) { _logger.printTrace( - 'Error trying to run "chmod $mode ${entity.path}": $error', + 'Error trying to run chmod on ${entity.absolute.path}: $error', ); } } @@ -270,22 +268,20 @@ class _PosixUtils extends OperatingSystemUtils { @override HostPlatform get hostPlatform { if (_hostPlatform == null) { - final RunResult hostPlatformCheck = _processUtils.runSync(<String>['uname', '-m']); + final RunResult hostPlatformCheck = + _processUtils.runSync(<String>['uname', '-m']); // On x64 stdout is "uname -m: x86_64" // On arm64 stdout is "uname -m: aarch64, arm64_v8a" if (hostPlatformCheck.exitCode != 0) { - _hostPlatform = HostPlatform.linux_x64; _logger.printError( - 'Encountered an error trying to run "uname -m":\n' - ' exit code: ${hostPlatformCheck.exitCode}\n' - ' stdout: ${hostPlatformCheck.stdout.trimRight()}\n' - ' stderr: ${hostPlatformCheck.stderr.trimRight()}\n' - 'Assuming host platform is ${getNameForHostPlatform(_hostPlatform!)}.', + 'Error trying to run uname -m' + '\nstdout: ${hostPlatformCheck.stdout}' + '\nstderr: ${hostPlatformCheck.stderr}', ); + _hostPlatform = HostPlatform.linux_x64; } else if (hostPlatformCheck.stdout.trim().endsWith('x86_64')) { _hostPlatform = HostPlatform.linux_x64; } else { - // We default to ARM if it's not x86_64 and we did not get an error. _hostPlatform = HostPlatform.linux_arm64; } } @@ -451,9 +447,8 @@ class _MacOSUtils extends _PosixUtils { ); for (final FileSystemEntity unzippedFile in tempDirectory.listSync(followLinks: false)) { // rsync --delete the unzipped files so files removed from the archive are also removed from the target. - // Add the '-8' parameter to avoid mangling filenames with encodings that do not match the current locale. _processUtils.runSync( - <String>['rsync', '-8', '-av', '--delete', unzippedFile.path, targetDirectory.path], + <String>['rsync', '-av', '--delete', unzippedFile.path, targetDirectory.path], throwOnError: true, verboseExceptions: true, ); diff --git a/packages/flutter_tools/lib/src/base/task_queue.dart b/packages/flutter_tools/lib/src/base/task_queue.dart index b93359a31dcf9..a83baff2ab1b6 100644 --- a/packages/flutter_tools/lib/src/base/task_queue.dart +++ b/packages/flutter_tools/lib/src/base/task_queue.dart @@ -5,7 +5,7 @@ import 'dart:async'; import 'dart:collection'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; /// A closure type used by the [TaskQueue]. typedef TaskQueueClosure<T> = Future<T> Function(); diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart index f9c952c49ddf5..e2c9089472602 100644 --- a/packages/flutter_tools/lib/src/base/user_messages.dart +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -24,7 +24,6 @@ class UserMessages { String flutterGitUrl(String url) => 'FLUTTER_GIT_URL = $url'; String engineRevision(String revision) => 'Engine revision $revision'; String dartRevision(String revision) => 'Dart version $revision'; - String devToolsVersion(String version) => 'DevTools version $version'; String pubMirrorURL(String url) => 'Pub download mirror $url'; String flutterMirrorURL(String url) => 'Flutter download mirror $url'; String get flutterBinariesDoNotRun => diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index e8d5a7551e318..765e9f851c098 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -11,7 +11,7 @@ import 'base/logger.dart'; import 'base/os.dart'; import 'base/utils.dart'; import 'convert.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; /// Whether icon font subsetting is enabled by default. const bool kIconTreeShakerEnabledDefault = true; @@ -751,7 +751,7 @@ HostPlatform getCurrentHostPlatform() { return HostPlatform.windows_x64; } - globals.printWarning('Unsupported host platform, defaulting to Linux'); + globals.printError('Unsupported host platform, defaulting to Linux'); return HostPlatform.linux_x64; } diff --git a/packages/flutter_tools/lib/src/build_system/targets/android.dart b/packages/flutter_tools/lib/src/build_system/targets/android.dart index ee86042f748b8..b9e7dcec013d8 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/android.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/android.dart @@ -7,7 +7,7 @@ import '../../base/build.dart'; import '../../base/deferred_component.dart'; import '../../base/file_system.dart'; import '../../build_info.dart'; -import '../../globals.dart' as globals show xcode; +import '../../globals_null_migrated.dart' as globals show xcode; import '../../project.dart'; import '../build_system.dart'; import '../depfile.dart'; diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 6b0ac8d0406d1..05a048ef4ae0a 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -10,7 +10,7 @@ import '../../base/file_system.dart'; import '../../build_info.dart'; import '../../compile.dart'; import '../../dart/package_map.dart'; -import '../../globals.dart' as globals show xcode; +import '../../globals_null_migrated.dart' as globals show xcode; import '../build_system.dart'; import '../depfile.dart'; import '../exceptions.dart'; diff --git a/packages/flutter_tools/lib/src/build_system/targets/deferred_components.dart b/packages/flutter_tools/lib/src/build_system/targets/deferred_components.dart index 21208979a66b8..a01ab26bab294 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/deferred_components.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/deferred_components.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:meta/meta.dart'; import '../../android/deferred_components_gen_snapshot_validator.dart'; @@ -17,8 +19,8 @@ import 'android.dart'; class DeferredComponentsGenSnapshotValidatorTarget extends Target { /// Create an [AndroidAotDeferredComponentsBundle] implementation for a given [targetPlatform] and [buildMode]. DeferredComponentsGenSnapshotValidatorTarget({ - required this.deferredComponentsDependencies, - required this.nonDeferredComponentsDependencies, + @required this.deferredComponentsDependencies, + @required this.nonDeferredComponentsDependencies, this.title, this.exitOnFail = true, }); @@ -29,7 +31,7 @@ class DeferredComponentsGenSnapshotValidatorTarget extends Target { /// The title of the [DeferredComponentsGenSnapshotValidator] that is /// displayed to the developer when logging results. - final String? title; + final String title; /// Whether to exit the tool if a recommended change is found by the /// [DeferredComponentsGenSnapshotValidator]. @@ -70,7 +72,7 @@ class DeferredComponentsGenSnapshotValidatorTarget extends Target { } @visibleForTesting - DeferredComponentsGenSnapshotValidator? validator; + DeferredComponentsGenSnapshotValidator validator; @override Future<void> build(Environment environment) async { @@ -90,18 +92,18 @@ class DeferredComponentsGenSnapshotValidatorTarget extends Target { abis: _abis ); - validator! + validator ..checkAppAndroidManifestComponentLoadingUnitMapping( - FlutterProject.current().manifest.deferredComponents ?? <DeferredComponent>[], + FlutterProject.current().manifest.deferredComponents, generatedLoadingUnits, ) ..checkAgainstLoadingUnitsCache(generatedLoadingUnits) ..writeLoadingUnitsCache(generatedLoadingUnits); - validator!.handleResults(); + validator.handleResults(); depfileService.writeToFile( - Depfile(validator!.inputs, validator!.outputs), + Depfile(validator.inputs, validator.outputs), environment.buildDir.childFile('flutter_$name.d'), ); } diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart index ae2b2014fd2da..94d53a0cf6198 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:meta/meta.dart'; import '../../artifacts.dart'; @@ -10,7 +12,7 @@ import '../../base/common.dart'; import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../build_info.dart'; -import '../../globals.dart' as globals show xcode; +import '../../globals_null_migrated.dart' as globals show xcode; import '../../macos/xcode.dart'; import '../../project.dart'; import '../build_system.dart'; @@ -35,47 +37,45 @@ abstract class AotAssemblyBase extends Target { final AOTSnapshotter snapshotter = AOTSnapshotter( fileSystem: environment.fileSystem, logger: environment.logger, - xcode: globals.xcode!, + xcode: globals.xcode, artifacts: environment.artifacts, processManager: environment.processManager, ); final String buildOutputPath = environment.buildDir.path; - final String? environmentBuildMode = environment.defines[kBuildMode]; - if (environmentBuildMode == null) { + if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'aot_assembly'); } - final String? environmentTargetPlatform = environment.defines[kTargetPlatform]; - if (environmentTargetPlatform== null) { + if (environment.defines[kTargetPlatform] == null) { throw MissingDefineException(kTargetPlatform, 'aot_assembly'); } - final String? sdkRoot = environment.defines[kSdkRoot]; - if (sdkRoot == null) { + if (environment.defines[kSdkRoot] == null) { throw MissingDefineException(kSdkRoot, 'aot_assembly'); } final List<String> extraGenSnapshotOptions = decodeCommaSeparated(environment.defines, kExtraGenSnapshotOptions); final bool bitcode = environment.defines[kBitcodeFlag] == 'true'; - final BuildMode buildMode = getBuildModeForName(environmentBuildMode); - final TargetPlatform targetPlatform = getTargetPlatformForName(environmentTargetPlatform); - final String? splitDebugInfo = environment.defines[kSplitDebugInfo]; + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); + final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]); + final String splitDebugInfo = environment.defines[kSplitDebugInfo]; final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true'; final List<DarwinArch> darwinArchs = environment.defines[kIosArchs] ?.split(' ') - .map(getIOSArchForName) - .toList() + ?.map(getIOSArchForName) + ?.toList() ?? <DarwinArch>[DarwinArch.arm64]; if (targetPlatform != TargetPlatform.ios) { throw Exception('aot_assembly is only supported for iOS applications.'); } - final EnvironmentType? environmentType = environmentTypeFromSdkroot(sdkRoot, environment.fileSystem); + final String sdkRoot = environment.defines[kSdkRoot]; + final EnvironmentType environmentType = environmentTypeFromSdkroot(sdkRoot, environment.fileSystem); if (environmentType == EnvironmentType.simulator) { throw Exception( 'release/profile builds are only supported for physical devices. ' 'attempted to build for simulator.' ); } - final String? codeSizeDirectory = environment.defines[kCodeSizeDirectory]; + final String codeSizeDirectory = environment.defines[kCodeSizeDirectory]; // If we're building multiple iOS archs the binaries need to be lipo'd // together. @@ -220,13 +220,14 @@ class DebugUniversalFramework extends Target { @override Future<void> build(Environment environment) async { - final String? sdkRoot = environment.defines[kSdkRoot]; - if (sdkRoot == null) { + if (environment.defines[kSdkRoot] == null) { throw MissingDefineException(kSdkRoot, name); } // Generate a trivial App.framework. - final Set<String>? iosArchNames = environment.defines[kIosArchs]?.split(' ').toSet(); + final Set<String> iosArchNames = environment.defines[kIosArchs] + ?.split(' ') + ?.toSet(); final File output = environment.buildDir .childDirectory('App.framework') .childFile('App'); @@ -235,7 +236,6 @@ class DebugUniversalFramework extends Target { output, environment, iosArchNames, - sdkRoot, ); } } @@ -272,31 +272,30 @@ abstract class UnpackIOS extends Target { @override Future<void> build(Environment environment) async { - final String? sdkRoot = environment.defines[kSdkRoot]; - if (sdkRoot == null) { + if (environment.defines[kSdkRoot] == null) { throw MissingDefineException(kSdkRoot, name); } - final String? archs = environment.defines[kIosArchs]; - if (archs == null) { + if (environment.defines[kIosArchs] == null) { throw MissingDefineException(kIosArchs, name); } if (environment.defines[kBitcodeFlag] == null) { throw MissingDefineException(kBitcodeFlag, name); } - _copyFramework(environment, sdkRoot); + _copyFramework(environment); final File frameworkBinary = environment.outputDir.childDirectory('Flutter.framework').childFile('Flutter'); final String frameworkBinaryPath = frameworkBinary.path; if (!frameworkBinary.existsSync()) { throw Exception('Binary $frameworkBinaryPath does not exist, cannot thin'); } - _thinFramework(environment, frameworkBinaryPath, archs); + _thinFramework(environment, frameworkBinaryPath); _bitcodeStripFramework(environment, frameworkBinaryPath); _signFramework(environment, frameworkBinaryPath, buildMode); } - void _copyFramework(Environment environment, String sdkRoot) { - final EnvironmentType? environmentType = environmentTypeFromSdkroot(sdkRoot, environment.fileSystem); + void _copyFramework(Environment environment) { + final String sdkRoot = environment.defines[kSdkRoot]; + final EnvironmentType environmentType = environmentTypeFromSdkroot(sdkRoot, environment.fileSystem); final String basePath = environment.artifacts.getArtifactPath( Artifact.flutterFramework, platform: TargetPlatform.ios, @@ -322,7 +321,8 @@ abstract class UnpackIOS extends Target { } /// Destructively thin Flutter.framework to include only the specified architectures. - void _thinFramework(Environment environment, String frameworkBinaryPath, String archs) { + void _thinFramework(Environment environment, String frameworkBinaryPath) { + final String archs = environment.defines[kIosArchs]; final List<String> archList = archs.split(' ').toList(); final ProcessResult infoResult = environment.processManager.runSync(<String>[ 'lipo', @@ -454,11 +454,10 @@ abstract class IosAssetBundle extends Target { @override Future<void> build(Environment environment) async { - final String? environmentBuildMode = environment.defines[kBuildMode]; - if (environmentBuildMode == null) { + if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, name); } - final BuildMode buildMode = getBuildModeForName(environmentBuildMode); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework'); final String frameworkBinaryPath = frameworkDirectory.childFile('App').path; final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets'); @@ -575,7 +574,7 @@ class ReleaseIosApplicationBundle extends IosAssetBundle { /// but it isn't actually executed. To generate something valid, we compile a trivial /// constant. Future<void> _createStubAppFramework(File outputFile, Environment environment, - Set<String>? iosArchNames, String sdkRoot) async { + Set<String> iosArchNames) async { try { outputFile.createSync(recursive: true); } on Exception catch (e) { @@ -591,12 +590,13 @@ Future<void> _createStubAppFramework(File outputFile, Environment environment, static const int Moo = 88; '''); - final EnvironmentType? environmentType = environmentTypeFromSdkroot(sdkRoot, fileSystem); + final String sdkRoot = environment.defines[kSdkRoot]; + final EnvironmentType environmentType = environmentTypeFromSdkroot(sdkRoot, fileSystem); - await globals.xcode!.clang(<String>[ + await globals.xcode.clang(<String>[ '-x', 'c', - for (String arch in iosArchNames ?? <String>{}) ...<String>['-arch', arch], + for (String arch in iosArchNames) ...<String>['-arch', arch], stubSource.path, '-dynamiclib', '-fembed-bitcode-marker', @@ -625,9 +625,9 @@ Future<void> _createStubAppFramework(File outputFile, Environment environment, } void _signFramework(Environment environment, String binaryPath, BuildMode buildMode) { - String? codesignIdentity = environment.defines[kCodesignIdentity]; + final String codesignIdentity = environment.defines[kCodesignIdentity]; if (codesignIdentity == null || codesignIdentity.isEmpty) { - codesignIdentity = '-'; + return; } final ProcessResult result = environment.processManager.runSync(<String>[ 'codesign', diff --git a/packages/flutter_tools/lib/src/build_system/targets/linux.dart b/packages/flutter_tools/lib/src/build_system/targets/linux.dart index 549c48cc4d6f2..e9155d76ec484 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/linux.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/linux.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../../artifacts.dart'; import '../../base/file_system.dart'; import '../../build_info.dart'; @@ -47,11 +49,7 @@ class UnpackLinux extends Target { @override Future<void> build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final String engineSourcePath = environment.artifacts .getArtifactPath( Artifact.linuxDesktopPath, @@ -119,11 +117,10 @@ abstract class BundleLinuxAssets extends Target { @override Future<void> build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { + if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'bundle_linux_assets'); } - final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final Directory outputDirectory = environment.outputDir .childDirectory('flutter_assets'); if (!outputDirectory.existsSync()) { diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart index 53b3028829fe1..9672906db8f1a 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../../artifacts.dart'; import '../../base/build.dart'; import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../base/process.dart'; import '../../build_info.dart'; -import '../../globals.dart' as globals show xcode; +import '../../globals_null_migrated.dart' as globals show xcode; import '../build_system.dart'; import '../depfile.dart'; import '../exceptions.dart'; @@ -44,11 +46,10 @@ abstract class UnpackMacOS extends Target { @override Future<void> build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { + if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'unpack_macos'); } - final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final String basePath = environment.artifacts.getArtifactPath(Artifact.flutterMacOSFramework, mode: buildMode); final ProcessResult result = environment.processManager.runSync(<String>[ @@ -181,7 +182,7 @@ class DebugMacOSFramework extends Target { final Iterable<DarwinArch> darwinArchs = environment.defines[kDarwinArchs] ?.split(' ') - .map(getDarwinArchForName) + ?.map(getDarwinArchForName) ?? <DarwinArch>[DarwinArch.x86_64]; final Iterable<String> darwinArchArguments = @@ -192,7 +193,7 @@ class DebugMacOSFramework extends Target { ..writeAsStringSync(r''' static const int Moo = 88; '''); - final RunResult result = await globals.xcode!.clang(<String>[ + final RunResult result = await globals.xcode.clang(<String>[ '-x', 'c', debugApp.path, @@ -230,28 +231,23 @@ class CompileMacOSFramework extends Target { @override Future<void> build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { + if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'compile_macos_framework'); } - final String? targetPlatformEnvironment = environment.defines[kTargetPlatform]; - if (targetPlatformEnvironment == null) { - throw MissingDefineException(kTargetPlatform, 'kernel_snapshot'); - } - final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); if (buildMode == BuildMode.debug) { throw Exception('precompiled macOS framework only supported in release/profile builds.'); } final String buildOutputPath = environment.buildDir.path; - final String? codeSizeDirectory = environment.defines[kCodeSizeDirectory]; - final String? splitDebugInfo = environment.defines[kSplitDebugInfo]; + final String codeSizeDirectory = environment.defines[kCodeSizeDirectory]; + final String splitDebugInfo = environment.defines[kSplitDebugInfo]; final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true'; final List<String> extraGenSnapshotOptions = decodeCommaSeparated(environment.defines, kExtraGenSnapshotOptions); - final TargetPlatform targetPlatform = getTargetPlatformForName(targetPlatformEnvironment); + final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]); final List<DarwinArch> darwinArchs = environment.defines[kDarwinArchs] ?.split(' ') - .map(getDarwinArchForName) - .toList() + ?.map(getDarwinArchForName) + ?.toList() ?? <DarwinArch>[DarwinArch.x86_64]; if (targetPlatform != TargetPlatform.darwin) { throw Exception('compile_macos_framework is only supported for darwin TargetPlatform.'); @@ -260,7 +256,7 @@ class CompileMacOSFramework extends Target { final AOTSnapshotter snapshotter = AOTSnapshotter( fileSystem: environment.fileSystem, logger: environment.logger, - xcode: globals.xcode!, + xcode: globals.xcode, artifacts: environment.artifacts, processManager: environment.processManager ); @@ -357,11 +353,10 @@ abstract class MacOSBundleFlutterAssets extends Target { @override Future<void> build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { + if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'compile_macos_framework'); } - final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final Directory frameworkRootDirectory = environment .outputDir .childDirectory('App.framework'); diff --git a/packages/flutter_tools/lib/src/build_system/targets/web.dart b/packages/flutter_tools/lib/src/build_system/targets/web.dart index 462c22febbe6f..6a74cf3df17ab 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/web.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/web.dart @@ -2,9 +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:math'; import 'package:crypto/crypto.dart'; +import 'package:meta/meta.dart'; import 'package:package_config/package_config.dart'; import '../../artifacts.dart'; @@ -15,11 +18,10 @@ import '../../cache.dart'; import '../../convert.dart'; import '../../dart/language_version.dart'; import '../../dart/package_map.dart'; -import '../../globals.dart' as globals; +import '../../globals_null_migrated.dart' as globals; import '../../project.dart'; import '../build_system.dart'; import '../depfile.dart'; -import '../exceptions.dart'; import 'assets.dart'; import 'localizations.dart'; @@ -62,7 +64,7 @@ const String kOfflineFirst = 'offline-first'; const String kNoneWorker = 'none'; /// Convert a [value] into a [ServiceWorkerStrategy]. -ServiceWorkerStrategy _serviceWorkerStrategyFromString(String? value) { +ServiceWorkerStrategy _serviceWorkerStrategyFromString(String value) { switch (value) { case kNoneWorker: return ServiceWorkerStrategy.none; @@ -95,7 +97,7 @@ class WebEntrypointTarget extends Target { @override Future<void> build(Environment environment) async { - final String? targetFile = environment.defines[kTargetFile]; + final String targetFile = environment.defines[kTargetFile]; final bool hasPlugins = environment.defines[kHasWebPlugins] == 'true'; final Uri importUri = environment.fileSystem.file(targetFile).absolute.uri; // TODO(zanderso): support configuration of this file. @@ -108,7 +110,7 @@ class WebEntrypointTarget extends Target { final LanguageVersion languageVersion = determineLanguageVersion( environment.fileSystem.file(targetFile), packageConfig[flutterProject.manifest.appName], - Cache.flutterRoot!, + Cache.flutterRoot, ); // Use the PackageConfig to find the correct package-scheme import path @@ -209,21 +211,16 @@ class Dart2JSTarget extends Target { @override Future<void> build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final bool sourceMapsEnabled = environment.defines[kSourceMapsEnabled] == 'true'; final bool nativeNullAssertions = environment.defines[kNativeNullAssertions] == 'true'; - final Artifacts artifacts = globals.artifacts!; - final String librariesSpec = (artifacts.getHostArtifact(HostArtifact.flutterWebSdk) as Directory).childFile('libraries.json').path; + final String librariesSpec = (globals.artifacts.getHostArtifact(HostArtifact.flutterWebSdk) as Directory).childFile('libraries.json').path; final List<String> sharedCommandOptions = <String>[ - artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, '--disable-dart-dev', - artifacts.getHostArtifact(HostArtifact.dart2jsSnapshot).path, + globals.artifacts.getHostArtifact(HostArtifact.dart2jsSnapshot).path, '--libraries-spec=$librariesSpec', - ...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions), + ...?decodeCommaSeparated(environment.defines, kExtraFrontEndOptions), if (nativeNullAssertions) '--native-null-assertions', if (buildMode == BuildMode.profile) @@ -250,7 +247,7 @@ class Dart2JSTarget extends Target { throw Exception(_collectOutput(kernelResult)); } - final String? dart2jsOptimization = environment.defines[kDart2jsOptimization]; + final String dart2jsOptimization = environment.defines[kDart2jsOptimization]; final File outputJSFile = environment.buildDir.childFile('main.dart.js'); final bool csp = environment.defines[kCspMode] == 'true'; @@ -269,7 +266,7 @@ class Dart2JSTarget extends Target { final File dart2jsDeps = environment.buildDir .childFile('app.dill.deps'); if (!dart2jsDeps.existsSync()) { - globals.printWarning('Warning: dart2js did not produced expected deps list at ' + globals.printError('Warning: dart2js did not produced expected deps list at ' '${dart2jsDeps.path}'); return; } @@ -387,11 +384,12 @@ class WebReleaseBundle extends Target { "navigator.serviceWorker.register('flutter_service_worker.js')", "navigator.serviceWorker.register('flutter_service_worker.js?v=$randomHash')", ); - final String? baseHref = environment.defines[kBaseHref]; - if (resultString.contains(kBaseHrefPlaceholder) && baseHref == null) { + if (resultString.contains(kBaseHrefPlaceholder) && + environment.defines[kBaseHref] == null) { resultString = resultString.replaceAll(kBaseHrefPlaceholder, '/'); - } else if (resultString.contains(kBaseHrefPlaceholder) && baseHref != null) { - resultString = resultString.replaceAll(kBaseHrefPlaceholder, baseHref); + } else if (resultString.contains(kBaseHrefPlaceholder) && + environment.defines[kBaseHref] != null) { + resultString = resultString.replaceAll(kBaseHrefPlaceholder, environment.defines[kBaseHref]); } outputFile.writeAsStringSync(resultString); continue; @@ -412,10 +410,9 @@ class WebReleaseBundle extends Target { /// These assets can be cached forever and are only invalidated when the /// Flutter SDK is upgraded to a new version. class WebBuiltInAssets extends Target { - const WebBuiltInAssets(this.fileSystem, this.cache); + const WebBuiltInAssets(this.fileSystem); final FileSystem fileSystem; - final Cache cache; @override String get name => 'web_static_assets'; @@ -434,15 +431,7 @@ class WebBuiltInAssets extends Target { @override Future<void> build(Environment environment) async { - // TODO(yjbanov): https://github.com/flutter/flutter/issues/52588 - // - // Update this when we start building CanvasKit from sources. In the - // meantime, get the Web SDK directory from cache rather than through - // Artifacts. The latter is sensitive to `--local-engine`, which changes - // the directory to point to ENGINE/src/out. However, CanvasKit is not yet - // built as part of the engine, but fetched from CIPD, and so it won't be - // found in ENGINE/src/out. - final Directory flutterWebSdk = cache.getWebSdkDirectory(); + final Directory flutterWebSdk = globals.artifacts.getHostArtifact(HostArtifact.flutterWebSdk) as Directory; final Directory canvasKitDirectory = flutterWebSdk.childDirectory('canvaskit'); for (final File file in canvasKitDirectory.listSync(recursive: true).whereType<File>()) { final String relativePath = fileSystem.path.relative(file.path, from: canvasKitDirectory.path); @@ -454,10 +443,9 @@ class WebBuiltInAssets extends Target { /// Generate a service worker for a web target. class WebServiceWorker extends Target { - const WebServiceWorker(this.fileSystem, this.cache); + const WebServiceWorker(this.fileSystem); final FileSystem fileSystem; - final Cache cache; @override String get name => 'web_service_worker'; @@ -466,7 +454,7 @@ class WebServiceWorker extends Target { List<Target> get dependencies => <Target>[ const Dart2JSTarget(), const WebReleaseBundle(), - WebBuiltInAssets(fileSystem, cache), + WebBuiltInAssets(fileSystem), ]; @override @@ -551,7 +539,7 @@ class WebServiceWorker extends Target { String generateServiceWorker( Map<String, String> resources, List<String> coreBundle, { - required ServiceWorkerStrategy serviceWorkerStrategy, + @required ServiceWorkerStrategy serviceWorkerStrategy, }) { if (serviceWorkerStrategy == ServiceWorkerStrategy.none) { return ''; diff --git a/packages/flutter_tools/lib/src/build_system/targets/windows.dart b/packages/flutter_tools/lib/src/build_system/targets/windows.dart index 4eed095b1ca09..12e4dc9a9c050 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/windows.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/windows.dart @@ -2,6 +2,10 @@ // 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:meta/meta.dart'; + import '../../artifacts.dart'; import '../../base/file_system.dart'; import '../../build_info.dart'; @@ -64,11 +68,7 @@ class UnpackWindows extends Target { @override Future<void> build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final String engineSourcePath = environment.artifacts .getArtifactPath( Artifact.windowsDesktopPath, @@ -135,11 +135,7 @@ class UnpackWindowsUwp extends Target { @override Future<void> build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final String engineSourcePath = environment.artifacts .getArtifactPath( Artifact.windowsUwpDesktopPath, @@ -213,11 +209,10 @@ abstract class BundleWindowsAssets extends Target { @override Future<void> build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { + if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'bundle_windows_assets'); } - final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); + final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final Directory outputDirectory = environment.outputDir .childDirectory('flutter_assets'); if (!outputDirectory.existsSync()) { @@ -260,7 +255,7 @@ abstract class BundleWindowsAssetsUwp extends BundleWindowsAssets { /// A wrapper for AOT compilation that copies app.so into the output directory. class WindowsAotBundle extends Target { /// Create a [WindowsAotBundle] wrapper for [aotTarget]. - const WindowsAotBundle(this.aotTarget, {required this.uwp}); + const WindowsAotBundle(this.aotTarget, {@required this.uwp}); /// The [AotElfBase] subclass that produces the app.so. final AotElfBase aotTarget; diff --git a/packages/flutter_tools/lib/src/bundle.dart b/packages/flutter_tools/lib/src/bundle.dart index 6eed94ee93a88..4fe5f055d5c4b 100644 --- a/packages/flutter_tools/lib/src/bundle.dart +++ b/packages/flutter_tools/lib/src/bundle.dart @@ -9,7 +9,7 @@ import 'base/config.dart'; import 'base/file_system.dart'; import 'build_info.dart'; import 'convert.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; String get defaultMainPath => globals.fs.path.join('lib', 'main.dart'); const String defaultManifestPath = 'pubspec.yaml'; diff --git a/packages/flutter_tools/lib/src/bundle_builder.dart b/packages/flutter_tools/lib/src/bundle_builder.dart index 2ed5e99387d5a..f437a50eb6e83 100644 --- a/packages/flutter_tools/lib/src/bundle_builder.dart +++ b/packages/flutter_tools/lib/src/bundle_builder.dart @@ -16,7 +16,7 @@ import 'build_system/targets/common.dart'; import 'bundle.dart'; import 'cache.dart'; import 'devfs.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; import 'project.dart'; @@ -70,7 +70,7 @@ class BundleBuilder { final Target target = buildInfo.mode == BuildMode.debug ? const CopyFlutterBundle() : const ReleaseCopyFlutterBundle(); - final BuildResult result = await buildSystem.build(target, environment); + final BuildResult result = await buildSystem!.build(target, environment); if (!result.success) { for (final ExceptionMeasurement measurement in result.exceptions.values) { @@ -140,7 +140,7 @@ Future<void> writeBundle( try { bundleDir.deleteSync(recursive: true); } on FileSystemException catch (err) { - loggerOverride.printWarning( + loggerOverride.printError( 'Failed to clean up asset directory ${bundleDir.path}: $err\n' 'To clean build artifacts, use the command "flutter clean".' ); diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 2f5e9edf1aa7e..7870c7807f926 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -103,20 +103,6 @@ class DevelopmentArtifact { /// /// This does not provide any artifacts by default. See [FlutterCache] for the default /// artifact set. -/// -/// ## Artifact mirrors -/// -/// Some environments cannot reach the Google Cloud Storage buckets and CIPD due -/// to regional or corporate policies. -/// -/// To enable Flutter users in these environments, the Flutter tool supports -/// custom artifact mirrors that the administrators of such environments may -/// provide. To use an artifact mirror, the user defines the -/// `FLUTTER_STORAGE_BASE_URL` environment variable that points to the mirror. -/// Flutter tool reads this variable and uses it instead of the default URLs. -/// -/// For more details on specific URLs used to download artifacts, see -/// [storageBaseUrl] and [cipdBaseUrl]. class Cache { /// [rootOverride] is configurable for testing. /// [artifacts] is configurable for testing. @@ -153,7 +139,7 @@ class Cache { platform ??= FakePlatform(environment: <String, String>{}); logger ??= BufferLogger.test(); return Cache( - rootOverride: rootOverride ?? fileSystem.directory('cache'), + rootOverride: rootOverride ??= fileSystem.directory('cache'), artifacts: artifacts ?? <ArtifactSet>[], logger: logger, fileSystem: fileSystem, @@ -178,7 +164,6 @@ class Cache { late final ArtifactUpdater _artifactUpdater = _createUpdater(); - @visibleForTesting @protected void registerArtifact(ArtifactSet artifactSet) { _artifacts.add(artifactSet); @@ -193,16 +178,11 @@ class Cache { tempStorage: getDownloadDir(), platform: _platform, httpClient: HttpClient(), - allowedBaseUrls: <String>[ - storageBaseUrl, - cipdBaseUrl, - ], ); } static const List<String> _hostsBlockedInChina = <String> [ 'storage.googleapis.com', - 'chrome-infra-packages.appspot.com', ]; // Initialized by FlutterCommandRunner on startup. @@ -340,17 +320,13 @@ class Cache { } on FileSystemException { if (!printed) { _logger.printTrace('Waiting to be able to obtain lock of Flutter binary artifacts directory: ${_lock!.path}'); - // This needs to go to stderr to avoid cluttering up stdout if a - // parent process is collecting stdout (e.g. when calling "flutter - // version --machine"). It's not really a "warning" though, so print it - // in grey. Also, make sure that it isn't counted as a warning for - // Logger.warningsAreFatal. - final bool oldWarnings = _logger.hadWarningOutput; - _logger.printWarning( + // This needs to go to stderr to avoid cluttering up stdout if a parent + // process is collecting stdout. It's not really an "error" though, + // so print it in grey. + _logger.printError( 'Waiting for another flutter command to release the startup lock...', color: TerminalColor.grey, ); - _logger.hadWarningOutput = oldWarnings; printed = true; } await Future<void>.delayed(const Duration(milliseconds: 50)); @@ -380,35 +356,6 @@ class Cache { } } - String get devToolsVersion { - if (_devToolsVersion == null) { - const String devToolsDirPath = 'dart-sdk/bin/resources/devtools'; - final Directory devToolsDir = getCacheDir(devToolsDirPath, shouldCreate: false); - if (!devToolsDir.existsSync()) { - throw Exception('Could not find directory at ${devToolsDir.path}'); - } - final String versionFilePath = '${devToolsDir.path}/version.json'; - final File versionFile = _fileSystem.file(versionFilePath); - if (!versionFile.existsSync()) { - throw Exception('Could not find file at $versionFilePath'); - } - final dynamic data = jsonDecode(versionFile.readAsStringSync()); - if (data is! Map<String, Object>) { - throw Exception("Expected object of type 'Map<String, Object>' but got one of type '${data.runtimeType}'"); - } - final dynamic version = data['version']; - if (version == null) { - throw Exception('Could not parse DevTools version from $version'); - } - if (version is! String) { - throw Exception("Could not parse DevTools version. Expected object of type 'String', but got one of type '${version.runtimeType}'"); - } - return _devToolsVersion = version; - } - return _devToolsVersion!; - } - String ? _devToolsVersion; - /// The current version of Dart used to build Flutter and run the tool. String get dartSdkVersion { if (_dartSdkVersion == null) { @@ -450,17 +397,6 @@ class Cache { } String? _engineRevision; - /// The base for URLs that store Flutter engine artifacts that are fetched - /// during the installation of the Flutter SDK. - /// - /// By default the base URL is https://storage.googleapis.com. However, if - /// `FLUTTER_STORAGE_BASE_URL` environment variable is provided, the - /// environment variable value is returned instead. - /// - /// See also: - /// - /// * [cipdBaseUrl], which determines how CIPD artifacts are fetched. - /// * [Cache] class-level dartdocs that explain how artifact mirrors work. String get storageBaseUrl { final String? overrideUrl = _platform.environment['FLUTTER_STORAGE_BASE_URL']; if (overrideUrl == null) { @@ -476,25 +412,6 @@ class Cache { return overrideUrl; } - /// The base for URLs that store Flutter engine artifacts in CIPD. - /// - /// For some platforms, such as Web and Fuchsia, CIPD artifacts are fetched - /// during the installation of the Flutter SDK, in addition to those fetched - /// from [storageBaseUrl]. - /// - /// By default the base URL is https://chrome-infra-packages.appspot.com/dl. - /// However, if `FLUTTER_STORAGE_BASE_URL` environment variable is provided, - /// then the following value is used: - /// - /// FLUTTER_STORAGE_BASE_URL/flutter_infra_release/cipd - /// - /// See also: - /// - /// * [storageBaseUrl], which determines how engine artifacts stored in the - /// Google Cloud Storage buckets are fetched. - /// * https://chromium.googlesource.com/infra/luci/luci-go/+/refs/heads/main/cipd, - /// which contains information about CIPD. - /// * [Cache] class-level dartdocs that explain how artifact mirrors work. String get cipdBaseUrl { final String? overrideUrl = _platform.environment['FLUTTER_STORAGE_BASE_URL']; if (overrideUrl == null) { @@ -545,12 +462,9 @@ class Cache { } /// Return a directory in the cache dir. For `pkg`, this will return `bin/cache/pkg`. - /// - /// When [shouldCreate] is true, the cache directory at [name] will be created - /// if it does not already exist. - Directory getCacheDir(String name, { bool shouldCreate = true }) { + Directory getCacheDir(String name) { final Directory dir = _fileSystem.directory(_fileSystem.path.join(getRoot().path, name)); - if (!dir.existsSync() && shouldCreate) { + if (!dir.existsSync()) { dir.createSync(recursive: true); _osUtils.chmod(dir, '755'); } @@ -618,7 +532,7 @@ class Cache { ErrorHandlingFileSystem.deleteIfExists(file); } } on FileSystemException catch (err) { - _logger.printWarning('Failed to delete some stamp files: $err'); + _logger.printError('Failed to delete some stamp files: $err'); } } @@ -812,7 +726,7 @@ abstract class CachedArtifact extends ArtifactSet { await updateInner(artifactUpdater, fileSystem, operatingSystemUtils); try { if (version == null) { - logger.printWarning( + logger.printError( 'No known version for the artifact name "$name". ' 'Flutter can continue, but the artifact may be re-downloaded on ' 'subsequent invocations until the problem is resolved.', @@ -821,7 +735,7 @@ abstract class CachedArtifact extends ArtifactSet { cache.setStampFor(stampName, version!); } } on FileSystemException catch (err) { - logger.printWarning( + logger.printError( 'The new artifact "$name" was downloaded, but Flutter failed to update ' 'its stamp file, receiving the error "$err". ' 'Flutter can continue, but the artifact may be re-downloaded on ' @@ -974,14 +888,12 @@ class ArtifactUpdater { required Directory tempStorage, required HttpClient httpClient, required Platform platform, - required List<String> allowedBaseUrls, }) : _operatingSystemUtils = operatingSystemUtils, _httpClient = httpClient, _logger = logger, _fileSystem = fileSystem, _tempStorage = tempStorage, - _platform = platform, - _allowedBaseUrls = allowedBaseUrls; + _platform = platform; /// The number of times the artifact updater will repeat the artifact download loop. static const int _kRetryCount = 2; @@ -993,13 +905,6 @@ class ArtifactUpdater { final HttpClient _httpClient; final Platform _platform; - /// Artifacts should only be downloaded from URLs that use one of these - /// prefixes. - /// - /// [ArtifactUpdater] will issue a warning if an attempt to download from a - /// non-compliant URL is made. - final List<String> _allowedBaseUrls; - /// Keep track of the files we've downloaded for this execution so we /// can delete them after completion. We don't delete them right after /// extraction in case [update] is interrupted, so we can restart without @@ -1052,7 +957,7 @@ class ArtifactUpdater { if (tempFile.existsSync()) { tempFile.deleteSync(); } - await _download(url, tempFile, status); + await _download(url, tempFile); if (!tempFile.existsSync()) { throw Exception('Did not find downloaded file ${tempFile.path}'); @@ -1135,26 +1040,7 @@ class ArtifactUpdater { /// /// See also: /// * https://cloud.google.com/storage/docs/xml-api/reference-headers#xgooghash - Future<void> _download(Uri url, File file, Status status) async { - final bool isAllowedUrl = _allowedBaseUrls.any((String baseUrl) => url.toString().startsWith(baseUrl)); - - // In tests make this a hard failure. - assert( - isAllowedUrl, - 'URL not allowed: $url\n' - 'Allowed URLs must be based on one of: ${_allowedBaseUrls.join(', ')}', - ); - - // In production, issue a warning but allow the download to proceed. - if (!isAllowedUrl) { - status.pause(); - _logger.printWarning( - 'Downloading an artifact that may not be reachable in some environments (e.g. firewalled environments): $url\n' - 'This should not have happened. This is likely a Flutter SDK bug. Please file an issue at https://github.com/flutter/flutter/issues/new?template=1_activation.md' - ); - status.resume(); - } - + Future<void> _download(Uri url, File file) async { final HttpClientRequest request = await _httpClient.getUrl(url); final HttpClientResponse response = await request.close(); if (response.statusCode != HttpStatus.ok) { @@ -1240,7 +1126,7 @@ class ArtifactUpdater { try { file.deleteSync(); } on FileSystemException catch (e) { - _logger.printWarning('Failed to delete "${file.path}". Please delete manually. $e'); + _logger.printError('Failed to delete "${file.path}". Please delete manually. $e'); continue; } for (Directory directory = file.parent; directory.absolute.path != _tempStorage.absolute.path; directory = directory.parent) { diff --git a/packages/flutter_tools/lib/src/commands/analyze.dart b/packages/flutter_tools/lib/src/commands/analyze.dart index fff00ced75d2f..63d3ede975e89 100644 --- a/packages/flutter_tools/lib/src/commands/analyze.dart +++ b/packages/flutter_tools/lib/src/commands/analyze.dart @@ -2,6 +2,9 @@ // 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:meta/meta.dart'; import 'package:process/process.dart'; import '../artifacts.dart'; @@ -17,12 +20,12 @@ class AnalyzeCommand extends FlutterCommand { AnalyzeCommand({ bool verboseHelp = false, this.workingDirectory, - required FileSystem fileSystem, - required Platform platform, - required Terminal terminal, - required Logger logger, - required ProcessManager processManager, - required Artifacts artifacts, + @required FileSystem fileSystem, + @required Platform platform, + @required Terminal terminal, + @required Logger logger, + @required ProcessManager processManager, + @required Artifacts artifacts, }) : _artifacts = artifacts, _fileSystem = fileSystem, _processManager = processManager, @@ -32,6 +35,7 @@ class AnalyzeCommand extends FlutterCommand { argParser.addFlag('flutter-repo', negatable: false, help: 'Include all the examples and tests from the Flutter repository.', + defaultsTo: false, hide: !verboseHelp); argParser.addFlag('current-package', help: 'Analyze the current project, if applicable.', defaultsTo: true); @@ -76,15 +80,17 @@ class AnalyzeCommand extends FlutterCommand { 'files that will be analyzed.\n' 'Ignored if "--watch" is specified.'); argParser.addFlag('fatal-infos', + negatable: true, help: 'Treat info level issues as fatal.', defaultsTo: true); argParser.addFlag('fatal-warnings', + negatable: true, help: 'Treat warning level issues as fatal.', defaultsTo: true); } /// The working directory for testing analysis using dartanalyzer. - final Directory? workingDirectory; + final Directory workingDirectory; final Artifacts _artifacts; final FileSystem _fileSystem; @@ -121,9 +127,9 @@ class AnalyzeCommand extends FlutterCommand { Future<FlutterCommandResult> runCommand() async { if (boolArg('watch')) { await AnalyzeContinuously( - argResults!, - runner!.getRepoRoots(), - runner!.getRepoPackages(), + argResults, + runner.getRepoRoots(), + runner.getRepoPackages(), fileSystem: _fileSystem, logger: _logger, platform: _platform, @@ -133,9 +139,9 @@ class AnalyzeCommand extends FlutterCommand { ).analyze(); } else { await AnalyzeOnce( - argResults!, - runner!.getRepoRoots(), - runner!.getRepoPackages(), + argResults, + runner.getRepoRoots(), + runner.getRepoPackages(), workingDirectory: workingDirectory, fileSystem: _fileSystem, logger: _logger, diff --git a/packages/flutter_tools/lib/src/commands/analyze_base.dart b/packages/flutter_tools/lib/src/commands/analyze_base.dart index dbb55c9d672ed..ef7a1c58166d1 100644 --- a/packages/flutter_tools/lib/src/commands/analyze_base.dart +++ b/packages/flutter_tools/lib/src/commands/analyze_base.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:args/args.dart'; import 'package:meta/meta.dart'; import 'package:process/process.dart'; @@ -15,19 +17,19 @@ import '../base/platform.dart'; import '../base/terminal.dart'; import '../base/utils.dart'; import '../cache.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; /// Common behavior for `flutter analyze` and `flutter analyze --watch` abstract class AnalyzeBase { AnalyzeBase(this.argResults, { - required this.repoRoots, - required this.repoPackages, - required this.fileSystem, - required this.logger, - required this.platform, - required this.processManager, - required this.terminal, - required this.artifacts, + @required this.repoRoots, + @required this.repoPackages, + @required this.fileSystem, + @required this.logger, + @required this.platform, + @required this.processManager, + @required this.terminal, + @required this.artifacts, }); /// The parsed argument results for execution. @@ -79,22 +81,16 @@ abstract class AnalyzeBase { } bool get isFlutterRepo => argResults['flutter-repo'] as bool; - String get sdkPath { - final String? dartSdk = argResults['dart-sdk'] as String?; - if (dartSdk != null) { - return dartSdk; - } - return artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path; - } + String get sdkPath => argResults['dart-sdk'] as String ?? artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path; bool get isBenchmarking => argResults['benchmark'] as bool; String get protocolTrafficLog => argResults['protocol-traffic-log'] as String; /// Generate an analysis summary for both [AnalyzeOnce], [AnalyzeContinuously]. static String generateErrorsMessage({ - required int issueCount, - int? issueDiff, - int? files, - required String seconds, + @required int issueCount, + int issueDiff, + int files, + @required String seconds, }) { final StringBuffer errorsMessage = StringBuffer(issueCount > 0 ? '$issueCount ${pluralize('issue', issueCount)} found.' @@ -122,7 +118,7 @@ class PackageDependency { // This is a map from dependency targets (lib directories) to a list // of places that ask for that target (.packages or pubspec.yaml files) Map<String, List<String>> values = <String, List<String>>{}; - String? canonicalSource; + String canonicalSource; void addCanonicalCase(String packagePath, String pubSpecYamlPath) { assert(canonicalSource == null); add(packagePath, pubSpecYamlPath); @@ -133,12 +129,11 @@ class PackageDependency { } bool get hasConflict => values.length > 1; bool get hasConflictAffectingFlutterRepo { - final String? flutterRoot = Cache.flutterRoot; - assert(flutterRoot != null && globals.fs.path.isAbsolute(flutterRoot)); + assert(globals.fs.path.isAbsolute(Cache.flutterRoot)); for (final List<String> targetSources in values.values) { for (final String source in targetSources) { assert(globals.fs.path.isAbsolute(source)); - if (globals.fs.path.isWithin(flutterRoot!, source)) { + if (globals.fs.path.isWithin(Cache.flutterRoot, source)) { return true; } } @@ -148,13 +143,12 @@ class PackageDependency { void describeConflict(StringBuffer result) { assert(hasConflict); final List<String> targets = values.keys.toList(); - targets.sort((String a, String b) => values[b]!.length.compareTo(values[a]!.length)); + targets.sort((String a, String b) => values[b].length.compareTo(values[a].length)); for (final String target in targets) { - final List<String> targetList = values[target]!; - final int count = targetList.length; + final int count = values[target].length; result.writeln(' $count ${count == 1 ? 'source wants' : 'sources want'} "$target":'); bool canonical = false; - for (final String source in targetList) { + for (final String source in values[target]) { result.writeln(' $source'); if (source == canonicalSource) { canonical = true; @@ -269,20 +263,18 @@ class PackageDependencyTracker { String generateConflictReport() { assert(hasConflicts); final StringBuffer result = StringBuffer(); - packages.forEach((String package, PackageDependency dependency) { - if (dependency.hasConflict) { - result.writeln('Package "$package" has conflicts:'); - dependency.describeConflict(result); - } - }); + for (final String package in packages.keys.where((String package) => packages[package].hasConflict)) { + result.writeln('Package "$package" has conflicts:'); + packages[package].describeConflict(result); + } return result.toString(); } Map<String, String> asPackageMap() { final Map<String, String> result = <String, String>{}; - packages.forEach((String package, PackageDependency dependency) { - result[package] = dependency.target; - }); + for (final String package in packages.keys) { + result[package] = packages[package].target; + } return result; } } diff --git a/packages/flutter_tools/lib/src/commands/analyze_continuously.dart b/packages/flutter_tools/lib/src/commands/analyze_continuously.dart index 705ed337932df..05e4d6512cd58 100644 --- a/packages/flutter_tools/lib/src/commands/analyze_continuously.dart +++ b/packages/flutter_tools/lib/src/commands/analyze_continuously.dart @@ -2,7 +2,10 @@ // 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/args.dart'; +import 'package:meta/meta.dart'; import 'package:process/process.dart'; import '../artifacts.dart'; @@ -20,12 +23,12 @@ class AnalyzeContinuously extends AnalyzeBase { ArgResults argResults, List<String> repoRoots, List<Directory> repoPackages, { - required FileSystem fileSystem, - required Logger logger, - required Terminal terminal, - required Platform platform, - required ProcessManager processManager, - required Artifacts artifacts, + @required FileSystem fileSystem, + @required Logger logger, + @required Terminal terminal, + @required Platform platform, + @required ProcessManager processManager, + @required Artifacts artifacts, }) : super( argResults, repoPackages: repoPackages, @@ -38,13 +41,13 @@ class AnalyzeContinuously extends AnalyzeBase { artifacts: artifacts, ); - String? analysisTarget; + String analysisTarget; bool firstAnalysis = true; Set<String> analyzedPaths = <String>{}; Map<String, List<AnalysisError>> analysisErrors = <String, List<AnalysisError>>{}; - final Stopwatch analysisTimer = Stopwatch(); + Stopwatch analysisTimer; int lastErrorCount = 0; - Status? analysisStatus; + Status analysisStatus; @override Future<void> analyze() async { @@ -80,7 +83,7 @@ class AnalyzeContinuously extends AnalyzeBase { server.onErrors.listen(_handleAnalysisErrors); await server.start(); - final int? exitCode = await server.onExit; + final int exitCode = await server.onExit; final String message = 'Analysis server exited with code $exitCode.'; if (exitCode != 0) { @@ -101,7 +104,7 @@ class AnalyzeContinuously extends AnalyzeBase { } analysisStatus = logger.startProgress('Analyzing $analysisTarget...'); analyzedPaths.clear(); - analysisTimer.start(); + analysisTimer = Stopwatch()..start(); } else { analysisStatus?.stop(); analysisStatus = null; @@ -110,29 +113,27 @@ class AnalyzeContinuously extends AnalyzeBase { logger.printStatus(terminal.clearScreen(), newline: false); // Remove errors for deleted files, sort, and print errors. - final List<AnalysisError> sortedErrors = <AnalysisError>[]; - final List<String> pathsToRemove = <String>[]; - analysisErrors.forEach((String path, List<AnalysisError> errors) { + final List<AnalysisError> errors = <AnalysisError>[]; + for (final String path in analysisErrors.keys.toList()) { if (fileSystem.isFileSync(path)) { - sortedErrors.addAll(errors); + errors.addAll(analysisErrors[path]); } else { - pathsToRemove.add(path); + analysisErrors.remove(path); } - }); - analysisErrors.removeWhere((String path, _) => pathsToRemove.contains(path)); + } - sortedErrors.sort(); + errors.sort(); - for (final AnalysisError error in sortedErrors) { + for (final AnalysisError error in errors) { logger.printStatus(error.toString()); if (error.code != null) { logger.printTrace('error code: ${error.code}'); } } - dumpErrors(sortedErrors.map<String>((AnalysisError error) => error.toLegacyString())); + dumpErrors(errors.map<String>((AnalysisError error) => error.toLegacyString())); - final int issueCount = sortedErrors.length; + final int issueCount = errors.length; final int issueDiff = issueCount - lastErrorCount; lastErrorCount = issueCount; final String seconds = (analysisTimer.elapsedMilliseconds / 1000.0).toStringAsFixed(2); diff --git a/packages/flutter_tools/lib/src/commands/analyze_once.dart b/packages/flutter_tools/lib/src/commands/analyze_once.dart index f69f4c65ad73b..0101f0190b329 100644 --- a/packages/flutter_tools/lib/src/commands/analyze_once.dart +++ b/packages/flutter_tools/lib/src/commands/analyze_once.dart @@ -2,9 +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:async'; import 'package:args/args.dart'; +import 'package:meta/meta.dart'; import 'package:process/process.dart'; import '../artifacts.dart'; @@ -21,12 +24,12 @@ class AnalyzeOnce extends AnalyzeBase { ArgResults argResults, List<String> repoRoots, List<Directory> repoPackages, { - required FileSystem fileSystem, - required Logger logger, - required Platform platform, - required ProcessManager processManager, - required Terminal terminal, - required Artifacts artifacts, + @required FileSystem fileSystem, + @required Logger logger, + @required Platform platform, + @required ProcessManager processManager, + @required Terminal terminal, + @required Artifacts artifacts, this.workingDirectory, }) : super( argResults, @@ -41,7 +44,7 @@ class AnalyzeOnce extends AnalyzeBase { ); /// The working directory for testing analysis using dartanalyzer. - final Directory? workingDirectory; + final Directory workingDirectory; @override Future<void> analyze() async { @@ -95,10 +98,10 @@ class AnalyzeOnce extends AnalyzeBase { protocolTrafficLog: protocolTrafficLog, ); - Stopwatch? timer; - Status? progress; + Stopwatch timer; + Status progress; try { - StreamSubscription<bool>? subscription; + StreamSubscription<bool> subscription; void handleAnalysisStatus(bool isAnalyzing) { if (!isAnalyzing) { @@ -120,7 +123,7 @@ class AnalyzeOnce extends AnalyzeBase { await server.start(); // Completing the future in the callback can't fail. - unawaited(server.onExit.then<void>((int? exitCode) { + unawaited(server.onExit.then<void>((int exitCode) { if (!analysisCompleter.isCompleted) { analysisCompleter.completeError( // Include the last 20 lines of server output in exception message @@ -136,7 +139,7 @@ class AnalyzeOnce extends AnalyzeBase { final String message = directories.length > 1 ? '${directories.length} ${directories.length == 1 ? 'directory' : 'directories'}' : fileSystem.path.basename(directories.first); - progress = argResults['preamble'] == true + progress = argResults['preamble'] as bool ? logger.startProgress( 'Analyzing $message...', ) diff --git a/packages/flutter_tools/lib/src/commands/assemble.dart b/packages/flutter_tools/lib/src/commands/assemble.dart index 928181d31f65f..9c06a44933eec 100644 --- a/packages/flutter_tools/lib/src/commands/assemble.dart +++ b/packages/flutter_tools/lib/src/commands/assemble.dart @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:args/args.dart'; +// @dart = 2.8 + import 'package:meta/meta.dart'; -import '../artifacts.dart'; import '../base/common.dart'; import '../base/file_system.dart'; import '../build_info.dart'; @@ -22,7 +22,7 @@ import '../build_system/targets/web.dart'; import '../build_system/targets/windows.dart'; import '../cache.dart'; import '../convert.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import '../runner/flutter_command.dart'; @@ -49,7 +49,7 @@ List<Target> _kDefaultTargets = <Target>[ const ReleaseBundleLinuxAssets(TargetPlatform.linux_x64), const ReleaseBundleLinuxAssets(TargetPlatform.linux_arm64), // Web targets - WebServiceWorker(globals.fs, globals.cache), + WebServiceWorker(globals.fs), const ReleaseAndroidApplication(), // This is a one-off rule for bundle and aot compat. const CopyFlutterBundle(), @@ -88,7 +88,7 @@ List<Target> _kDefaultTargets = <Target>[ /// Assemble provides a low level API to interact with the flutter tool build /// system. class AssembleCommand extends FlutterCommand { - AssembleCommand({ bool verboseHelp = false, required BuildSystem buildSystem }) + AssembleCommand({ bool verboseHelp = false, @required BuildSystem buildSystem }) : _buildSystem = buildSystem { argParser.addMultiOption( 'define', @@ -161,13 +161,13 @@ class AssembleCommand extends FlutterCommand { @override Future<Set<DevelopmentArtifact>> get requiredArtifacts async { - final String? platform = environment.defines[kTargetPlatform]; + final String platform = environment.defines[kTargetPlatform]; if (platform == null) { return super.requiredArtifacts; } final TargetPlatform targetPlatform = getTargetPlatformForName(platform); - final DevelopmentArtifact? artifact = artifactFromTargetPlatform(targetPlatform); + final DevelopmentArtifact artifact = artifactFromTargetPlatform(targetPlatform); if (artifact != null) { return <DevelopmentArtifact>{artifact}; } @@ -176,19 +176,18 @@ class AssembleCommand extends FlutterCommand { /// The target(s) we are building. List<Target> createTargets() { - final ArgResults argumentResults = argResults!; - if (argumentResults.rest.isEmpty) { + if (argResults.rest.isEmpty) { throwToolExit('missing target name for flutter assemble.'); } - final String name = argumentResults.rest.first; + final String name = argResults.rest.first; final Map<String, Target> targetMap = <String, Target>{ for (final Target target in _kDefaultTargets) target.name: target }; final List<Target> results = <Target>[ - for (final String targetName in argumentResults.rest) + for (final String targetName in argResults.rest) if (targetMap.containsKey(targetName)) - targetMap[targetName]! + targetMap[targetName] ]; if (results.isEmpty) { throwToolExit('No target named "$name" defined.'); @@ -197,7 +196,7 @@ class AssembleCommand extends FlutterCommand { } bool isDeferredComponentsTargets() { - for (final String targetName in argResults!.rest) { + for (final String targetName in argResults.rest) { if (deferredComponentsTargets.contains(targetName)) { return true; } @@ -206,7 +205,7 @@ class AssembleCommand extends FlutterCommand { } bool isDebug() { - for (final String targetName in argResults!.rest) { + for (final String targetName in argResults.rest) { if (targetName.contains('debug')) { return true; } @@ -214,12 +213,13 @@ class AssembleCommand extends FlutterCommand { return false; } - late final Environment environment = createEnvironment(); + Environment get environment => _environment ??= createEnvironment(); + Environment _environment; /// The environmental configuration for a build invocation. Environment createEnvironment() { final FlutterProject flutterProject = FlutterProject.current(); - String? output = stringArg('output'); + String output = stringArg('output'); if (output == null) { throwToolExit('--output directory is required for assemble.'); } @@ -227,7 +227,6 @@ class AssembleCommand extends FlutterCommand { if (globals.fs.path.isRelative(output)) { output = globals.fs.path.join(flutterProject.directory.path, output); } - final Artifacts artifacts = globals.artifacts!; final Environment result = Environment( outputDir: globals.fs.directory(output), buildDir: flutterProject.directory @@ -238,12 +237,12 @@ class AssembleCommand extends FlutterCommand { inputs: _parseDefines(stringsArg('input')), cacheDir: globals.cache.getRoot(), flutterRootDir: globals.fs.directory(Cache.flutterRoot), - artifacts: artifacts, + artifacts: globals.artifacts, fileSystem: globals.fs, logger: globals.logger, processManager: globals.processManager, platform: globals.platform, - engineVersion: artifacts.isLocalEngine + engineVersion: globals.artifacts.isLocalEngine ? null : globals.flutterVersion.engineRevision, generateDartPluginRegistry: true, @@ -262,19 +261,18 @@ class AssembleCommand extends FlutterCommand { final String value = chunk.substring(indexEquals + 1); results[key] = value; } - final ArgResults argumentResults = argResults!; - if (argumentResults.wasParsed(FlutterOptions.kExtraGenSnapshotOptions)) { - results[kExtraGenSnapshotOptions] = (argumentResults[FlutterOptions.kExtraGenSnapshotOptions] as List<String>).join(','); + if (argResults.wasParsed(FlutterOptions.kExtraGenSnapshotOptions)) { + results[kExtraGenSnapshotOptions] = (argResults[FlutterOptions.kExtraGenSnapshotOptions] as List<String>).join(','); } - if (argumentResults.wasParsed(FlutterOptions.kDartDefinesOption)) { - results[kDartDefines] = (argumentResults[FlutterOptions.kDartDefinesOption] as List<String>).join(','); + if (argResults.wasParsed(FlutterOptions.kDartDefinesOption)) { + results[kDartDefines] = (argResults[FlutterOptions.kDartDefinesOption] as List<String>).join(','); } results[kDeferredComponents] = 'false'; if (FlutterProject.current().manifest.deferredComponents != null && isDeferredComponentsTargets() && !isDebug()) { results[kDeferredComponents] = 'true'; } - if (argumentResults.wasParsed(FlutterOptions.kExtraFrontEndOptions)) { - results[kExtraFrontEndOptions] = (argumentResults[FlutterOptions.kExtraFrontEndOptions] as List<String>).join(','); + if (argResults.wasParsed(FlutterOptions.kExtraFrontEndOptions)) { + results[kExtraFrontEndOptions] = (argResults[FlutterOptions.kExtraFrontEndOptions] as List<String>).join(','); } return results; } @@ -291,7 +289,7 @@ class AssembleCommand extends FlutterCommand { nonDeferredTargets.add(target); } } - Target? target; + Target target; List<String> decodedDefines; try { decodedDefines = decodeDartDefines(environment.defines, kDartDefines); @@ -316,13 +314,12 @@ class AssembleCommand extends FlutterCommand { } else if (targets.isNotEmpty) { target = targets.single; } - final ArgResults argumentResults = argResults!; final BuildResult result = await _buildSystem.build( - target!, + target, environment, buildSystemConfig: BuildSystemConfig( - resourcePoolSize: argumentResults.wasParsed('resource-pool-size') - ? int.tryParse(stringArg('resource-pool-size')!) + resourcePoolSize: argResults.wasParsed('resource-pool-size') + ? int.tryParse(stringArg('resource-pool-size')) : null, ), ); @@ -338,17 +335,17 @@ class AssembleCommand extends FlutterCommand { } globals.printTrace('build succeeded.'); - if (argumentResults.wasParsed('build-inputs')) { - writeListIfChanged(result.inputFiles, stringArg('build-inputs')!); + if (argResults.wasParsed('build-inputs')) { + writeListIfChanged(result.inputFiles, stringArg('build-inputs')); } - if (argumentResults.wasParsed('build-outputs')) { - writeListIfChanged(result.outputFiles, stringArg('build-outputs')!); + if (argResults.wasParsed('build-outputs')) { + writeListIfChanged(result.outputFiles, stringArg('build-outputs')); } - if (argumentResults.wasParsed('performance-measurement-file')) { - final File outFile = globals.fs.file(argumentResults['performance-measurement-file']); + if (argResults.wasParsed('performance-measurement-file')) { + final File outFile = globals.fs.file(argResults['performance-measurement-file']); writePerformanceData(result.performance.values, outFile); } - if (argumentResults.wasParsed('depfile')) { + if (argResults.wasParsed('depfile')) { final File depfileFile = globals.fs.file(stringArg('depfile')); final Depfile depfile = Depfile(result.inputFiles, result.outputFiles); final DepfileService depfileService = DepfileService( diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index f93d73c6a1042..c9618d6be300e 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -18,11 +18,10 @@ import '../base/io.dart'; import '../build_info.dart'; import '../commands/daemon.dart'; import '../compile.dart'; -import '../daemon.dart'; import '../device.dart'; import '../device_port_forwarder.dart'; import '../fuchsia/fuchsia_device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../ios/devices.dart'; import '../ios/simulators.dart'; import '../macos/macos_ipad_device.dart'; @@ -236,10 +235,8 @@ known, it can be explicitly provided to attach via the command-line, e.g. final Daemon daemon = boolArg('machine') ? Daemon( - DaemonConnection( - daemonStreams: StdioDaemonStreams(globals.stdio), - logger: globals.logger, - ), + stdinCommandStream, + stdoutCommandResponse, notifyingLogger: (globals.logger is NotifyingLogger) ? globals.logger as NotifyingLogger : NotifyingLogger(verbose: globals.logger.isVerbose, parent: globals.logger), diff --git a/packages/flutter_tools/lib/src/commands/build.dart b/packages/flutter_tools/lib/src/commands/build.dart index 5cfaa11c5dc97..2fc4b73b3ee03 100644 --- a/packages/flutter_tools/lib/src/commands/build.dart +++ b/packages/flutter_tools/lib/src/commands/build.dart @@ -2,13 +2,15 @@ // 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:meta/meta.dart'; import '../build_info.dart'; import '../commands/build_linux.dart'; import '../commands/build_macos.dart'; import '../commands/build_windows.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; import 'build_aar.dart'; import 'build_apk.dart'; @@ -59,13 +61,12 @@ class BuildCommand extends FlutterCommand { String get category => FlutterCommandCategory.project; @override - Future<FlutterCommandResult> runCommand() async => FlutterCommandResult.fail(); + Future<FlutterCommandResult> runCommand() async => null; } abstract class BuildSubCommand extends FlutterCommand { - BuildSubCommand({required bool verboseHelp}) { + BuildSubCommand() { requiresPubspecYaml(); - usesFatalWarningsOption(verboseHelp: verboseHelp); } @override diff --git a/packages/flutter_tools/lib/src/commands/build_aar.dart b/packages/flutter_tools/lib/src/commands/build_aar.dart index d4f8367237c3d..4a3d2776f5a20 100644 --- a/packages/flutter_tools/lib/src/commands/build_aar.dart +++ b/packages/flutter_tools/lib/src/commands/build_aar.dart @@ -2,6 +2,9 @@ // 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:meta/meta.dart'; + import '../android/android_builder.dart'; import '../android/gradle_utils.dart'; import '../base/common.dart'; @@ -10,14 +13,14 @@ import '../base/file_system.dart'; import '../base/os.dart'; import '../build_info.dart'; import '../cache.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import '../runner/flutter_command.dart' show FlutterCommandResult; import 'build.dart'; class BuildAarCommand extends BuildSubCommand { - BuildAarCommand({ required bool verboseHelp }) : super(verboseHelp: verboseHelp) { + BuildAarCommand({ @required bool verboseHelp }) { argParser ..addFlag( 'debug', @@ -41,7 +44,6 @@ class BuildAarCommand extends BuildSubCommand { addSplitDebugInfoOption(); addDartObfuscationOption(); usesDartDefineOption(); - usesExtraDartFlagOptions(verboseHelp: verboseHelp); usesTrackWidgetCreation(verboseHelp: false); addNullSafetyModeOptions(hide: !verboseHelp); addEnableExperimentation(hide: !verboseHelp); @@ -49,6 +51,7 @@ class BuildAarCommand extends BuildSubCommand { argParser ..addMultiOption( 'target-platform', + splitCommas: true, defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'], allowed: <String>['android-arm', 'android-arm64', 'android-x86', 'android-x64'], help: 'The target platform for which the project is compiled.', @@ -112,11 +115,10 @@ class BuildAarCommand extends BuildSubCommand { final Iterable<AndroidArch> targetArchitectures = stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName); - final String? buildNumberArg = stringArg('build-number'); final String buildNumber = argParser.options.containsKey('build-number') - && buildNumberArg != null - && buildNumberArg.isNotEmpty - ? buildNumberArg + && stringArg('build-number') != null + && stringArg('build-number').isNotEmpty + ? stringArg('build-number') : '1.0'; final File targetFile = globals.fs.file(globals.fs.path.join('lib', 'main.dart')); @@ -138,7 +140,7 @@ class BuildAarCommand extends BuildSubCommand { } displayNullSafetyMode(androidBuildInfo.first.buildInfo); - await androidBuilder?.buildAar( + await androidBuilder.buildAar( project: _getProject(), target: targetFile.path, androidBuildInfo: androidBuildInfo, @@ -151,10 +153,9 @@ class BuildAarCommand extends BuildSubCommand { /// Returns the [FlutterProject] which is determined from the remaining command-line /// argument if any or the current working directory. FlutterProject _getProject() { - final List<String> remainingArguments = argResults!.rest; - if (remainingArguments.isEmpty) { + if (argResults.rest.isEmpty) { return FlutterProject.current(); } - return FlutterProject.fromDirectory(globals.fs.directory(findProjectRoot(globals.fs, remainingArguments.first))); + return FlutterProject.fromDirectory(globals.fs.directory(findProjectRoot(globals.fs, argResults.rest.first))); } } diff --git a/packages/flutter_tools/lib/src/commands/build_apk.dart b/packages/flutter_tools/lib/src/commands/build_apk.dart index ac48a579a58c8..63caab55c53b0 100644 --- a/packages/flutter_tools/lib/src/commands/build_apk.dart +++ b/packages/flutter_tools/lib/src/commands/build_apk.dart @@ -2,19 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../android/android_builder.dart'; import '../android/build_validation.dart'; import '../android/gradle_utils.dart'; import '../build_info.dart'; import '../cache.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import '../runner/flutter_command.dart' show FlutterCommandResult; import 'build.dart'; class BuildApkCommand extends BuildSubCommand { - BuildApkCommand({bool verboseHelp = false}) : super(verboseHelp: verboseHelp) { + BuildApkCommand({bool verboseHelp = false}) { addTreeShakeIconsFlag(); usesTargetOption(); addBuildModeFlags(verboseHelp: verboseHelp); @@ -34,7 +36,6 @@ class BuildApkCommand extends BuildSubCommand { usesAnalyzeSizeFlag(); addAndroidSpecificBuildOptions(hide: !verboseHelp); addMultidexOption(); - addIgnoreDeprecationOption(); argParser ..addFlag('split-per-abi', negatable: false, @@ -42,6 +43,7 @@ class BuildApkCommand extends BuildSubCommand { 'To learn more, see: https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split', ) ..addMultiOption('target-platform', + splitCommas: true, defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'], allowed: <String>['android-arm', 'android-arm64', 'android-x86', 'android-x64'], help: 'The target platform for which the app is compiled.', @@ -52,9 +54,6 @@ class BuildApkCommand extends BuildSubCommand { @override final String name = 'apk'; - @override - DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : DeprecationBehavior.exit; - @override Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{ DevelopmentArtifact.androidGenSnapshot, @@ -106,7 +105,7 @@ class BuildApkCommand extends BuildSubCommand { validateBuild(androidBuildInfo); displayNullSafetyMode(androidBuildInfo.buildInfo); globals.terminal.usesTerminalUi = true; - await androidBuilder?.buildApk( + await androidBuilder.buildApk( project: FlutterProject.current(), target: targetFile, androidBuildInfo: androidBuildInfo, diff --git a/packages/flutter_tools/lib/src/commands/build_appbundle.dart b/packages/flutter_tools/lib/src/commands/build_appbundle.dart index 22dc06140f151..7d9a2821cc5c3 100644 --- a/packages/flutter_tools/lib/src/commands/build_appbundle.dart +++ b/packages/flutter_tools/lib/src/commands/build_appbundle.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../android/android_builder.dart'; import '../android/build_validation.dart'; import '../android/deferred_components_prebuild_validator.dart'; @@ -10,16 +12,14 @@ import '../base/deferred_component.dart'; import '../base/file_system.dart'; import '../build_info.dart'; import '../cache.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import '../runner/flutter_command.dart' show FlutterCommandResult; import 'build.dart'; class BuildAppBundleCommand extends BuildSubCommand { - BuildAppBundleCommand({ - bool verboseHelp = false, - }) : super(verboseHelp: verboseHelp) { + BuildAppBundleCommand({bool verboseHelp = false}) { addTreeShakeIconsFlag(); usesTargetOption(); addBuildModeFlags(verboseHelp: verboseHelp); @@ -40,13 +40,14 @@ class BuildAppBundleCommand extends BuildSubCommand { usesAnalyzeSizeFlag(); addAndroidSpecificBuildOptions(hide: !verboseHelp); addMultidexOption(); - addIgnoreDeprecationOption(); argParser.addMultiOption('target-platform', + splitCommas: true, defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'], allowed: <String>['android-arm', 'android-arm64', 'android-x64'], help: 'The target platform for which the app is compiled.', ); argParser.addFlag('deferred-components', + negatable: true, defaultsTo: true, help: 'Setting to false disables building with deferred components. All deferred code ' 'will be compiled into the base app, and assets act as if they were defined under' @@ -54,6 +55,7 @@ class BuildAppBundleCommand extends BuildSubCommand { 'non-deferred components apps.', ); argParser.addFlag('validate-deferred-components', + negatable: true, defaultsTo: true, help: 'When enabled, deferred component apps will fail to build if setup problems are ' 'detected that would prevent deferred components from functioning properly. The ' @@ -68,9 +70,6 @@ class BuildAppBundleCommand extends BuildSubCommand { @override final String name = 'appbundle'; - @override - DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : DeprecationBehavior.exit; - @override Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{ DevelopmentArtifact.androidGenSnapshot, @@ -116,8 +115,7 @@ class BuildAppBundleCommand extends BuildSubCommand { ); // Do all setup verification that doesn't involve loading units. Checks that // require generated loading units are done after gen_snapshot in assemble. - final List<DeferredComponent>? deferredComponents = FlutterProject.current().manifest.deferredComponents; - if (deferredComponents != null && boolArg('deferred-components') && boolArg('validate-deferred-components') && !boolArg('debug')) { + if (FlutterProject.current().manifest.deferredComponents != null && boolArg('deferred-components') && boolArg('validate-deferred-components') && !boolArg('debug')) { final DeferredComponentsPrebuildValidator validator = DeferredComponentsPrebuildValidator( FlutterProject.current().directory, globals.logger, @@ -125,14 +123,14 @@ class BuildAppBundleCommand extends BuildSubCommand { title: 'Deferred components prebuild validation', ); validator.clearOutputDir(); - await validator.checkAndroidDynamicFeature(deferredComponents); - validator.checkAndroidResourcesStrings(deferredComponents); + await validator.checkAndroidDynamicFeature(FlutterProject.current().manifest.deferredComponents); + validator.checkAndroidResourcesStrings(FlutterProject.current().manifest.deferredComponents); validator.handleResults(); // Delete intermediates libs dir for components to resolve mismatching // abis supported by base and dynamic feature modules. - for (final DeferredComponent component in deferredComponents) { + for (final DeferredComponent component in FlutterProject.current().manifest.deferredComponents) { final Directory deferredLibsIntermediate = FlutterProject.current().directory .childDirectory('build') .childDirectory(component.name) @@ -149,7 +147,7 @@ class BuildAppBundleCommand extends BuildSubCommand { validateBuild(androidBuildInfo); displayNullSafetyMode(androidBuildInfo.buildInfo); globals.terminal.usesTerminalUi = true; - await androidBuilder?.buildAab( + await androidBuilder.buildAab( project: FlutterProject.current(), target: targetFile, androidBuildInfo: androidBuildInfo, diff --git a/packages/flutter_tools/lib/src/commands/build_bundle.dart b/packages/flutter_tools/lib/src/commands/build_bundle.dart index f7f90453edc00..3b48eecac96ae 100644 --- a/packages/flutter_tools/lib/src/commands/build_bundle.dart +++ b/packages/flutter_tools/lib/src/commands/build_bundle.dart @@ -2,22 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../base/common.dart'; import '../build_info.dart'; import '../bundle.dart'; import '../bundle_builder.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import '../runner/flutter_command.dart'; import 'build.dart'; class BuildBundleCommand extends BuildSubCommand { - BuildBundleCommand({ - bool verboseHelp = false, - BundleBuilder? bundleBuilder, - }) : _bundleBuilder = bundleBuilder ?? BundleBuilder(), super(verboseHelp: verboseHelp) { + BuildBundleCommand({bool verboseHelp = false, this.bundleBuilder}) { usesTargetOption(); usesFilesystemOptions(hide: !verboseHelp); usesBuildNumberOption(); @@ -52,14 +51,18 @@ class BuildBundleCommand extends BuildSubCommand { ) ..addFlag( 'tree-shake-icons', + negatable: true, + defaultsTo: false, hide: !verboseHelp, help: '(deprecated) Icon font tree shaking is not supported by this command.', ); usesPubOption(); usesTrackWidgetCreation(verboseHelp: verboseHelp); + + bundleBuilder ??= BundleBuilder(); } - final BundleBuilder _bundleBuilder; + BundleBuilder bundleBuilder; @override final String name = 'bundle'; @@ -87,7 +90,7 @@ class BuildBundleCommand extends BuildSubCommand { @override Future<void> validateCommand() async { - if (boolArg('tree-shake-icons')) { + if (argResults['tree-shake-icons'] as bool) { throwToolExit('The "--tree-shake-icons" flag is deprecated for "build bundle" and will be removed in a future version of Flutter.'); } return super.validateCommand(); @@ -95,7 +98,7 @@ class BuildBundleCommand extends BuildSubCommand { @override Future<FlutterCommandResult> runCommand() async { - final String targetPlatform = stringArg('target-platform')!; + final String targetPlatform = stringArg('target-platform'); final TargetPlatform platform = getTargetPlatformForName(targetPlatform); if (platform == null) { throwToolExit('Unknown platform: $targetPlatform'); @@ -135,7 +138,7 @@ class BuildBundleCommand extends BuildSubCommand { final BuildInfo buildInfo = await getBuildInfo(); displayNullSafetyMode(buildInfo); - await _bundleBuilder.build( + await bundleBuilder.build( platform: platform, buildInfo: buildInfo, mainPath: targetFile, diff --git a/packages/flutter_tools/lib/src/commands/build_fuchsia.dart b/packages/flutter_tools/lib/src/commands/build_fuchsia.dart index 5f751036abf05..cd0b67baacebc 100644 --- a/packages/flutter_tools/lib/src/commands/build_fuchsia.dart +++ b/packages/flutter_tools/lib/src/commands/build_fuchsia.dart @@ -2,22 +2,24 @@ // 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:meta/meta.dart'; + import '../base/common.dart'; import '../build_info.dart'; import '../cache.dart'; import '../features.dart'; import '../fuchsia/fuchsia_build.dart'; import '../fuchsia/fuchsia_pm.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../runner/flutter_command.dart' show FlutterCommandResult; import 'build.dart'; /// A command to build a Fuchsia target. class BuildFuchsiaCommand extends BuildSubCommand { - BuildFuchsiaCommand({ - required bool verboseHelp, - }) : super(verboseHelp: verboseHelp) { + BuildFuchsiaCommand({ @required bool verboseHelp }) { addTreeShakeIconsFlag(); usesTargetOption(); usesDartDefineOption(); @@ -79,9 +81,9 @@ class BuildFuchsiaCommand extends BuildSubCommand { await buildFuchsia( fuchsiaProject: flutterProject.fuchsia, target: targetFile, - targetPlatform: getTargetPlatformForName(stringArg('target-platform')!), + targetPlatform: getTargetPlatformForName(stringArg('target-platform')), buildInfo: buildInfo, - runnerPackageSource: stringArg('runner-source')!, + runnerPackageSource: stringArg('runner-source'), ); return FlutterCommandResult.success(); } diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart index 8047bca14217d..8402eb17d39f8 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios.dart @@ -2,7 +2,10 @@ // 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:meta/meta.dart'; import '../base/analyze_size.dart'; import '../base/common.dart'; @@ -11,7 +14,7 @@ import '../base/process.dart'; import '../base/utils.dart'; import '../build_info.dart'; import '../convert.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../ios/application_package.dart'; import '../ios/mac.dart'; import '../runner/flutter_command.dart'; @@ -20,7 +23,7 @@ import 'build.dart'; /// Builds an .app for an iOS app to be used for local testing on an iOS device /// or simulator. Can only be run on a macOS host. class BuildIOSCommand extends _BuildIOSSubCommand { - BuildIOSCommand({ required bool verboseHelp }) : super(verboseHelp: verboseHelp) { + BuildIOSCommand({ @required bool verboseHelp }) : super(verboseHelp: verboseHelp) { argParser ..addFlag('config-only', help: 'Update the project configuration without performing a build. ' @@ -64,7 +67,7 @@ class BuildIOSCommand extends _BuildIOSSubCommand { /// /// Can only be run on a macOS host. class BuildIOSArchiveCommand extends _BuildIOSSubCommand { - BuildIOSArchiveCommand({required bool verboseHelp}) + BuildIOSArchiveCommand({@required bool verboseHelp}) : super(verboseHelp: verboseHelp) { argParser.addOption( 'export-options-plist', @@ -96,7 +99,7 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { @override final bool shouldCodesign = true; - String? get exportOptionsPlist => stringArg('export-options-plist'); + String get exportOptionsPlist => stringArg('export-options-plist'); @override Directory _outputAppDirectory(String xcodeResultOutput) => globals.fs @@ -106,42 +109,41 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { @override Future<FlutterCommandResult> runCommand() async { - final String? exportOptions = exportOptionsPlist; - if (exportOptions != null) { - final FileSystemEntityType type = globals.fs.typeSync(exportOptions); + if (exportOptionsPlist != null) { + final FileSystemEntityType type = globals.fs.typeSync(exportOptionsPlist); if (type == FileSystemEntityType.notFound) { throwToolExit( - '"$exportOptions" property list does not exist.'); + '"$exportOptionsPlist" property list does not exist.'); } else if (type != FileSystemEntityType.file) { throwToolExit( - '"$exportOptions" is not a file. See "xcodebuild -h" for available keys.'); + '"$exportOptionsPlist" is not a file. See "xcodebuild -h" for available keys.'); } } final FlutterCommandResult xcarchiveResult = await super.runCommand(); final BuildInfo buildInfo = await getBuildInfo(); displayNullSafetyMode(buildInfo); - if (exportOptions == null) { + if (exportOptionsPlist == null) { return xcarchiveResult; } // xcarchive failed or not at expected location. if (xcarchiveResult.exitStatus != ExitStatus.success) { - globals.printStatus('Skipping IPA'); + globals.logger.printStatus('Skipping IPA'); return xcarchiveResult; } // Build IPA from generated xcarchive. - final BuildableIOSApp app = await buildableIOSApp; - Status? status; - RunResult? result; + final BuildableIOSApp app = await buildableIOSApp(buildInfo); + Status status; + RunResult result; final String outputPath = globals.fs.path.absolute(app.ipaOutputPath); try { status = globals.logger.startProgress('Building IPA...'); result = await globals.processUtils.run( <String>[ - ...globals.xcode!.xcrunCommand(), + ...globals.xcode.xcrunCommand(), 'xcodebuild', '-exportArchive', if (shouldCodesign) ...<String>[ @@ -153,11 +155,11 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { '-exportPath', outputPath, '-exportOptionsPlist', - globals.fs.path.absolute(exportOptions), + globals.fs.path.absolute(exportOptionsPlist), ], ); } finally { - status?.stop(); + status.stop(); } if (result.exitCode != 0) { @@ -174,16 +176,14 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { throwToolExit('Encountered error while building IPA:\n$errorMessage'); } - globals.printStatus('Built IPA to $outputPath.'); + globals.logger.printStatus('Built IPA to $outputPath.'); return FlutterCommandResult.success(); } } abstract class _BuildIOSSubCommand extends BuildSubCommand { - _BuildIOSSubCommand({ - required bool verboseHelp - }) : super(verboseHelp: verboseHelp) { + _BuildIOSSubCommand({ @required bool verboseHelp }) { addTreeShakeIconsFlag(); addSplitDebugInfoOption(); addBuildModeFlags(verboseHelp: verboseHelp); @@ -212,19 +212,15 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand { bool get configOnly; bool get shouldCodesign; - late final Future<BuildInfo> cachedBuildInfo = getBuildInfo(); - - late final Future<BuildableIOSApp> buildableIOSApp = () async { - final BuildableIOSApp? app = await applicationPackages?.getPackageForPlatform( + Future<BuildableIOSApp> buildableIOSApp(BuildInfo buildInfo) async { + _buildableIOSApp ??= await applicationPackages.getPackageForPlatform( TargetPlatform.ios, - buildInfo: await cachedBuildInfo, - ) as BuildableIOSApp?; + buildInfo: buildInfo, + ) as BuildableIOSApp; + return _buildableIOSApp; + } - if (app == null) { - throwToolExit('Application not configured for iOS'); - } - return app; - }(); + BuildableIOSApp _buildableIOSApp; Directory _outputAppDirectory(String xcodeResultOutput); @@ -234,7 +230,7 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand { @override Future<FlutterCommandResult> runCommand() async { defaultBuildMode = environmentType == EnvironmentType.simulator ? BuildMode.debug : BuildMode.release; - final BuildInfo buildInfo = await cachedBuildInfo; + final BuildInfo buildInfo = await getBuildInfo(); if (!supported) { throwToolExit('Building for iOS is only supported on macOS.'); @@ -252,10 +248,14 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand { ); } - final BuildableIOSApp app = await buildableIOSApp; + final BuildableIOSApp app = await buildableIOSApp(buildInfo); + + if (app == null) { + throwToolExit('Application not configured for iOS'); + } final String logTarget = environmentType == EnvironmentType.simulator ? 'simulator' : 'device'; - final String typeName = globals.artifacts!.getEngineType(TargetPlatform.ios, buildInfo.mode); + final String typeName = globals.artifacts.getEngineType(TargetPlatform.ios, buildInfo.mode); if (xcodeBuildAction == XcodeBuildAction.build) { globals.printStatus('Building $app for $logTarget ($typeName)...'); } else { @@ -291,24 +291,20 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand { final File precompilerTrace = globals.fs.directory(buildInfo.codeSizeDirectory) .childFile('trace.$arch.json'); - final String? resultOutput = result.output; - if (resultOutput == null) { - throwToolExit('Could not find app to analyze code size'); - } - final Directory outputAppDirectoryCandidate = _outputAppDirectory(resultOutput); + final Directory outputAppDirectoryCandidate = _outputAppDirectory(result.output); - Directory? appDirectory; + Directory appDirectory; if (outputAppDirectoryCandidate.existsSync()) { appDirectory = outputAppDirectoryCandidate.listSync() .whereType<Directory>() - .where((Directory directory) { + .firstWhere((Directory directory) { return globals.fs.path.extension(directory.path) == '.app'; - }).first; + }, orElse: () => null); } if (appDirectory == null) { throwToolExit('Could not find app to analyze code size in ${outputAppDirectoryCandidate.path}'); } - final Map<String, Object?> output = await sizeAnalyzer.analyzeAotSnapshot( + final Map<String, Object> output = await sizeAnalyzer.analyzeAotSnapshot( aotSnapshot: aotSnapshot, precompilerTrace: precompilerTrace, outputDirectory: appDirectory, diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart index 1af299a55e65c..c6c1c02f8c6d0 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:meta/meta.dart'; import '../artifacts.dart'; @@ -16,7 +18,7 @@ import '../build_system/build_system.dart'; import '../build_system/targets/ios.dart'; import '../cache.dart'; import '../flutter_plugins.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../macos/cocoapod_utils.dart'; import '../project.dart'; import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommandResult; @@ -29,17 +31,15 @@ import 'build.dart'; /// managers. class BuildIOSFrameworkCommand extends BuildSubCommand { BuildIOSFrameworkCommand({ - // Instantiating FlutterVersion kicks off networking, so delay until it's needed, but allow test injection. - @visibleForTesting FlutterVersion? flutterVersion, - required BuildSystem buildSystem, - required bool verboseHelp, - Cache? cache, - Platform? platform - }) : _injectedFlutterVersion = flutterVersion, + FlutterVersion flutterVersion, // Instantiating FlutterVersion kicks off networking, so delay until it's needed, but allow test injection. + @required BuildSystem buildSystem, + @required bool verboseHelp, + Cache cache, + Platform platform + }) : _flutterVersion = flutterVersion, _buildSystem = buildSystem, _injectedCache = cache, - _injectedPlatform = platform, - super(verboseHelp: verboseHelp) { + _injectedPlatform = platform { addTreeShakeIconsFlag(); usesTargetOption(); usesFlavorOption(); @@ -53,22 +53,26 @@ class BuildIOSFrameworkCommand extends BuildSubCommand { argParser ..addFlag('debug', + negatable: true, defaultsTo: true, help: 'Whether to produce a framework for the debug build configuration. ' 'By default, all build configurations are built.' ) ..addFlag('profile', + negatable: true, defaultsTo: true, help: 'Whether to produce a framework for the profile build configuration. ' 'By default, all build configurations are built.' ) ..addFlag('release', + negatable: true, defaultsTo: true, help: 'Whether to produce a framework for the release build configuration. ' 'By default, all build configurations are built.' ) ..addFlag('universal', help: '(deprecated) Produce universal frameworks that include all valid architectures.', + negatable: true, hide: !verboseHelp, ) ..addFlag('xcframework', @@ -92,18 +96,16 @@ class BuildIOSFrameworkCommand extends BuildSubCommand { ); } - final BuildSystem? _buildSystem; + final BuildSystem _buildSystem; BuildSystem get buildSystem => _buildSystem ?? globals.buildSystem; Cache get _cache => _injectedCache ?? globals.cache; - final Cache? _injectedCache; + final Cache _injectedCache; Platform get _platform => _injectedPlatform ?? globals.platform; - final Platform? _injectedPlatform; + final Platform _injectedPlatform; - // FlutterVersion.instance kicks off git processing which can sometimes fail, so don't try it until needed. - FlutterVersion get _flutterVersion => _injectedFlutterVersion ?? globals.flutterVersion; - final FlutterVersion? _injectedFlutterVersion; + FlutterVersion _flutterVersion; @override bool get reportNullSafety => false; @@ -121,7 +123,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand { DevelopmentArtifact.iOS, }; - late final FlutterProject _project = FlutterProject.current(); + FlutterProject _project; Future<List<BuildInfo>> getBuildInfos() async { final List<BuildInfo> buildInfos = <BuildInfo>[]; @@ -145,6 +147,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand { @override Future<void> validateCommand() async { await super.validateCommand(); + _project = FlutterProject.current(); if (!supported) { throwToolExit('Building frameworks for iOS is only supported on the Mac.'); } @@ -174,7 +177,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand { final List<BuildInfo> buildInfos = await getBuildInfos(); displayNullSafetyMode(buildInfos.first); for (final BuildInfo buildInfo in buildInfos) { - final String? productBundleIdentifier = await _project.ios.productBundleIdentifier(buildInfo); + final String productBundleIdentifier = await _project.ios.productBundleIdentifier(buildInfo); globals.printStatus('Building frameworks for $productBundleIdentifier in ${getNameForBuildMode(buildInfo.mode)} mode...'); final String xcodeBuildConfiguration = sentenceCase(getNameForBuildMode(buildInfo.mode)); final Directory modeDirectory = outputDirectory.childDirectory(xcodeBuildConfiguration); @@ -184,6 +187,8 @@ class BuildIOSFrameworkCommand extends BuildSubCommand { } if (boolArg('cocoapods')) { + // FlutterVersion.instance kicks off git processing which can sometimes fail, so don't try it until needed. + _flutterVersion ??= globals.flutterVersion; produceFlutterPodspec(buildInfo.mode, modeDirectory, force: boolArg('force')); } else { // Copy Flutter.xcframework. @@ -257,7 +262,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand { // Fake out a semantic version with major.minor.(patch * 100) + hotfix. // A real increasing version is required to prompt CocoaPods to fetch // new artifacts when the source URL changes. - final int minorHotfixVersion = (gitTagVersion.z ?? 0) * 100 + (gitTagVersion.hotfix ?? 0); + final int minorHotfixVersion = gitTagVersion.z * 100 + (gitTagVersion.hotfix ?? 0); final File license = _cache.getLicenseFile(); if (!license.existsSync()) { @@ -303,7 +308,7 @@ end final Status status = globals.logger.startProgress( ' ├─Copying Flutter.xcframework...', ); - final String engineCacheFlutterFrameworkDirectory = globals.artifacts!.getArtifactPath( + final String engineCacheFlutterFrameworkDirectory = globals.artifacts.getArtifactPath( Artifact.flutterXcframework, platform: TargetPlatform.ios, mode: buildInfo.mode, @@ -363,15 +368,15 @@ end kIosArchs: defaultIOSArchsForEnvironment(sdkType) .map(getNameForDarwinArch) .join(' '), - kSdkRoot: await globals.xcode!.sdkLocation(sdkType), + kSdkRoot: await globals.xcode.sdkLocation(sdkType), ...buildInfo.toBuildSystemEnvironment(), }, - artifacts: globals.artifacts!, + artifacts: globals.artifacts, fileSystem: globals.fs, logger: globals.logger, processManager: globals.processManager, platform: globals.platform, - engineVersion: globals.artifacts!.isLocalEngine + engineVersion: globals.artifacts.isLocalEngine ? null : globals.flutterVersion.engineRevision, generateDartPluginRegistry: true, @@ -417,7 +422,7 @@ end 'bitcode' : 'marker'; // In release, force bitcode embedding without archiving. List<String> pluginsBuildCommand = <String>[ - ...globals.xcode!.xcrunCommand(), + ...globals.xcode.xcrunCommand(), 'xcodebuild', '-alltargets', '-sdk', @@ -433,6 +438,7 @@ end RunResult buildPluginsResult = await globals.processUtils.run( pluginsBuildCommand, workingDirectory: _project.ios.hostAppRoot.childDirectory('Pods').path, + allowReentrantFlutter: false, ); if (buildPluginsResult.exitCode != 0) { @@ -442,7 +448,7 @@ end // Always build debug for simulator. final String simulatorConfiguration = sentenceCase(getNameForBuildMode(BuildMode.debug)); pluginsBuildCommand = <String>[ - ...globals.xcode!.xcrunCommand(), + ...globals.xcode.xcrunCommand(), 'xcodebuild', '-alltargets', '-sdk', @@ -460,6 +466,7 @@ end workingDirectory: _project.ios.hostAppRoot .childDirectory('Pods') .path, + allowReentrantFlutter: false, ); if (buildPluginsResult.exitCode != 0) { @@ -507,7 +514,7 @@ end return; } final List<String> xcframeworkCommand = <String>[ - ...globals.xcode!.xcrunCommand(), + ...globals.xcode.xcrunCommand(), 'xcodebuild', '-create-xcframework', for (Directory framework in frameworks) ...<String>[ @@ -528,6 +535,7 @@ end final RunResult xcframeworkResult = await globals.processUtils.run( xcframeworkCommand, + allowReentrantFlutter: false, ); if (xcframeworkResult.exitCode != 0) { diff --git a/packages/flutter_tools/lib/src/commands/build_linux.dart b/packages/flutter_tools/lib/src/commands/build_linux.dart index d783f53776942..5c65fb38ab6b2 100644 --- a/packages/flutter_tools/lib/src/commands/build_linux.dart +++ b/packages/flutter_tools/lib/src/commands/build_linux.dart @@ -2,13 +2,17 @@ // 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:meta/meta.dart'; + import '../base/analyze_size.dart'; import '../base/common.dart'; import '../base/os.dart'; import '../build_info.dart'; import '../cache.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../linux/build_linux.dart'; import '../project.dart'; import '../runner/flutter_command.dart' show FlutterCommandResult; @@ -17,10 +21,9 @@ import 'build.dart'; /// A command to build a linux desktop target through a build shell script. class BuildLinuxCommand extends BuildSubCommand { BuildLinuxCommand({ - required OperatingSystemUtils operatingSystemUtils, + @required OperatingSystemUtils operatingSystemUtils, bool verboseHelp = false, - }) : _operatingSystemUtils = operatingSystemUtils, - super(verboseHelp: verboseHelp) { + }) : _operatingSystemUtils = operatingSystemUtils { addCommonDesktopBuildOptions(verboseHelp: verboseHelp); final String defaultTargetPlatform = (_operatingSystemUtils.hostPlatform == HostPlatform.linux_arm64) ? @@ -59,7 +62,7 @@ class BuildLinuxCommand extends BuildSubCommand { final BuildInfo buildInfo = await getBuildInfo(); final FlutterProject flutterProject = FlutterProject.current(); final TargetPlatform targetPlatform = - getTargetPlatformForName(stringArg('target-platform')!); + getTargetPlatformForName(stringArg('target-platform')); final bool needCrossBuild = getNameForHostPlatformArch(_operatingSystemUtils.hostPlatform) != getNameForTargetPlatformArch(targetPlatform); @@ -93,7 +96,7 @@ class BuildLinuxCommand extends BuildSubCommand { ), needCrossBuild: needCrossBuild, targetPlatform: targetPlatform, - targetSysroot: stringArg('target-sysroot')!, + targetSysroot: stringArg('target-sysroot'), ); return FlutterCommandResult.success(); } diff --git a/packages/flutter_tools/lib/src/commands/build_macos.dart b/packages/flutter_tools/lib/src/commands/build_macos.dart index 415de8f5d273b..161d00517ebc5 100644 --- a/packages/flutter_tools/lib/src/commands/build_macos.dart +++ b/packages/flutter_tools/lib/src/commands/build_macos.dart @@ -2,12 +2,16 @@ // 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:meta/meta.dart'; + import '../base/analyze_size.dart'; import '../base/common.dart'; import '../build_info.dart'; import '../cache.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../macos/build_macos.dart'; import '../project.dart'; import '../runner/flutter_command.dart' show FlutterCommandResult; @@ -15,9 +19,7 @@ import 'build.dart'; /// A command to build a macOS desktop target through a build shell script. class BuildMacosCommand extends BuildSubCommand { - BuildMacosCommand({ - required bool verboseHelp, - }) : super(verboseHelp: verboseHelp) { + BuildMacosCommand({ @required bool verboseHelp }) { addCommonDesktopBuildOptions(verboseHelp: verboseHelp); usesBuildNumberOption(); usesBuildNameOption(); diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart index 8cc322dcdf037..8cb8b06a27098 100644 --- a/packages/flutter_tools/lib/src/commands/build_web.dart +++ b/packages/flutter_tools/lib/src/commands/build_web.dart @@ -2,11 +2,15 @@ // 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:meta/meta.dart'; + import '../base/common.dart'; import '../build_info.dart'; import '../build_system/targets/web.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommandResult; @@ -15,8 +19,8 @@ import 'build.dart'; class BuildWebCommand extends BuildSubCommand { BuildWebCommand({ - required bool verboseHelp, - }) : super(verboseHelp: verboseHelp) { + @required bool verboseHelp, + }) { addTreeShakeIconsFlag(enabledByDefault: false); usesTargetOption(); usesPubOption(); @@ -27,12 +31,14 @@ class BuildWebCommand extends BuildSubCommand { addNullSafetyModeOptions(hide: !verboseHelp); addNativeNullAssertions(); argParser.addFlag('csp', + defaultsTo: false, negatable: false, help: 'Disable dynamic generation of code in the generated output. ' 'This is necessary to satisfy CSP restrictions (see http://www.w3.org/TR/CSP/).' ); argParser.addFlag( 'source-maps', + defaultsTo: false, help: 'Generate a sourcemap file. These can be used by browsers ' 'to view and debug the original source code of a compiled and minified Dart ' 'application.' @@ -85,13 +91,12 @@ class BuildWebCommand extends BuildSubCommand { throwToolExit('"build web" is not currently supported. To enable, run "flutter config --enable-web".'); } final FlutterProject flutterProject = FlutterProject.current(); - final String target = stringArg('target')!; + final String target = stringArg('target'); final BuildInfo buildInfo = await getBuildInfo(); if (buildInfo.isDebug) { throwToolExit('debug builds cannot be built directly for the web. Try using "flutter run"'); } - final String? baseHref = stringArg('base-href'); - if (baseHref != null && !(baseHref.startsWith('/') && baseHref.endsWith('/'))) { + if (stringArg('base-href') != null && !(stringArg('base-href').startsWith('/') && stringArg('base-href').endsWith('/'))) { throwToolExit('base-href should start and end with /'); } if (!flutterProject.web.existsSync()) { @@ -102,7 +107,7 @@ class BuildWebCommand extends BuildSubCommand { .childFile('index.html') .readAsStringSync() .contains(kBaseHrefPlaceholder) && - baseHref != null) { + stringArg('base-href') != null) { throwToolExit( "Couldn't find the placeholder for base href. " r'Please add `<base href="$FLUTTER_BASE_HREF">` to web/index.html' @@ -114,10 +119,10 @@ class BuildWebCommand extends BuildSubCommand { target, buildInfo, boolArg('csp'), - stringArg('pwa-strategy')!, + stringArg('pwa-strategy'), boolArg('source-maps'), boolArg('native-null-assertions'), - baseHref, + stringArg('base-href'), ); return FlutterCommandResult.success(); } diff --git a/packages/flutter_tools/lib/src/commands/build_windows.dart b/packages/flutter_tools/lib/src/commands/build_windows.dart index b42c97676afe8..9b492702eb87c 100644 --- a/packages/flutter_tools/lib/src/commands/build_windows.dart +++ b/packages/flutter_tools/lib/src/commands/build_windows.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:meta/meta.dart'; import '../base/analyze_size.dart'; @@ -9,7 +11,7 @@ import '../base/common.dart'; import '../build_info.dart'; import '../cache.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../runner/flutter_command.dart' show FlutterCommandResult; import '../windows/build_windows.dart'; @@ -18,9 +20,7 @@ import 'build.dart'; /// A command to build a windows desktop target through a build shell script. class BuildWindowsCommand extends BuildSubCommand { - BuildWindowsCommand({ - bool verboseHelp = false, - }) : super(verboseHelp: verboseHelp) { + BuildWindowsCommand({ bool verboseHelp = false }) { addCommonDesktopBuildOptions(verboseHelp: verboseHelp); } @@ -39,7 +39,7 @@ class BuildWindowsCommand extends BuildSubCommand { String get description => 'Build a Windows desktop application.'; @visibleForTesting - VisualStudio? visualStudioOverride; + VisualStudio visualStudioOverride; @override Future<FlutterCommandResult> runCommand() async { diff --git a/packages/flutter_tools/lib/src/commands/build_winuwp.dart b/packages/flutter_tools/lib/src/commands/build_winuwp.dart index 7fb6eb9617775..c9801f5ce4e0b 100644 --- a/packages/flutter_tools/lib/src/commands/build_winuwp.dart +++ b/packages/flutter_tools/lib/src/commands/build_winuwp.dart @@ -2,13 +2,15 @@ // 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:meta/meta.dart'; import '../base/common.dart'; import '../build_info.dart'; import '../cache.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../runner/flutter_command.dart' show FlutterCommandResult; import '../windows/build_windows.dart'; @@ -17,9 +19,7 @@ import 'build.dart'; /// A command to build a Windows UWP desktop target. class BuildWindowsUwpCommand extends BuildSubCommand { - BuildWindowsUwpCommand({ - bool verboseHelp = false, - }) : super(verboseHelp: verboseHelp) { + BuildWindowsUwpCommand({ bool verboseHelp = false }) { addCommonDesktopBuildOptions(verboseHelp: verboseHelp); } @@ -38,7 +38,7 @@ class BuildWindowsUwpCommand extends BuildSubCommand { String get description => 'Build a Windows UWP desktop application.'; @visibleForTesting - VisualStudio? visualStudioOverride; + VisualStudio visualStudioOverride; @override Future<FlutterCommandResult> runCommand() async { diff --git a/packages/flutter_tools/lib/src/commands/channel.dart b/packages/flutter_tools/lib/src/commands/channel.dart index c100112c3c322..d404d57664e73 100644 --- a/packages/flutter_tools/lib/src/commands/channel.dart +++ b/packages/flutter_tools/lib/src/commands/channel.dart @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../base/common.dart'; import '../cache.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; import '../version.dart'; @@ -14,6 +16,7 @@ class ChannelCommand extends FlutterCommand { 'all', abbr: 'a', help: 'Include all the available branches (including local branches) when listing channels.', + defaultsTo: false, hide: !verboseHelp, ); } @@ -28,30 +31,29 @@ class ChannelCommand extends FlutterCommand { final String category = FlutterCommandCategory.sdk; @override - String get invocation => '${runner?.executableName} $name [<channel-name>]'; + String get invocation => '${runner.executableName} $name [<channel-name>]'; @override Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{}; @override Future<FlutterCommandResult> runCommand() async { - final List<String> rest = argResults?.rest ?? <String>[]; - switch (rest.length) { + switch (argResults.rest.length) { case 0: await _listChannels( showAll: boolArg('all'), - verbose: globalResults?['verbose'] == true, + verbose: globalResults['verbose'] as bool, ); return FlutterCommandResult.success(); case 1: - await _switchChannel(rest[0]); + await _switchChannel(argResults.rest[0]); return FlutterCommandResult.success(); default: throw ToolExit('Too many arguments.\n$usage'); } } - Future<void> _listChannels({ required bool showAll, required bool verbose }) async { + Future<void> _listChannels({ bool showAll, bool verbose }) async { // Beware: currentBranch could contain PII. See getBranchName(). final String currentChannel = globals.flutterVersion.channel; final String currentBranch = globals.flutterVersion.getBranchName(); diff --git a/packages/flutter_tools/lib/src/commands/clean.dart b/packages/flutter_tools/lib/src/commands/clean.dart index e72abddbcbef8..c41b8dd1f813e 100644 --- a/packages/flutter_tools/lib/src/commands/clean.dart +++ b/packages/flutter_tools/lib/src/commands/clean.dart @@ -2,13 +2,14 @@ // 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:meta/meta.dart'; -import '../../src/macos/xcode.dart'; import '../base/file_system.dart'; import '../base/logger.dart'; import '../build_info.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../ios/xcodeproj.dart'; import '../project.dart'; import '../runner/flutter_command.dart'; @@ -39,8 +40,7 @@ class CleanCommand extends FlutterCommand { // Clean Xcode to remove intermediate DerivedData artifacts. // Do this before removing ephemeral directory, which would delete the xcworkspace. final FlutterProject flutterProject = FlutterProject.current(); - final Xcode? xcode = globals.xcode; - if (xcode != null && xcode.isInstalledAndMeetsVersionCheck) { + if (globals.xcode.isInstalledAndMeetsVersionCheck) { await _cleanXcode(flutterProject.ios); await _cleanXcode(flutterProject.macos); } @@ -78,16 +78,15 @@ class CleanCommand extends FlutterCommand { 'Cleaning Xcode workspace...', ); try { - final XcodeProjectInterpreter xcodeProjectInterpreter = globals.xcodeProjectInterpreter!; final Directory xcodeWorkspace = xcodeProject.xcodeWorkspace; - final XcodeProjectInfo projectInfo = await xcodeProjectInterpreter.getInfo(xcodeWorkspace.parent.path); + final XcodeProjectInfo projectInfo = await globals.xcodeProjectInterpreter.getInfo(xcodeWorkspace.parent.path); for (final String scheme in projectInfo.schemes) { - await xcodeProjectInterpreter.cleanWorkspace(xcodeWorkspace.path, scheme, verbose: _verbose); + await globals.xcodeProjectInterpreter.cleanWorkspace(xcodeWorkspace.path, scheme, verbose: _verbose); } } on Exception catch (error) { globals.printTrace('Could not clean Xcode workspace: $error'); } finally { - xcodeStatus.stop(); + xcodeStatus?.stop(); } } diff --git a/packages/flutter_tools/lib/src/commands/config.dart b/packages/flutter_tools/lib/src/commands/config.dart index d7913e8a5c747..72f8fb6b48640 100644 --- a/packages/flutter_tools/lib/src/commands/config.dart +++ b/packages/flutter_tools/lib/src/commands/config.dart @@ -2,18 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import '../../src/android/android_sdk.dart'; -import '../../src/android/android_studio.dart'; +// @dart = 2.8 + import '../base/common.dart'; import '../convert.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../reporting/reporting.dart'; import '../runner/flutter_command.dart'; class ConfigCommand extends FlutterCommand { ConfigCommand({ bool verboseHelp = false }) { argParser.addFlag('analytics', + negatable: true, help: 'Enable or disable reporting anonymously tool usage statistics and crash reports.'); argParser.addFlag('clear-ios-signing-cert', negatable: false, @@ -27,13 +28,13 @@ class ConfigCommand extends FlutterCommand { hide: !verboseHelp, help: 'Print config values as json.'); for (final Feature feature in allFeatures) { - final String? configSetting = feature.configSetting; - if (configSetting == null) { + if (feature.configSetting == null) { continue; } argParser.addFlag( - configSetting, + feature.configSetting, help: feature.generateHelpMessage(), + negatable: true, ); } argParser.addFlag( @@ -69,16 +70,15 @@ class ConfigCommand extends FlutterCommand { final Map<String, Feature> featuresByName = <String, Feature>{}; final String channel = globals.flutterVersion.channel; for (final Feature feature in allFeatures) { - final String? configSetting = feature.configSetting; - if (configSetting != null) { - featuresByName[configSetting] = feature; + if (feature.configSetting != null) { + featuresByName[feature.configSetting] = feature; } } String values = globals.config.keys .map<String>((String key) { String configFooter = ''; if (featuresByName.containsKey(key)) { - final FeatureChannelSetting setting = featuresByName[key]!.getSettingForChannel(channel); + final FeatureChannelSetting setting = featuresByName[key].getSettingForChannel(channel); if (!setting.available) { configFooter = '(Unavailable)'; } @@ -97,7 +97,7 @@ class ConfigCommand extends FlutterCommand { /// Return null to disable analytics recording of the `config` command. @override - Future<String?> get usagePath async => null; + Future<String> get usagePath async => null; @override Future<FlutterCommandResult> runCommand() async { @@ -108,15 +108,14 @@ class ConfigCommand extends FlutterCommand { if (boolArg('clear-features')) { for (final Feature feature in allFeatures) { - final String? configSetting = feature.configSetting; - if (configSetting != null) { - globals.config.removeValue(configSetting); + if (feature.configSetting != null) { + globals.config.removeValue(feature.configSetting); } } return FlutterCommandResult.success(); } - if (argResults?.wasParsed('analytics') == true) { + if (argResults.wasParsed('analytics')) { final bool value = boolArg('analytics'); // The tool sends the analytics event *before* toggling the flag // intentionally to be sure that opt-out events are sent correctly. @@ -131,20 +130,20 @@ class ConfigCommand extends FlutterCommand { globals.printStatus('Analytics reporting ${value ? 'enabled' : 'disabled'}.'); } - if (argResults?.wasParsed('android-sdk') == true) { - _updateConfig('android-sdk', stringArg('android-sdk')!); + if (argResults.wasParsed('android-sdk')) { + _updateConfig('android-sdk', stringArg('android-sdk')); } - if (argResults?.wasParsed('android-studio-dir') == true) { - _updateConfig('android-studio-dir', stringArg('android-studio-dir')!); + if (argResults.wasParsed('android-studio-dir')) { + _updateConfig('android-studio-dir', stringArg('android-studio-dir')); } - if (argResults?.wasParsed('clear-ios-signing-cert') == true) { + if (argResults.wasParsed('clear-ios-signing-cert')) { _updateConfig('ios-signing-cert', ''); } - if (argResults?.wasParsed('build-dir') == true) { - final String buildDir = stringArg('build-dir')!; + if (argResults.wasParsed('build-dir')) { + final String buildDir = stringArg('build-dir'); if (globals.fs.path.isAbsolute(buildDir)) { throwToolExit('build-dir should be a relative path'); } @@ -152,18 +151,17 @@ class ConfigCommand extends FlutterCommand { } for (final Feature feature in allFeatures) { - final String? configSetting = feature.configSetting; - if (configSetting == null) { + if (feature.configSetting == null) { continue; } - if (argResults?.wasParsed(configSetting) == true) { - final bool keyValue = boolArg(configSetting); - globals.config.setValue(configSetting, keyValue); - globals.printStatus('Setting "$configSetting" value to "$keyValue".'); + if (argResults.wasParsed(feature.configSetting)) { + final bool keyValue = boolArg(feature.configSetting); + globals.config.setValue(feature.configSetting, keyValue); + globals.printStatus('Setting "${feature.configSetting}" value to "$keyValue".'); } } - if (argResults == null || argResults!.arguments.isEmpty) { + if (argResults.arguments.isEmpty) { globals.printStatus(usage); } else { globals.printStatus('\nYou may need to restart any open editors for them to read new settings.'); @@ -174,19 +172,17 @@ class ConfigCommand extends FlutterCommand { Future<void> handleMachine() async { // Get all the current values. - final Map<String, Object?> results = <String, Object?>{}; + final Map<String, dynamic> results = <String, dynamic>{}; for (final String key in globals.config.keys) { results[key] = globals.config.getValue(key); } // Ensure we send any calculated ones, if overrides don't exist. - final AndroidStudio? androidStudio = globals.androidStudio; - if (results['android-studio-dir'] == null && androidStudio != null) { - results['android-studio-dir'] = androidStudio.directory; + if (results['android-studio-dir'] == null && globals.androidStudio != null) { + results['android-studio-dir'] = globals.androidStudio.directory; } - final AndroidSdk? androidSdk = globals.androidSdk; - if (results['android-sdk'] == null && androidSdk != null) { - results['android-sdk'] = androidSdk.directory.path; + if (results['android-sdk'] == null && globals.androidSdk != null) { + results['android-sdk'] = globals.androidSdk.directory.path; } globals.printStatus(const JsonEncoder.withIndent(' ').convert(results)); diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index d7f82a710809a..86650c967b78e 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -16,7 +16,7 @@ import '../dart/pub.dart'; import '../features.dart'; import '../flutter_manifest.dart'; import '../flutter_project_metadata.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../ios/code_signing.dart'; import '../project.dart'; import '../reporting/reporting.dart'; @@ -228,7 +228,7 @@ class CreateCommand extends CreateBase { validateProjectDir(overwrite: overwrite); if (boolArg('with-driver-test')) { - globals.printWarning( + globals.printError( 'The "--with-driver-test" argument has been deprecated and will no longer add a flutter ' 'driver template. Instead, learn how to use package:integration_test by ' 'visiting https://pub.dev/packages/integration_test .' @@ -271,9 +271,6 @@ class CreateCommand extends CreateBase { // Enable null safety everywhere. dartSdkVersionBounds: '">=$dartSdk <3.0.0"', implementationTests: boolArg('implementation-tests'), - agpVersion: gradle.templateAndroidGradlePluginVersion, - kotlinVersion: gradle.templateKotlinGradlePluginVersion, - gradleVersion: gradle.templateDefaultGradleVersion, ); final String relativeDirPath = globals.fs.path.relative(projectDirPath); @@ -292,46 +289,19 @@ class CreateCommand extends CreateBase { int generatedFileCount = 0; switch (template) { case FlutterProjectType.app: - generatedFileCount += await generateApp( - 'app', - relativeDir, - templateContext, - overwrite: overwrite, - printStatusWhenWriting: !creatingNewProject, - ); + generatedFileCount += await generateApp('app', relativeDir, templateContext, overwrite: overwrite); break; case FlutterProjectType.skeleton: - generatedFileCount += await generateApp( - 'skeleton', - relativeDir, - templateContext, - overwrite: overwrite, - printStatusWhenWriting: !creatingNewProject, - ); + generatedFileCount += await generateApp('skeleton', relativeDir, templateContext, overwrite: overwrite); break; case FlutterProjectType.module: - generatedFileCount += await _generateModule( - relativeDir, - templateContext, - overwrite: overwrite, - printStatusWhenWriting: !creatingNewProject, - ); + generatedFileCount += await _generateModule(relativeDir, templateContext, overwrite: overwrite); break; case FlutterProjectType.package: - generatedFileCount += await _generatePackage( - relativeDir, - templateContext, - overwrite: overwrite, - printStatusWhenWriting: !creatingNewProject, - ); + generatedFileCount += await _generatePackage(relativeDir, templateContext, overwrite: overwrite); break; case FlutterProjectType.plugin: - generatedFileCount += await _generatePlugin( - relativeDir, - templateContext, - overwrite: overwrite, - printStatusWhenWriting: !creatingNewProject, - ); + generatedFileCount += await _generatePlugin(relativeDir, templateContext, overwrite: overwrite); break; } if (sampleCode != null) { @@ -397,24 +367,13 @@ Your $application code is in $relativeAppMain. return FlutterCommandResult.success(); } - Future<int> _generateModule( - Directory directory, - Map<String, dynamic> templateContext, { - bool overwrite = false, - bool printStatusWhenWriting = true, - }) async { + Future<int> _generateModule(Directory directory, Map<String, dynamic> templateContext, { bool overwrite = false }) async { int generatedCount = 0; final String description = argResults.wasParsed('description') ? stringArg('description') : 'A new flutter module project.'; templateContext['description'] = description; - generatedCount += await renderTemplate( - globals.fs.path.join('module', 'common'), - directory, - templateContext, - overwrite: overwrite, - printStatusWhenWriting: printStatusWhenWriting, - ); + generatedCount += await renderTemplate(globals.fs.path.join('module', 'common'), directory, templateContext, overwrite: overwrite); if (boolArg('pub')) { await pub.get( context: PubContext.create, @@ -431,24 +390,13 @@ Your $application code is in $relativeAppMain. return generatedCount; } - Future<int> _generatePackage( - Directory directory, - Map<String, dynamic> templateContext, { - bool overwrite = false, - bool printStatusWhenWriting = true, - }) async { + Future<int> _generatePackage(Directory directory, Map<String, dynamic> templateContext, { bool overwrite = false }) async { int generatedCount = 0; final String description = argResults.wasParsed('description') ? stringArg('description') : 'A new Flutter package project.'; templateContext['description'] = description; - generatedCount += await renderTemplate( - 'package', - directory, - templateContext, - overwrite: overwrite, - printStatusWhenWriting: printStatusWhenWriting, - ); + generatedCount += await renderTemplate('package', directory, templateContext, overwrite: overwrite); if (boolArg('pub')) { await pub.get( context: PubContext.createPackage, @@ -460,12 +408,7 @@ Your $application code is in $relativeAppMain. return generatedCount; } - Future<int> _generatePlugin( - Directory directory, - Map<String, dynamic> templateContext, { - bool overwrite = false, - bool printStatusWhenWriting = true, - }) async { + Future<int> _generatePlugin(Directory directory, Map<String, dynamic> templateContext, { bool overwrite = false }) async { // Plugins only add a platform if it was requested explicitly by the user. if (!argResults.wasParsed('platforms')) { for (final String platform in kAllCreatePlatforms) { @@ -487,13 +430,7 @@ Your $application code is in $relativeAppMain. ? stringArg('description') : 'A new flutter plugin project.'; templateContext['description'] = description; - generatedCount += await renderTemplate( - 'plugin', - directory, - templateContext, - overwrite: overwrite, - printStatusWhenWriting: printStatusWhenWriting, - ); + generatedCount += await renderTemplate('plugin', directory, templateContext, overwrite: overwrite); if (boolArg('pub')) { await pub.get( @@ -524,14 +461,7 @@ Your $application code is in $relativeAppMain. templateContext['pluginProjectName'] = projectName; templateContext['androidPluginIdentifier'] = androidPluginIdentifier; - generatedCount += await generateApp( - 'app', - project.example.directory, - templateContext, - overwrite: overwrite, - pluginExampleApp: true, - printStatusWhenWriting: printStatusWhenWriting, - ); + generatedCount += await generateApp('app', project.example.directory, templateContext, overwrite: overwrite, pluginExampleApp: true); return generatedCount; } diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index 7ea49d03788fa..89fb128bfa000 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -13,15 +13,12 @@ import '../android/gradle_utils.dart' as gradle; import '../base/common.dart'; import '../base/file_system.dart'; import '../base/utils.dart'; -import '../build_info.dart'; -import '../build_system/build_system.dart'; import '../cache.dart'; import '../convert.dart'; -import '../dart/generate_synthetic_packages.dart'; import '../dart/pub.dart'; import '../features.dart'; import '../flutter_project_metadata.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../runner/flutter_command.dart'; import '../template.dart'; @@ -336,9 +333,6 @@ abstract class CreateBase extends FlutterCommand { String iosLanguage, String flutterRoot, String dartSdkVersionBounds, - String agpVersion, - String kotlinVersion, - String gradleVersion, bool withPluginHook = false, bool ios = false, bool android = false, @@ -401,9 +395,6 @@ abstract class CreateBase extends FlutterCommand { 'year': DateTime.now().year, 'dartSdkVersionBounds': dartSdkVersionBounds, 'implementationTests': implementationTests, - 'agpVersion': agpVersion, - 'kotlinVersion': kotlinVersion, - 'gradleVersion': gradleVersion, }; } @@ -413,12 +404,8 @@ abstract class CreateBase extends FlutterCommand { /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`. @protected Future<int> renderTemplate( - String templateName, - Directory directory, - Map<String, Object> context, { - bool overwrite = false, - bool printStatusWhenWriting = true, - }) async { + String templateName, Directory directory, Map<String, Object> context, + {bool overwrite = false}) async { final Template template = await Template.fromName( templateName, fileSystem: globals.fs, @@ -426,12 +413,7 @@ abstract class CreateBase extends FlutterCommand { templateRenderer: globals.templateRenderer, templateManifest: _templateManifest, ); - return template.render( - directory, - context, - overwriteExisting: overwrite, - printStatusWhenWriting: printStatusWhenWriting, - ); + return template.render(directory, context, overwriteExisting: overwrite); } /// Merges named templates into a single template, output to `directory`. @@ -441,12 +423,8 @@ abstract class CreateBase extends FlutterCommand { /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`. @protected Future<int> renderMerged( - List<String> names, - Directory directory, - Map<String, Object> context, { - bool overwrite = false, - bool printStatusWhenWriting = true, - }) async { + List<String> names, Directory directory, Map<String, Object> context, + {bool overwrite = false}) async { final Template template = await Template.merged( names, directory, @@ -455,12 +433,7 @@ abstract class CreateBase extends FlutterCommand { templateRenderer: globals.templateRenderer, templateManifest: _templateManifest, ); - return template.render( - directory, - context, - overwriteExisting: overwrite, - printStatusWhenWriting: printStatusWhenWriting, - ); + return template.render(directory, context, overwriteExisting: overwrite); } /// Generate application project in the `directory` using `templateContext`. @@ -468,20 +441,14 @@ abstract class CreateBase extends FlutterCommand { /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`. @protected Future<int> generateApp( - String templateName, - Directory directory, - Map<String, Object> templateContext, { - bool overwrite = false, - bool pluginExampleApp = false, - bool printStatusWhenWriting = true, - }) async { + String templateName, Directory directory, Map<String, Object> templateContext, + {bool overwrite = false, bool pluginExampleApp = false}) async { int generatedCount = 0; generatedCount += await renderMerged( <String>[templateName, 'app_shared'], directory, templateContext, overwrite: overwrite, - printStatusWhenWriting: printStatusWhenWriting, ); final FlutterProject project = FlutterProject.fromDirectory(directory); if (templateContext['android'] == true) { @@ -489,27 +456,6 @@ abstract class CreateBase extends FlutterCommand { } if (boolArg('pub')) { - final Environment environment = Environment( - artifacts: globals.artifacts, - logger: globals.logger, - cacheDir: globals.cache.getRoot(), - engineVersion: globals.flutterVersion.engineRevision, - fileSystem: globals.fs, - flutterRootDir: globals.fs.directory(Cache.flutterRoot), - outputDir: globals.fs.directory(getBuildDirectory()), - processManager: globals.processManager, - platform: globals.platform, - projectDir: project.directory, - generateDartPluginRegistry: true, - ); - - // Generate the l10n synthetic package that will be injected into the - // package_config in the call to pub.get() below. - await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: globals.buildSystem, - ); - await pub.get( context: PubContext.create, directory: directory.path, diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index cfaa273e9afee..8e636d33ad904 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart @@ -18,12 +18,12 @@ import '../base/logger.dart'; import '../base/terminal.dart'; import '../base/utils.dart'; import '../build_info.dart'; -import '../daemon.dart'; +import '../convert.dart'; import '../device.dart'; import '../device_port_forwarder.dart'; import '../emulator.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../resident_runner.dart'; import '../run_cold.dart'; @@ -41,13 +41,7 @@ const String protocolVersion = '0.6.1'; /// It can be shutdown with a `daemon.shutdown` command (or by killing the /// process). class DaemonCommand extends FlutterCommand { - DaemonCommand({ this.hidden = false }) { - argParser.addOption( - 'listen-on-tcp-port', - help: 'If specified, the daemon will be listening for commands on the specified port instead of stdio.', - valueHelp: 'port', - ); - } + DaemonCommand({ this.hidden = false }); @override final String name = 'daemon'; @@ -63,31 +57,9 @@ class DaemonCommand extends FlutterCommand { @override Future<FlutterCommandResult> runCommand() async { - if (argResults['listen-on-tcp-port'] != null) { - int port; - try { - port = int.parse(stringArg('listen-on-tcp-port')); - } on FormatException catch (error) { - throwToolExit('Invalid port for `--listen-on-tcp-port`: $error'); - } - - await _DaemonServer( - port: port, - logger: StdoutLogger( - terminal: globals.terminal, - stdio: globals.stdio, - outputPreferences: globals.outputPreferences, - ), - notifyingLogger: asLogger<NotifyingLogger>(globals.logger), - ).run(); - return FlutterCommandResult.success(); - } globals.printStatus('Starting device daemon...'); final Daemon daemon = Daemon( - DaemonConnection( - daemonStreams: StdioDaemonStreams(globals.stdio), - logger: globals.logger, - ), + stdinCommandStream, stdoutCommandResponse, notifyingLogger: asLogger<NotifyingLogger>(globals.logger), ); final int code = await daemon.onExit; @@ -98,57 +70,14 @@ class DaemonCommand extends FlutterCommand { } } -class _DaemonServer { - _DaemonServer({ - this.port, - this.logger, - this.notifyingLogger, - }); - - final int port; - - /// Stdout logger used to print general server-related errors. - final Logger logger; - - // Logger that sends the message to the other end of daemon connection. - final NotifyingLogger notifyingLogger; - - Future<void> run() async { - final ServerSocket serverSocket = await ServerSocket.bind(InternetAddress.loopbackIPv4, port); - logger.printStatus('Daemon server listening on ${serverSocket.port}'); - - final StreamSubscription<Socket> subscription = serverSocket.listen( - (Socket socket) async { - // We have to listen to socket.done. Otherwise when the connection is - // reset, we will receive an uncatchable exception. - // https://github.com/dart-lang/sdk/issues/25518 - final Future<void> socketDone = socket.done.catchError((dynamic error, StackTrace stackTrace) { - logger.printError('Socket error: $error'); - logger.printTrace('$stackTrace'); - }); - final Daemon daemon = Daemon( - DaemonConnection( - daemonStreams: TcpDaemonStreams(socket, logger: logger), - logger: logger, - ), - notifyingLogger: notifyingLogger, - ); - await daemon.onExit; - await socketDone; - }, - ); - - // Wait indefinitely until the server closes. - await subscription.asFuture<void>(); - await subscription.cancel(); - } -} +typedef DispatchCommand = void Function(Map<String, dynamic> command); typedef CommandHandler = Future<dynamic> Function(Map<String, dynamic> args); class Daemon { Daemon( - this.connection, { + Stream<Map<String, dynamic>> commandStream, + this.sendCommand, { this.notifyingLogger, this.logToStdout = false, }) { @@ -160,10 +89,9 @@ class Daemon { _registerDomain(devToolsDomain = DevToolsDomain(this)); // Start listening. - _commandSubscription = connection.incomingCommands.listen( + _commandSubscription = commandStream.listen( _handleRequest, onDone: () { - shutdown(); if (!_onExitCompleter.isCompleted) { _onExitCompleter.complete(0); } @@ -171,15 +99,16 @@ class Daemon { ); } - final DaemonConnection connection; - DaemonDomain daemonDomain; AppDomain appDomain; DeviceDomain deviceDomain; EmulatorDomain emulatorDomain; DevToolsDomain devToolsDomain; StreamSubscription<Map<String, dynamic>> _commandSubscription; + int _outgoingRequestId = 1; + final Map<String, Completer<dynamic>> _outgoingRequestCompleters = <String, Completer<dynamic>>{}; + final DispatchCommand sendCommand; final NotifyingLogger notifyingLogger; final bool logToStdout; @@ -205,27 +134,62 @@ class Daemon { try { final String method = request['method'] as String; - assert(method != null); - if (!method.contains('.')) { - throw 'method not understood: $method'; - } + if (method != null) { + if (!method.contains('.')) { + throw 'method not understood: $method'; + } - final String prefix = method.substring(0, method.indexOf('.')); - final String name = method.substring(method.indexOf('.') + 1); - if (_domainMap[prefix] == null) { - throw 'no domain for method: $method'; - } + final String prefix = method.substring(0, method.indexOf('.')); + final String name = method.substring(method.indexOf('.') + 1); + if (_domainMap[prefix] == null) { + throw 'no domain for method: $method'; + } + + _domainMap[prefix].handleCommand(name, id, castStringKeyedMap(request['params']) ?? const <String, dynamic>{}); + } else { + // If there was no 'method' field then it's a response to a daemon-to-editor request. + final Completer<dynamic> completer = _outgoingRequestCompleters[id.toString()]; + if (completer == null) { + throw 'unexpected response with id: $id'; + } + _outgoingRequestCompleters.remove(id.toString()); - _domainMap[prefix].handleCommand(name, id, castStringKeyedMap(request['params']) ?? const <String, dynamic>{}); + if (request['error'] != null) { + completer.completeError(request['error']); + } else { + completer.complete(request['result']); + } + } } on Exception catch (error, trace) { - connection.sendErrorResponse(id, _toJsonable(error), trace); + _send(<String, dynamic>{ + 'id': id, + 'error': _toJsonable(error), + 'trace': '$trace', + }); } } + Future<dynamic> sendRequest(String method, [ dynamic args ]) { + final Map<String, dynamic> map = <String, dynamic>{'method': method}; + if (args != null) { + map['params'] = _toJsonable(args); + } + + final int id = _outgoingRequestId++; + final Completer<dynamic> completer = Completer<dynamic>(); + + map['id'] = id.toString(); + _outgoingRequestCompleters[id.toString()] = completer; + + _send(map); + return completer.future; + } + + void _send(Map<String, dynamic> map) => sendCommand(map); + Future<void> shutdown({ dynamic error }) async { await devToolsDomain?.dispose(); await _commandSubscription?.cancel(); - await connection.dispose(); for (final Domain domain in _domainMap.values) { await domain.dispose(); } @@ -261,16 +225,30 @@ abstract class Domain { } throw 'command not understood: $name.$command'; }).then<dynamic>((dynamic result) { - daemon.connection.sendResponse(id, _toJsonable(result)); - }).catchError((Object error, StackTrace stackTrace) { - daemon.connection.sendErrorResponse(id, _toJsonable(error), stackTrace); + if (result == null) { + _send(<String, dynamic>{'id': id}); + } else { + _send(<String, dynamic>{'id': id, 'result': _toJsonable(result)}); + } + }).catchError((dynamic error, dynamic trace) { + _send(<String, dynamic>{ + 'id': id, + 'error': _toJsonable(error), + 'trace': '$trace', + }); }); } void sendEvent(String name, [ dynamic args ]) { - daemon.connection.sendEvent(name, _toJsonable(args)); + final Map<String, dynamic> map = <String, dynamic>{'event': name}; + if (args != null) { + map['params'] = _toJsonable(args); + } + _send(map); } + void _send(Map<String, dynamic> map) => daemon._send(map); + String _getStringArg(Map<String, dynamic> args, String name, { bool required = false }) { if (required && !args.containsKey(name)) { throw '$name is required'; @@ -331,7 +309,7 @@ class DaemonDomain extends Domain { // capture the print output for testing. // ignore: avoid_print print(message.message); - } else if (message.level == 'error' || message.level == 'warning') { + } else if (message.level == 'error') { globals.stdio.stderrWrite('${message.message}\n'); if (message.stackTrace != null) { globals.stdio.stderrWrite( @@ -368,7 +346,7 @@ class DaemonDomain extends Domain { /// --web-allow-expose-url switch. The client may return the same URL back if /// tunnelling is not required for a given URL. Future<String> exposeUrl(String url) async { - final dynamic res = await daemon.connection.sendRequest('app.exposeUrl', <String, String>{'url': url}); + final dynamic res = await daemon.sendRequest('app.exposeUrl', <String, String>{'url': url}); if (res is Map<String, dynamic> && res['url'] is String) { return res['url'] as String; } else { @@ -929,6 +907,35 @@ class DevToolsDomain extends Domain { } } +Stream<Map<String, dynamic>> get stdinCommandStream => globals.stdio.stdin + .transform<String>(utf8.decoder) + .transform<String>(const LineSplitter()) + .where((String line) => line.startsWith('[{') && line.endsWith('}]')) + .map<Map<String, dynamic>>((String line) { + line = line.substring(1, line.length - 1); + return castStringKeyedMap(json.decode(line)); + }); + +void stdoutCommandResponse(Map<String, dynamic> command) { + globals.stdio.stdoutWrite( + '[${jsonEncodeObject(command)}]\n', + fallback: (String message, dynamic error, StackTrace stack) { + throwToolExit('Failed to write daemon command response to stdout: $error'); + }, + ); +} + +String jsonEncodeObject(dynamic object) { + return json.encode(object, toEncodable: _toEncodable); +} + +dynamic _toEncodable(dynamic object) { + if (object is OperationResult) { + return _operationResultToMap(object); + } + return object; +} + Future<Map<String, dynamic>> _deviceToMap(Device device) async { return <String, dynamic>{ 'id': device.id, @@ -963,7 +970,7 @@ dynamic _toJsonable(dynamic obj) { return obj; } if (obj is OperationResult) { - return _operationResultToMap(obj); + return obj; } if (obj is ToolExit) { return obj.message; @@ -1004,18 +1011,6 @@ class NotifyingLogger extends DelegatingLogger { _sendMessage(LogMessage('error', message, stackTrace)); } - @override - void printWarning( - String message, { - bool emphasis = false, - TerminalColor color, - int indent, - int hangingIndent, - bool wrap, - }) { - _sendMessage(LogMessage('warning', message)); - } - @override void printStatus( String message, { @@ -1029,13 +1024,6 @@ class NotifyingLogger extends DelegatingLogger { _sendMessage(LogMessage('status', message)); } - @override - void printBox(String message, { - String title, - }) { - _sendMessage(LogMessage('status', title == null ? message : '$title: $message')); - } - @override void printTrace(String message) { if (!verbose) { diff --git a/packages/flutter_tools/lib/src/commands/debug_adapter.dart b/packages/flutter_tools/lib/src/commands/debug_adapter.dart index 641b168a9d949..5ec797b67a57f 100644 --- a/packages/flutter_tools/lib/src/commands/debug_adapter.dart +++ b/packages/flutter_tools/lib/src/commands/debug_adapter.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'dart:async'; import '../debug_adapters/server.dart'; @@ -29,6 +31,7 @@ class DebugAdapterCommand extends FlutterCommand { argParser .addFlag( 'test', + defaultsTo: false, help: 'Whether to use the "flutter test" debug adapter to run tests' ' and emit custom events for test progress/results.', ); @@ -56,9 +59,9 @@ class DebugAdapterCommand extends FlutterCommand { globals.stdio.stdout.nonBlocking, fileSystem: globals.fs, platform: globals.platform, - ipv6: ipv6 == true, + ipv6: ipv6, enableDds: enableDds, - test: boolArg('test'), + test: boolArg('test') ?? false, ); await server.channel.closed; diff --git a/packages/flutter_tools/lib/src/commands/devices.dart b/packages/flutter_tools/lib/src/commands/devices.dart index 391cf06b183e9..1a988fb87c4be 100644 --- a/packages/flutter_tools/lib/src/commands/devices.dart +++ b/packages/flutter_tools/lib/src/commands/devices.dart @@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../base/common.dart'; import '../base/utils.dart'; import '../convert.dart'; import '../device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; class DevicesCommand extends FlutterCommand { @@ -18,6 +20,7 @@ class DevicesCommand extends FlutterCommand { argParser.addOption( 'timeout', abbr: 't', + defaultsTo: null, help: '(deprecated) This option has been replaced by "--${FlutterOptions.kDeviceTimeout}".', hide: !verboseHelp, ); @@ -34,9 +37,9 @@ class DevicesCommand extends FlutterCommand { final String category = FlutterCommandCategory.tools; @override - Duration? get deviceDiscoveryTimeout { - if (argResults?['timeout'] != null) { - final int? timeoutSeconds = int.tryParse(stringArg('timeout')!); + Duration get deviceDiscoveryTimeout { + if (argResults['timeout'] != null) { + final int timeoutSeconds = int.tryParse(stringArg('timeout')); if (timeoutSeconds == null) { throwToolExit('Could not parse -t/--timeout argument. It must be an integer.'); } @@ -47,22 +50,22 @@ class DevicesCommand extends FlutterCommand { @override Future<void> validateCommand() { - if (argResults?['timeout'] != null) { - globals.printWarning('${globals.logger.terminal.warningMark} The "--timeout" argument is deprecated; use "--${FlutterOptions.kDeviceTimeout}" instead.'); + if (argResults['timeout'] != null) { + globals.printError('${globals.logger.terminal.warningMark} The "--timeout" argument is deprecated; use "--${FlutterOptions.kDeviceTimeout}" instead.'); } return super.validateCommand(); } @override Future<FlutterCommandResult> runCommand() async { - if (globals.doctor?.canListAnything != true) { + if (!globals.doctor.canListAnything) { throwToolExit( "Unable to locate a development device; please run 'flutter doctor' for " 'information about installing additional components.', exitCode: 1); } - final List<Device> devices = await globals.deviceManager?.refreshAllConnectedDevices(timeout: deviceDiscoveryTimeout) ?? <Device>[]; + final List<Device> devices = await globals.deviceManager.refreshAllConnectedDevices(timeout: deviceDiscoveryTimeout); if (boolArg('machine')) { await printDevicesAsJson(devices); @@ -90,7 +93,7 @@ class DevicesCommand extends FlutterCommand { } Future<void> _printDiagnostics() async { - final List<String> diagnostics = await globals.deviceManager?.getDeviceDiagnostics() ?? <String>[]; + final List<String> diagnostics = await globals.deviceManager.getDeviceDiagnostics(); if (diagnostics.isNotEmpty) { globals.printStatus(''); for (final String diagnostic in diagnostics) { diff --git a/packages/flutter_tools/lib/src/commands/doctor.dart b/packages/flutter_tools/lib/src/commands/doctor.dart index 06de1b48784de..547b4758d684e 100644 --- a/packages/flutter_tools/lib/src/commands/doctor.dart +++ b/packages/flutter_tools/lib/src/commands/doctor.dart @@ -2,14 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../android/android_workflow.dart'; import '../base/common.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; class DoctorCommand extends FlutterCommand { DoctorCommand({this.verbose = false}) { argParser.addFlag('android-licenses', + defaultsTo: false, negatable: false, help: "Run the Android SDK manager tool to accept the SDK's licenses.", ); @@ -34,11 +37,11 @@ class DoctorCommand extends FlutterCommand { @override Future<FlutterCommandResult> runCommand() async { globals.flutterVersion.fetchTagsAndUpdate(); - if (argResults?.wasParsed('check-for-remote-artifacts') == true) { - final String engineRevision = stringArg('check-for-remote-artifacts')!; + if (argResults.wasParsed('check-for-remote-artifacts')) { + final String engineRevision = stringArg('check-for-remote-artifacts'); if (engineRevision.startsWith(RegExp(r'[a-f0-9]{1,40}'))) { - final bool success = await globals.doctor?.checkRemoteArtifacts(engineRevision) ?? false; - if (success) { + final bool success = await globals.doctor.checkRemoteArtifacts(engineRevision); + if (!success) { throwToolExit('Artifacts for engine $engineRevision are missing or are ' 'not yet available.', exitCode: 1); } @@ -47,11 +50,11 @@ class DoctorCommand extends FlutterCommand { 'git hash.'); } } - final bool success = await globals.doctor?.diagnose( + final bool success = await globals.doctor.diagnose( androidLicenses: boolArg('android-licenses'), verbose: verbose, androidLicenseValidator: androidLicenseValidator, - ) ?? false; + ); return FlutterCommandResult(success ? ExitStatus.success : ExitStatus.warning); } } diff --git a/packages/flutter_tools/lib/src/commands/downgrade.dart b/packages/flutter_tools/lib/src/commands/downgrade.dart index bb0eb428a9dc8..c71df4a9ba109 100644 --- a/packages/flutter_tools/lib/src/commands/downgrade.dart +++ b/packages/flutter_tools/lib/src/commands/downgrade.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:process/process.dart'; import '../base/common.dart'; @@ -11,7 +13,7 @@ import '../base/logger.dart'; import '../base/process.dart'; import '../base/terminal.dart'; import '../cache.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../persistent_tool_state.dart'; import '../runner/flutter_command.dart'; import '../version.dart'; @@ -29,13 +31,13 @@ import '../version.dart'; class DowngradeCommand extends FlutterCommand { DowngradeCommand({ bool verboseHelp = false, - PersistentToolState? persistentToolState, - Logger? logger, - ProcessManager? processManager, - FlutterVersion? flutterVersion, - Terminal? terminal, - Stdio? stdio, - FileSystem? fileSystem, + PersistentToolState persistentToolState, + Logger logger, + ProcessManager processManager, + FlutterVersion flutterVersion, + Terminal terminal, + Stdio stdio, + FileSystem fileSystem, }) : _terminal = terminal, _flutterVersion = flutterVersion, _persistentToolState = persistentToolState, @@ -59,14 +61,14 @@ class DowngradeCommand extends FlutterCommand { ); } - Terminal? _terminal; - FlutterVersion? _flutterVersion; - PersistentToolState? _persistentToolState; - ProcessUtils? _processUtils; - ProcessManager? _processManager; - Logger? _logger; - Stdio? _stdio; - FileSystem? _fileSystem; + Terminal _terminal; + FlutterVersion _flutterVersion; + PersistentToolState _persistentToolState; + ProcessUtils _processUtils; + ProcessManager _processManager; + Logger _logger; + Stdio _stdio; + FileSystem _fileSystem; @override String get description => 'Downgrade Flutter to the last active version for the current channel.'; @@ -87,26 +89,25 @@ class DowngradeCommand extends FlutterCommand { _flutterVersion ??= globals.flutterVersion; _persistentToolState ??= globals.persistentToolState; _processManager ??= globals.processManager; - _processUtils ??= ProcessUtils(processManager: _processManager!, logger: _logger!); + _processUtils ??= ProcessUtils(processManager: _processManager, logger: _logger); _stdio ??= globals.stdio; _fileSystem ??= globals.fs; - String workingDirectory = Cache.flutterRoot!; - if (argResults!.wasParsed('working-directory')) { - workingDirectory = stringArg('working-directory')!; + String workingDirectory = Cache.flutterRoot; + if (argResults.wasParsed('working-directory')) { + workingDirectory = stringArg('working-directory'); _flutterVersion = FlutterVersion(workingDirectory: workingDirectory); } - final String currentChannel = _flutterVersion!.channel; - final Channel? channel = getChannelForName(currentChannel); + final String currentChannel = _flutterVersion.channel; + final Channel channel = getChannelForName(currentChannel); if (channel == null) { throwToolExit( 'Flutter is not currently on a known channel. Use "flutter channel <name>" ' 'to switch to an official channel.', ); } - final PersistentToolState persistentToolState = _persistentToolState!; - final String? lastFlutterVersion = persistentToolState.lastActiveVersion(channel); - final String? currentFlutterVersion = _flutterVersion?.frameworkRevision; + final String lastFlutterVersion = _persistentToolState.lastActiveVersion(channel); + final String currentFlutterVersion = _flutterVersion.frameworkRevision; if (lastFlutterVersion == null || currentFlutterVersion == lastFlutterVersion) { final String trailing = await _createErrorMessage(workingDirectory, channel); throwToolExit( @@ -116,8 +117,7 @@ class DowngradeCommand extends FlutterCommand { } // Detect unknown versions. - final ProcessUtils processUtils = _processUtils!; - final RunResult parseResult = await processUtils.run(<String>[ + final RunResult parseResult = await _processUtils.run(<String>[ 'git', 'describe', '--tags', lastFlutterVersion, ], workingDirectory: workingDirectory); if (parseResult.exitCode != 0) { @@ -126,28 +126,25 @@ class DowngradeCommand extends FlutterCommand { final String humanReadableVersion = parseResult.stdout; // If there is a terminal attached, prompt the user to confirm the downgrade. - final Stdio stdio = _stdio!; - final Terminal terminal = _terminal!; - final Logger logger = _logger!; - if (stdio.hasTerminal && boolArg('prompt')) { - terminal.usesTerminalUi = true; - final String result = await terminal.promptForCharInput( + if (_stdio.hasTerminal && boolArg('prompt')) { + _terminal.usesTerminalUi = true; + final String result = await _terminal.promptForCharInput( const <String>['y', 'n'], prompt: 'Downgrade flutter to version $humanReadableVersion?', - logger: logger, + logger: _logger, ); if (result == 'n') { return FlutterCommandResult.success(); } } else { - logger.printStatus('Downgrading Flutter to version $humanReadableVersion'); + _logger.printStatus('Downgrading Flutter to version $humanReadableVersion'); } // To downgrade the tool, we perform a git checkout --hard, and then // switch channels. The version recorded must have existed on that branch // so this operation is safe. try { - await processUtils.run( + await _processUtils.run( <String>['git', 'reset', '--hard', lastFlutterVersion], throwOnError: true, workingDirectory: workingDirectory, @@ -161,7 +158,7 @@ class DowngradeCommand extends FlutterCommand { ); } try { - await processUtils.run( + await _processUtils.run( <String>['git', 'checkout', currentChannel, '--'], throwOnError: true, workingDirectory: workingDirectory, @@ -175,7 +172,7 @@ class DowngradeCommand extends FlutterCommand { ); } await FlutterVersion.resetFlutterVersionFreshnessCheck(); - logger.printStatus('Success'); + _logger.printStatus('Success'); return FlutterCommandResult.success(); } @@ -186,11 +183,11 @@ class DowngradeCommand extends FlutterCommand { if (channel == currentChannel) { continue; } - final String? sha = _persistentToolState?.lastActiveVersion(channel); + final String sha = _persistentToolState.lastActiveVersion(channel); if (sha == null) { continue; } - final RunResult parseResult = await _processUtils!.run(<String>[ + final RunResult parseResult = await _processUtils.run(<String>[ 'git', 'describe', '--tags', sha, ], workingDirectory: workingDirectory); if (parseResult.exitCode == 0) { diff --git a/packages/flutter_tools/lib/src/commands/drive.dart b/packages/flutter_tools/lib/src/commands/drive.dart index 4371f246c9f79..2084b79a7bb92 100644 --- a/packages/flutter_tools/lib/src/commands/drive.dart +++ b/packages/flutter_tools/lib/src/commands/drive.dart @@ -20,7 +20,7 @@ import '../build_info.dart'; import '../dart/package_map.dart'; import '../device.dart'; import '../drive/drive_service.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../resident_runner.dart'; import '../runner/flutter_command.dart' show FlutterCommandCategory, FlutterCommandResult, FlutterOptions; import '../web/web_device.dart'; diff --git a/packages/flutter_tools/lib/src/commands/emulators.dart b/packages/flutter_tools/lib/src/commands/emulators.dart index 89a3b7450b0c4..8ca8351afea55 100644 --- a/packages/flutter_tools/lib/src/commands/emulators.dart +++ b/packages/flutter_tools/lib/src/commands/emulators.dart @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:args/args.dart'; +// @dart = 2.8 import '../base/common.dart'; import '../base/utils.dart'; import '../doctor_validator.dart'; import '../emulator.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; class EmulatorsCommand extends FlutterCommand { @@ -39,22 +39,22 @@ class EmulatorsCommand extends FlutterCommand { @override Future<FlutterCommandResult> runCommand() async { - if (globals.doctor!.workflows.every((Workflow w) => !w.canListEmulators)) { + if (globals.doctor.workflows.every((Workflow w) => !w.canListEmulators)) { throwToolExit( 'Unable to find any emulator sources. Please ensure you have some\n' 'Android AVD images ${globals.platform.isMacOS ? 'or an iOS Simulator ' : ''}available.', exitCode: 1); } - final ArgResults argumentResults = argResults!; - if (argumentResults.wasParsed('launch')) { - final bool coldBoot = argumentResults.wasParsed('cold'); - await _launchEmulator(stringArg('launch')!, coldBoot: coldBoot); - } else if (argumentResults.wasParsed('create')) { + + if (argResults.wasParsed('launch')) { + final bool coldBoot = argResults.wasParsed('cold'); + await _launchEmulator(stringArg('launch'), coldBoot: coldBoot); + } else if (argResults.wasParsed('create')) { await _createEmulator(name: stringArg('name')); } else { - final String? searchText = - argumentResults.rest != null && argumentResults.rest.isNotEmpty - ? argumentResults.rest.first + final String searchText = + argResults.rest != null && argResults.rest.isNotEmpty + ? argResults.rest.first : null; await _listEmulators(searchText); } @@ -62,9 +62,9 @@ class EmulatorsCommand extends FlutterCommand { return FlutterCommandResult.success(); } - Future<void> _launchEmulator(String id, { required bool coldBoot }) async { + Future<void> _launchEmulator(String id, {bool coldBoot}) async { final List<Emulator> emulators = - await emulatorManager!.getEmulatorsMatching(id); + await emulatorManager.getEmulatorsMatching(id); if (emulators.isEmpty) { globals.printStatus("No emulator found that matches '$id'."); @@ -78,26 +78,23 @@ class EmulatorsCommand extends FlutterCommand { } } - Future<void> _createEmulator({ String? name }) async { + Future<void> _createEmulator({ String name }) async { final CreateEmulatorResult createResult = - await emulatorManager!.createEmulator(name: name); + await emulatorManager.createEmulator(name: name); if (createResult.success) { globals.printStatus("Emulator '${createResult.emulatorName}' created successfully."); } else { globals.printStatus("Failed to create emulator '${createResult.emulatorName}'.\n"); - final String? error = createResult.error; - if (error != null) { - globals.printStatus(error.trim()); - } + globals.printStatus(createResult.error.trim()); _printAdditionalInfo(); } } - Future<void> _listEmulators(String? searchText) async { + Future<void> _listEmulators(String searchText) async { final List<Emulator> emulators = searchText == null - ? await emulatorManager!.getAllAvailableEmulators() - : await emulatorManager!.getEmulatorsMatching(searchText); + ? await emulatorManager.getAllAvailableEmulators() + : await emulatorManager.getEmulatorsMatching(searchText); if (emulators.isEmpty) { globals.printStatus('No emulators available.'); diff --git a/packages/flutter_tools/lib/src/commands/format.dart b/packages/flutter_tools/lib/src/commands/format.dart index 986dc7ba22b75..7acb88b65beec 100644 --- a/packages/flutter_tools/lib/src/commands/format.dart +++ b/packages/flutter_tools/lib/src/commands/format.dart @@ -2,15 +2,18 @@ // 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/args.dart'; +import 'package:meta/meta.dart'; import '../artifacts.dart'; import '../base/common.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; class FormatCommand extends FlutterCommand { - FormatCommand({required this.verboseHelp}); + FormatCommand({@required this.verboseHelp}); @override ArgParser argParser = ArgParser.allowAnything(); @@ -30,24 +33,23 @@ class FormatCommand extends FlutterCommand { String get category => FlutterCommandCategory.project; @override - String get invocation => '${runner?.executableName} $name <one or more paths>'; + String get invocation => '${runner.executableName} $name <one or more paths>'; @override Future<FlutterCommandResult> runCommand() async { - final String dartBinary = globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path; + final String dartBinary = globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path; final List<String> command = <String>[ dartBinary, 'format', ]; - final List<String> rest = argResults?.rest ?? <String>[]; - if (rest.isEmpty) { + if (argResults.rest.isEmpty) { globals.printError( 'No files specified to be formatted.' ); command.add('-h'); } else { command.addAll(<String>[ - for (String arg in rest) + for (String arg in argResults.rest) if (arg == '--dry-run' || arg == '-n') '--output=none' else diff --git a/packages/flutter_tools/lib/src/commands/generate.dart b/packages/flutter_tools/lib/src/commands/generate.dart index d815d05d0e8f7..b78bdc2fb2970 100644 --- a/packages/flutter_tools/lib/src/commands/generate.dart +++ b/packages/flutter_tools/lib/src/commands/generate.dart @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import '../globals.dart' as globals; +// @dart = 2.8 + +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; class GenerateCommand extends FlutterCommand { diff --git a/packages/flutter_tools/lib/src/commands/generate_localizations.dart b/packages/flutter_tools/lib/src/commands/generate_localizations.dart index 17bf069712960..66526a37ed720 100644 --- a/packages/flutter_tools/lib/src/commands/generate_localizations.dart +++ b/packages/flutter_tools/lib/src/commands/generate_localizations.dart @@ -2,10 +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 '../base/common.dart'; import '../base/file_system.dart'; import '../base/logger.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../localizations/gen_l10n.dart'; import '../localizations/gen_l10n_types.dart'; import '../localizations/localizations_utils.dart'; @@ -19,8 +21,8 @@ import '../runner/flutter_command.dart'; /// [internationalization user guide](flutter.dev/go/i18n-user-guide). class GenerateLocalizationsCommand extends FlutterCommand { GenerateLocalizationsCommand({ - required FileSystem fileSystem, - required Logger logger, + FileSystem fileSystem, + Logger logger, }) : _fileSystem = fileSystem, _logger = logger { @@ -106,6 +108,7 @@ class GenerateLocalizationsCommand extends FlutterCommand { ); argParser.addFlag( 'use-deferred-loading', + defaultsTo: false, help: 'Whether to generate the Dart localization file with locales imported ' 'as deferred, allowing for lazy loading of each locale in Flutter web.\n' '\n' @@ -211,24 +214,25 @@ class GenerateLocalizationsCommand extends FlutterCommand { logger: _logger, options: options, projectDir: _fileSystem.currentDirectory, + dependenciesDir: null, fileSystem: _fileSystem, ); return FlutterCommandResult.success(); } - final String inputPathString = stringArg('arb-dir')!; // Has default value, cannot be null. - final String? outputPathString = stringArg('output-dir'); - final String outputFileString = stringArg('output-localization-file')!; // Has default value, cannot be null. - final String templateArbFileName = stringArg('template-arb-file')!; // Has default value, cannot be null. - final String? untranslatedMessagesFile = stringArg('untranslated-messages-file'); - final String classNameString = stringArg('output-class')!; // Has default value, cannot be null. + final String inputPathString = stringArg('arb-dir'); + final String outputPathString = stringArg('output-dir'); + final String outputFileString = stringArg('output-localization-file'); + final String templateArbFileName = stringArg('template-arb-file'); + final String untranslatedMessagesFile = stringArg('untranslated-messages-file'); + final String classNameString = stringArg('output-class'); final List<String> preferredSupportedLocales = stringsArg('preferred-supported-locales'); - final String? headerString = stringArg('header'); - final String? headerFile = stringArg('header-file'); + final String headerString = stringArg('header'); + final String headerFile = stringArg('header-file'); final bool useDeferredLoading = boolArg('use-deferred-loading'); - final String? inputsAndOutputsListPath = stringArg('gen-inputs-and-outputs-list'); + final String inputsAndOutputsListPath = stringArg('gen-inputs-and-outputs-list'); final bool useSyntheticPackage = boolArg('synthetic-package'); - final String? projectPathString = stringArg('project-dir'); + final String projectPathString = stringArg('project-dir'); final bool areResourceAttributesRequired = boolArg('required-resource-attributes'); final bool usesNullableGetter = boolArg('nullable-getter'); diff --git a/packages/flutter_tools/lib/src/commands/ide_config.dart b/packages/flutter_tools/lib/src/commands/ide_config.dart index 21b0863454bfe..1cffcf84c33a3 100644 --- a/packages/flutter_tools/lib/src/commands/ide_config.dart +++ b/packages/flutter_tools/lib/src/commands/ide_config.dart @@ -2,10 +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 '../base/common.dart'; import '../base/file_system.dart'; import '../cache.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; import '../template.dart'; @@ -13,6 +15,8 @@ class IdeConfigCommand extends FlutterCommand { IdeConfigCommand() { argParser.addFlag( 'overwrite', + negatable: true, + defaultsTo: false, help: 'When performing operations, overwrite existing files.', ); argParser.addFlag( @@ -27,6 +31,7 @@ class IdeConfigCommand extends FlutterCommand { ); argParser.addFlag( 'with-root-module', + negatable: true, defaultsTo: true, help: 'Also create module that corresponds to the root of Flutter tree. ' 'This makes the entire Flutter tree browsable and searchable in IDE. ' @@ -55,12 +60,12 @@ class IdeConfigCommand extends FlutterCommand { final bool hidden = true; @override - String get invocation => '${runner?.executableName} $name'; + String get invocation => '${runner.executableName} $name'; static const String _ideName = 'intellij'; Directory get _templateDirectory { return globals.fs.directory(globals.fs.path.join( - Cache.flutterRoot!, + Cache.flutterRoot, 'packages', 'flutter_tools', 'ide_templates', @@ -70,14 +75,14 @@ class IdeConfigCommand extends FlutterCommand { Directory get _createTemplatesDirectory { return globals.fs.directory(globals.fs.path.join( - Cache.flutterRoot!, + Cache.flutterRoot, 'packages', 'flutter_tools', 'templates', )); } - Directory get _flutterRoot => globals.fs.directory(globals.fs.path.absolute(Cache.flutterRoot!)); + Directory get _flutterRoot => globals.fs.directory(globals.fs.path.absolute(Cache.flutterRoot)); // Returns true if any entire path element is equal to dir. bool _hasDirectoryInPath(FileSystemEntity entity, String dir) { @@ -208,8 +213,7 @@ class IdeConfigCommand extends FlutterCommand { @override Future<FlutterCommandResult> runCommand() async { - final List<String> rest = argResults?.rest ?? <String>[]; - if (rest.isNotEmpty) { + if (argResults.rest.isNotEmpty) { throwToolExit('Currently, the only supported IDE is IntelliJ\n$usage', exitCode: 2); } @@ -218,12 +222,12 @@ class IdeConfigCommand extends FlutterCommand { return FlutterCommandResult.success(); } - final String flutterRoot = globals.fs.path.absolute(Cache.flutterRoot!); + final String flutterRoot = globals.fs.path.absolute(Cache.flutterRoot); final String dirPath = globals.fs.path.normalize( - globals.fs.directory(globals.fs.path.absolute(Cache.flutterRoot!)).absolute.path, + globals.fs.directory(globals.fs.path.absolute(Cache.flutterRoot)).absolute.path, ); - final String? error = _validateFlutterDir(dirPath, flutterRoot: flutterRoot); + final String error = _validateFlutterDir(dirPath, flutterRoot: flutterRoot); if (error != null) { throwToolExit(error); } @@ -261,7 +265,7 @@ class IdeConfigCommand extends FlutterCommand { /// Return null if the flutter root directory is a valid destination. Return a /// validation message if we should disallow the directory. -String? _validateFlutterDir(String dirPath, { String? flutterRoot }) { +String _validateFlutterDir(String dirPath, { String flutterRoot }) { final FileSystemEntityType type = globals.fs.typeSync(dirPath); switch (type) { // ignore: exhaustive_cases, https://github.com/dart-lang/linter/issues/3017 @@ -273,6 +277,5 @@ String? _validateFlutterDir(String dirPath, { String? flutterRoot }) { case FileSystemEntityType.notFound: return null; } - // In the case of any other [FileSystemEntityType]s, like the deprecated ones, return null. - return null; + return null; // dead code, remove after null safety migration } diff --git a/packages/flutter_tools/lib/src/commands/install.dart b/packages/flutter_tools/lib/src/commands/install.dart index 9ad0aa57bfc53..104cf48386500 100644 --- a/packages/flutter_tools/lib/src/commands/install.dart +++ b/packages/flutter_tools/lib/src/commands/install.dart @@ -2,12 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../android/android_device.dart'; import '../application_package.dart'; import '../base/common.dart'; import '../base/io.dart'; import '../device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { @@ -16,6 +18,8 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts usesDeviceUserOption(); usesDeviceTimeoutOption(); argParser.addFlag('uninstall-only', + negatable: true, + defaultsTo: false, help: 'Uninstall the app if already on the device. Skip install.', ); } @@ -29,10 +33,10 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts @override final String category = FlutterCommandCategory.tools; - Device? device; + Device device; bool get uninstallOnly => boolArg('uninstall-only'); - String? get userIdentifier => stringArg(FlutterOptions.kDeviceUser); + String get userIdentifier => stringArg(FlutterOptions.kDeviceUser); @override Future<void> validateCommand() async { @@ -48,23 +52,19 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts @override Future<FlutterCommandResult> runCommand() async { - final Device targetDevice = device!; - final ApplicationPackage? package = await applicationPackages?.getPackageForPlatform( - await targetDevice.targetPlatform, + final ApplicationPackage package = await applicationPackages.getPackageForPlatform( + await device.targetPlatform, ); - if (package == null) { - throwToolExit('Could not find or build package'); - } if (uninstallOnly) { - await _uninstallApp(package, targetDevice); + await _uninstallApp(package); } else { - await _installApp(package, targetDevice); + await _installApp(package); } return FlutterCommandResult.success(); } - Future<void> _uninstallApp(ApplicationPackage package, Device device) async { + Future<void> _uninstallApp(ApplicationPackage package) async { if (await device.isAppInstalled(package, userIdentifier: userIdentifier)) { globals.printStatus('Uninstalling $package from $device...'); if (!await device.uninstallApp(package, userIdentifier: userIdentifier)) { @@ -75,7 +75,7 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts } } - Future<void> _installApp(ApplicationPackage package, Device device) async { + Future<void> _installApp(ApplicationPackage package) async { globals.printStatus('Installing $package to $device...'); if (!await installApp(device, package, userIdentifier: userIdentifier)) { @@ -87,7 +87,7 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts Future<bool> installApp( Device device, ApplicationPackage package, { - String? userIdentifier, + String userIdentifier, bool uninstall = true }) async { if (package == null) { @@ -98,7 +98,7 @@ Future<bool> installApp( if (uninstall && await device.isAppInstalled(package, userIdentifier: userIdentifier)) { globals.printStatus('Uninstalling old version...'); if (!await device.uninstallApp(package, userIdentifier: userIdentifier)) { - globals.printWarning('Warning: uninstalling old version failed'); + globals.printError('Warning: uninstalling old version failed'); } } } on ProcessException catch (e) { diff --git a/packages/flutter_tools/lib/src/commands/logs.dart b/packages/flutter_tools/lib/src/commands/logs.dart index f5f1f37243bcd..80733ef7f1f8d 100644 --- a/packages/flutter_tools/lib/src/commands/logs.dart +++ b/packages/flutter_tools/lib/src/commands/logs.dart @@ -2,12 +2,14 @@ // 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 '../base/common.dart'; import '../base/io.dart'; import '../device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; class LogsCommand extends FlutterCommand { @@ -32,10 +34,10 @@ class LogsCommand extends FlutterCommand { @override Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{}; - Device? device; + Device device; @override - Future<FlutterCommandResult> verifyThenRunCommand(String? commandPath) async { + Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async { device = await findTargetDevice(includeUnsupportedDevices: true); if (device == null) { throwToolExit(null); @@ -45,12 +47,11 @@ class LogsCommand extends FlutterCommand { @override Future<FlutterCommandResult> runCommand() async { - final Device cachedDevice = device!; if (boolArg('clear')) { - cachedDevice.clearLogs(); + device.clearLogs(); } - final DeviceLogReader logReader = await cachedDevice.getLogReader(); + final DeviceLogReader logReader = await device.getLogReader(); globals.printStatus('Showing $logReader logs:'); diff --git a/packages/flutter_tools/lib/src/commands/make_host_app_editable.dart b/packages/flutter_tools/lib/src/commands/make_host_app_editable.dart index 907ce6090b4af..3fcb8669f1b6f 100644 --- a/packages/flutter_tools/lib/src/commands/make_host_app_editable.dart +++ b/packages/flutter_tools/lib/src/commands/make_host_app_editable.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../runner/flutter_command.dart'; class MakeHostAppEditableCommand extends FlutterCommand { diff --git a/packages/flutter_tools/lib/src/commands/packages.dart b/packages/flutter_tools/lib/src/commands/packages.dart index 796084f171d66..7797e901d374f 100644 --- a/packages/flutter_tools/lib/src/commands/packages.dart +++ b/packages/flutter_tools/lib/src/commands/packages.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:args/args.dart'; import '../base/common.dart'; @@ -12,7 +14,7 @@ import '../cache.dart'; import '../dart/generate_synthetic_packages.dart'; import '../dart/pub.dart'; import '../flutter_plugins.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../plugins.dart'; import '../project.dart'; import '../reporting/reporting.dart'; @@ -53,7 +55,7 @@ class PackagesCommand extends FlutterCommand { String get category => FlutterCommandCategory.project; @override - Future<FlutterCommandResult> runCommand() async => FlutterCommandResult.fail(); + Future<FlutterCommandResult> runCommand() async => null; } class PackagesGetCommand extends FlutterCommand { @@ -77,16 +79,15 @@ class PackagesGetCommand extends FlutterCommand { @override String get invocation { - return '${runner!.executableName} pub $name [<target directory>]'; + return '${runner.executableName} pub $name [<target directory>]'; } /// The pub packages usage values are incorrect since these are calculated/sent /// before pub get completes. This needs to be performed after dependency resolution. @override Future<CustomDimensions> get usageValues async { - final ArgResults argumentResults = argResults!; - final String? workingDirectory = argumentResults.rest.length == 1 ? argumentResults.rest[0] : null; - final String? target = findProjectRoot(globals.fs, workingDirectory); + final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null; + final String target = findProjectRoot(globals.fs, workingDirectory); if (target == null) { return const CustomDimensions(); } @@ -117,7 +118,7 @@ class PackagesGetCommand extends FlutterCommand { Future<void> _runPubGet(String directory, FlutterProject flutterProject) async { if (flutterProject.manifest.generateSyntheticPackage) { final Environment environment = Environment( - artifacts: globals.artifacts!, + artifacts: globals.artifacts, logger: globals.logger, cacheDir: globals.cache.getRoot(), engineVersion: globals.flutterVersion.engineRevision, @@ -158,13 +159,12 @@ class PackagesGetCommand extends FlutterCommand { @override Future<FlutterCommandResult> runCommand() async { - final ArgResults argumentResults = argResults!; - if (argumentResults.rest.length > 1) { + if (argResults.rest.length > 1) { throwToolExit('Too many arguments.\n$usage'); } - final String? workingDirectory = argumentResults.rest.length == 1 ? argumentResults.rest[0] : null; - final String? target = findProjectRoot(globals.fs, workingDirectory); + final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null; + final String target = findProjectRoot(globals.fs, workingDirectory); if (target == null) { throwToolExit( 'Expected to find project root in ' @@ -207,12 +207,12 @@ class PackagesTestCommand extends FlutterCommand { @override String get invocation { - return '${runner!.executableName} pub test [<tests...>]'; + return '${runner.executableName} pub test [<tests...>]'; } @override Future<FlutterCommandResult> runCommand() async { - await pub.batch(<String>['run', 'test', ...argResults!.rest], context: PubContext.runTest, retry: false); + await pub.batch(<String>['run', 'test', ...argResults.rest], context: PubContext.runTest, retry: false); return FlutterCommandResult.success(); } } @@ -241,12 +241,12 @@ class PackagesForwardCommand extends FlutterCommand { @override String get invocation { - return '${runner!.executableName} pub $_commandName [<arguments...>]'; + return '${runner.executableName} pub $_commandName [<arguments...>]'; } @override Future<FlutterCommandResult> runCommand() async { - final List<String> subArgs = argResults!.rest.toList() + final List<String> subArgs = argResults.rest.toList() ..removeWhere((String arg) => arg == '--'); await pub.interactively(<String>[_commandName, ...subArgs], stdio: globals.stdio); return FlutterCommandResult.success(); @@ -268,12 +268,12 @@ class PackagesPassthroughCommand extends FlutterCommand { @override String get invocation { - return '${runner!.executableName} packages pub [<arguments...>]'; + return '${runner.executableName} packages pub [<arguments...>]'; } @override Future<FlutterCommandResult> runCommand() async { - await pub.interactively(argResults!.rest, stdio: globals.stdio); + await pub.interactively(argResults.rest, stdio: globals.stdio); return FlutterCommandResult.success(); } } @@ -298,14 +298,14 @@ class PackagesInteractiveGetCommand extends FlutterCommand { @override String get invocation { - return '${runner!.executableName} pub $_commandName [<arguments...>]'; + return '${runner.executableName} pub $_commandName [<arguments...>]'; } @override Future<FlutterCommandResult> runCommand() async { - List<String> rest = argResults!.rest; + List<String> rest = argResults.rest; final bool isHelp = rest.contains('-h') || rest.contains('--help'); - String? target; + String target; if (rest.length == 1 && (rest.single.contains('/') || rest.single.contains(r'\'))) { // For historical reasons, if there is one argument to the command and it contains // a multiple-component path (i.e. contains a slash) then we use that to determine @@ -316,7 +316,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand { target = findProjectRoot(globals.fs); } - FlutterProject? flutterProject; + FlutterProject flutterProject; if (!isHelp) { if (target == null) { throwToolExit('Expected to find project root in current working directory.'); @@ -325,7 +325,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand { if (flutterProject.manifest.generateSyntheticPackage) { final Environment environment = Environment( - artifacts: globals.artifacts!, + artifacts: globals.artifacts, logger: globals.logger, cacheDir: globals.cache.getRoot(), engineVersion: globals.flutterVersion.engineRevision, @@ -351,7 +351,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand { directory: target, stdio: globals.stdio, touchesPackageConfig: !isHelp, - generateSyntheticPackage: flutterProject?.manifest.generateSyntheticPackage ?? false, + generateSyntheticPackage: flutterProject?.manifest?.generateSyntheticPackage ?? false, ); await flutterProject?.regeneratePlatformSpecificTooling(); diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 2bf805017b9d9..48d5dd803fad4 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -14,10 +14,9 @@ import '../base/common.dart'; import '../base/file_system.dart'; import '../base/utils.dart'; import '../build_info.dart'; -import '../daemon.dart'; import '../device.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import '../resident_runner.dart'; @@ -154,7 +153,6 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment addDdsOptions(verboseHelp: verboseHelp); addDevToolsOptions(verboseHelp: verboseHelp); addAndroidSpecificBuildOptions(hide: !verboseHelp); - usesFatalWarningsOption(verboseHelp: verboseHelp); } bool get traceStartup => boolArg('trace-startup'); @@ -252,7 +250,6 @@ class RunCommand extends RunCommandBase { // without needing to know the port. addPublishPort(verboseHelp: verboseHelp); addMultidexOption(); - addIgnoreDeprecationOption(); argParser ..addFlag('enable-software-rendering', negatable: false, @@ -344,10 +341,6 @@ class RunCommand extends RunCommandBase { @override final String name = 'run'; - @override - DeprecationBehavior get deprecationBehavior => boolArg('ignore-deprecation') ? DeprecationBehavior.ignore : _deviceDeprecationBehavior; - DeprecationBehavior _deviceDeprecationBehavior = DeprecationBehavior.none; - @override final String description = 'Run your Flutter app on an attached device.'; @@ -481,10 +474,6 @@ class RunCommand extends RunCommandBase { '--${FlutterOptions.kDeviceUser} is only supported for Android. At least one Android device is required.' ); } - - if (devices.any((Device device) => device is AndroidDevice)) { - _deviceDeprecationBehavior = DeprecationBehavior.exit; - } // Only support "web mode" with a single web device due to resident runner // refactoring required otherwise. webMode = featureFlags.isWebEnabled && @@ -557,10 +546,8 @@ class RunCommand extends RunCommandBase { throwToolExit('"--machine" does not support "-d all".'); } final Daemon daemon = Daemon( - DaemonConnection( - daemonStreams: StdioDaemonStreams(globals.stdio), - logger: globals.logger, - ), + stdinCommandStream, + stdoutCommandResponse, notifyingLogger: (globals.logger is NotifyingLogger) ? globals.logger as NotifyingLogger : NotifyingLogger(verbose: globals.logger.isVerbose, parent: globals.logger), diff --git a/packages/flutter_tools/lib/src/commands/screenshot.dart b/packages/flutter_tools/lib/src/commands/screenshot.dart index d8069ede5c19d..0f7419190d6f9 100644 --- a/packages/flutter_tools/lib/src/commands/screenshot.dart +++ b/packages/flutter_tools/lib/src/commands/screenshot.dart @@ -2,13 +2,15 @@ // 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:vm_service/vm_service.dart' as vm_service; import '../base/common.dart'; import '../base/file_system.dart'; import '../convert.dart'; import '../device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; import '../vmservice.dart'; @@ -65,9 +67,9 @@ class ScreenshotCommand extends FlutterCommand { @override final List<String> aliases = <String>['pic']; - Device? device; + Device device; - Future<void> _validateOptions(String? screenshotType, String? observatoryUrl) async { + Future<void> _validateOptions(String screenshotType, String observatoryUrl) async { switch (screenshotType) { case _kDeviceType: if (observatoryUrl != null) { @@ -77,8 +79,8 @@ class ScreenshotCommand extends FlutterCommand { if (device == null) { throwToolExit('Must have a connected device for screenshot type $screenshotType'); } - if (!device!.supportsScreenshot) { - throwToolExit('Screenshot not supported for ${device!.name}.'); + if (!device.supportsScreenshot) { + throwToolExit('Screenshot not supported for ${device.name}.'); } break; default: @@ -92,15 +94,15 @@ class ScreenshotCommand extends FlutterCommand { } @override - Future<FlutterCommandResult> verifyThenRunCommand(String? commandPath) async { + Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async { await _validateOptions(stringArg(_kType), stringArg(_kObservatoryUrl)); return super.verifyThenRunCommand(commandPath); } @override Future<FlutterCommandResult> runCommand() async { - File? outputFile; - if (argResults?.wasParsed(_kOut) == true) { + File outputFile; + if (argResults.wasParsed(_kOut)) { outputFile = globals.fs.file(stringArg(_kOut)); } @@ -121,24 +123,24 @@ class ScreenshotCommand extends FlutterCommand { : FlutterCommandResult.fail(); } - Future<void> runScreenshot(File? outputFile) async { + Future<void> runScreenshot(File outputFile) async { outputFile ??= globals.fsUtils.getUniqueFile( globals.fs.currentDirectory, 'flutter', 'png', ); try { - await device!.takeScreenshot(outputFile); + await device.takeScreenshot(outputFile); } on Exception catch (error) { throwToolExit('Error taking screenshot: $error'); } _showOutputFileInfo(outputFile); } - Future<bool> runSkia(File? outputFile) async { - final Uri observatoryUrl = Uri.parse(stringArg(_kObservatoryUrl)!); + Future<bool> runSkia(File outputFile) async { + final Uri observatoryUrl = Uri.parse(stringArg(_kObservatoryUrl)); final FlutterVmService vmService = await connectToVmService(observatoryUrl, logger: globals.logger); - final vm_service.Response? skp = await vmService.screenshotSkp(); + final vm_service.Response skp = await vmService.screenshotSkp(); if (skp == null) { globals.printError( 'The Skia picture request failed, probably because the device was ' @@ -152,17 +154,17 @@ class ScreenshotCommand extends FlutterCommand { 'skp', ); final IOSink sink = outputFile.openWrite(); - sink.add(base64.decode(skp.json?['skp'] as String)); + sink.add(base64.decode(skp.json['skp'] as String)); await sink.close(); _showOutputFileInfo(outputFile); _ensureOutputIsNotJsonRpcError(outputFile); return true; } - Future<bool> runRasterizer(File? outputFile) async { - final Uri observatoryUrl = Uri.parse(stringArg(_kObservatoryUrl)!); + Future<bool> runRasterizer(File outputFile) async { + final Uri observatoryUrl = Uri.parse(stringArg(_kObservatoryUrl)); final FlutterVmService vmService = await connectToVmService(observatoryUrl, logger: globals.logger); - final vm_service.Response? response = await vmService.screenshot(); + final vm_service.Response response = await vmService.screenshot(); if (response == null) { globals.printError( 'The screenshot request failed, probably because the device was ' @@ -176,7 +178,7 @@ class ScreenshotCommand extends FlutterCommand { 'png', ); final IOSink sink = outputFile.openWrite(); - sink.add(base64.decode(response.json?['screenshot'] as String)); + sink.add(base64.decode(response.json['screenshot'] as String)); await sink.close(); _showOutputFileInfo(outputFile); _ensureOutputIsNotJsonRpcError(outputFile); diff --git a/packages/flutter_tools/lib/src/commands/shell_completion.dart b/packages/flutter_tools/lib/src/commands/shell_completion.dart index 5fe8de30133d8..c06774bd87251 100644 --- a/packages/flutter_tools/lib/src/commands/shell_completion.dart +++ b/packages/flutter_tools/lib/src/commands/shell_completion.dart @@ -2,17 +2,21 @@ // 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:completion/completion.dart'; import '../base/common.dart'; import '../base/file_system.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; class ShellCompletionCommand extends FlutterCommand { ShellCompletionCommand() { argParser.addFlag( 'overwrite', + defaultsTo: false, + negatable: true, help: 'Causes the given shell completion setup script to be overwritten if it already exists.', ); } @@ -38,22 +42,21 @@ class ShellCompletionCommand extends FlutterCommand { /// Return null to disable analytics recording of the `bash-completion` command. @override - Future<String?> get usagePath async => null; + Future<String> get usagePath async => null; @override Future<FlutterCommandResult> runCommand() async { - final List<String> rest = argResults?.rest ?? <String>[]; - if (rest.length > 1) { + if (argResults.rest.length > 1) { throwToolExit('Too many arguments given to bash-completion command.', exitCode: 1); } - if (rest.isEmpty || rest.first == '-') { + if (argResults.rest.isEmpty || argResults.rest.first == '-') { final String script = generateCompletionScript(<String>['flutter']); globals.stdio.stdoutWrite(script); return FlutterCommandResult.warning(); } - final File outputFile = globals.fs.file(rest.first); + final File outputFile = globals.fs.file(argResults.rest.first); if (outputFile.existsSync() && !boolArg('overwrite')) { throwToolExit( 'Output file ${outputFile.path} already exists, will not overwrite. ' diff --git a/packages/flutter_tools/lib/src/commands/symbolize.dart b/packages/flutter_tools/lib/src/commands/symbolize.dart index f7ab2d20ded9c..df915b50cad33 100644 --- a/packages/flutter_tools/lib/src/commands/symbolize.dart +++ b/packages/flutter_tools/lib/src/commands/symbolize.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'dart:async'; import 'dart:typed_data'; @@ -22,8 +24,8 @@ import '../runner/flutter_command.dart'; /// over stdout. class SymbolizeCommand extends FlutterCommand { SymbolizeCommand({ - required Stdio stdio, - required FileSystem fileSystem, + @required Stdio stdio, + @required FileSystem fileSystem, DwarfSymbolizationService dwarfSymbolizationService = const DwarfSymbolizationService(), }) : _stdio = stdio, _fileSystem = fileSystem, @@ -65,13 +67,13 @@ class SymbolizeCommand extends FlutterCommand { @override Future<void> validateCommand() { - if (argResults?.wasParsed('debug-info') != true) { + if (!argResults.wasParsed('debug-info')) { throwToolExit('"--debug-info" is required to symbolize stack traces.'); } - if (!_fileSystem.isFileSync(stringArg('debug-info')!)) { + if (!_fileSystem.isFileSync(stringArg('debug-info'))) { throwToolExit('${stringArg('debug-info')} does not exist.'); } - if (argResults?.wasParsed('input') == true && !_fileSystem.isFileSync(stringArg('input')!)) { + if (argResults.wasParsed('input') && !_fileSystem.isFileSync(stringArg('input'))) { throwToolExit('${stringArg('input')} does not exist.'); } return super.validateCommand(); @@ -83,7 +85,7 @@ class SymbolizeCommand extends FlutterCommand { IOSink output; // Configure output to either specified file or stdout. - if (argResults?.wasParsed('output') == true) { + if (argResults.wasParsed('output')) { final File outputFile = _fileSystem.file(stringArg('output')); if (!outputFile.parent.existsSync()) { outputFile.parent.createSync(recursive: true); @@ -99,7 +101,7 @@ class SymbolizeCommand extends FlutterCommand { } // Configure input from either specified file or stdin. - if (argResults?.wasParsed('input') == true) { + if (argResults.wasParsed('input')) { input = _fileSystem.file(stringArg('input')).openRead(); } else { input = _stdio.stdin; @@ -119,7 +121,7 @@ class SymbolizeCommand extends FlutterCommand { typedef SymbolsTransformer = StreamTransformer<String, String> Function(Uint8List); StreamTransformer<String, String> _defaultTransformer(Uint8List symbols) { - final Dwarf? dwarf = Dwarf.fromBytes(symbols); + final Dwarf dwarf = Dwarf.fromBytes(symbols); if (dwarf == null) { throwToolExit('Failed to decode symbols file'); } @@ -135,7 +137,7 @@ StreamTransformer<String, String> _testTransformer(Uint8List buffer) { handleDone: (EventSink<String> sink) { sink.close(); }, - handleError: (Object error, StackTrace stackTrace, EventSink<String> sink) { + handleError: (dynamic error, StackTrace stackTrace, EventSink<String> sink) { sink.addError(error, stackTrace); } ); @@ -165,12 +167,12 @@ class DwarfSymbolizationService { /// Throws a [ToolExit] if the symbols cannot be parsed or the stack trace /// cannot be decoded. Future<void> decode({ - required Stream<List<int>> input, - required IOSink output, - required Uint8List symbols, + @required Stream<List<int>> input, + @required IOSink output, + @required Uint8List symbols, }) async { final Completer<void> onDone = Completer<void>(); - StreamSubscription<void>? subscription; + StreamSubscription<void> subscription; subscription = input .cast<List<int>>() .transform(const Utf8Decoder()) @@ -180,7 +182,7 @@ class DwarfSymbolizationService { try { output.writeln(line); } on Exception catch(e, s) { - subscription?.cancel().whenComplete(() { + subscription.cancel().whenComplete(() { if (!onDone.isCompleted) { onDone.completeError(e, s); } diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index f809823f5bf11..fae28596bb315 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart @@ -15,7 +15,7 @@ import '../build_info.dart'; import '../bundle_builder.dart'; import '../devfs.dart'; import '../device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../runner/flutter_command.dart'; import '../test/coverage_collector.dart'; @@ -73,7 +73,6 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { usesDartDefineOption(); usesWebRendererOption(); usesDeviceUserOption(); - usesFlavorOption(); argParser ..addMultiOption('name', @@ -217,8 +216,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { 'or as the string "none" to disable the timeout entirely.', defaultsTo: '30s', ); - addDdsOptions(verboseHelp: verboseHelp); - usesFatalWarningsOption(verboseHelp: verboseHelp); + addDdsOptions(verboseHelp: verboseHelp); } /// The interface for starting and configuring the tester. @@ -285,7 +283,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { // correct [requiredArtifacts] can be identified before [run] takes place. _isIntegrationTest = _shouldRunAsIntegrationTests(globals.fs.currentDirectory.absolute.path, _testFiles); - globals.printTrace( + globals.logger.printTrace( 'Found ${_testFiles.length} files which will be executed as ' '${_isIntegrationTest ? 'Integration' : 'Widget'} Tests.', ); @@ -340,7 +338,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { } if (_isIntegrationTest) { if (argResults.wasParsed('concurrency')) { - globals.printStatus( + globals.logger.printStatus( '-j/--concurrency was parsed but will be ignored, this option is not ' 'supported when running Integration Tests.', ); @@ -415,7 +413,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { ); } if (integrationTestDevice.platformType == PlatformType.web) { - // TODO(jiahaog): Support web. https://github.com/flutter/flutter/issues/66264 + // TODO(jiahaog): Support web. https://github.com/flutter/flutter/pull/74236 throwToolExit('Web devices are not supported for integration tests yet.'); } diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart index 3320161e6cea9..7c88c80b0ee03 100644 --- a/packages/flutter_tools/lib/src/commands/update_packages.dart +++ b/packages/flutter_tools/lib/src/commands/update_packages.dart @@ -16,7 +16,7 @@ import '../base/net.dart'; import '../base/task_queue.dart'; import '../cache.dart'; import '../dart/pub.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; /// Map from package name to package version, used to artificially pin a pub @@ -35,7 +35,11 @@ const Map<String, String> kManuallyPinnedDependencies = <String, String>{ // feature from https://github.com/dart-lang/shelf/issues/189 . This can be // removed when a new major version of shelf is published. 'shelf': '1.1.4', - 'video_player': '2.2.11', + 'video_player': '2.1.1', // Latest version does not resolve on our CI. + // "test" is pinned because 1.18.1 fails when running web tests with this error: + // FileSystemException: Cannot open file, path = '.../.pub-cache/hosted/pub.dartlang.org/test-1.18.1/lib/src/runner/browser/static/host.dart.js' (OS Error: No such file or directory, errno = 2) + // When removing this remove `pedantic` from dev/bots/allowlist.dart also. + 'test': '1.17.12', // https://github.com/dart-lang/test/issues/1594 }; class UpdatePackagesCommand extends FlutterCommand { @@ -97,12 +101,6 @@ class UpdatePackagesCommand extends FlutterCommand { help: 'For Flutter CLI testing only, forces this command to throw an unhandled exception.', defaultsTo: false, negatable: false, - ) - ..addOption( - 'jobs', - abbr: 'j', - help: 'Causes the "pub get" runs to happen concurrently on this many ' - 'CPUs. Defaults to the number of CPUs that this machine has.', ); } @@ -147,19 +145,19 @@ class UpdatePackagesCommand extends FlutterCommand { Future<FlutterCommandResult> runCommand() async { final List<Directory> packages = runner.getRepoPackages(); - final bool forceUpgrade = boolArg('force-upgrade'); + final bool upgrade = boolArg('force-upgrade'); final bool isPrintPaths = boolArg('paths'); final bool isPrintTransitiveClosure = boolArg('transitive-closure'); final bool isVerifyOnly = boolArg('verify-only'); final bool isConsumerOnly = boolArg('consumer-only'); final bool offline = boolArg('offline'); - final bool doUpgrade = forceUpgrade || isPrintPaths || isPrintTransitiveClosure; + final bool crash = boolArg('crash'); - if (boolArg('crash')) { + if (crash) { throw StateError('test crash please ignore.'); } - if (forceUpgrade && offline) { + if (upgrade && offline) { throwToolExit( '--force-upgrade cannot be used with the --offline flag' ); @@ -183,10 +181,60 @@ class UpdatePackagesCommand extends FlutterCommand { } if (isVerifyOnly) { - _verifyPubspecs(packages); + bool needsUpdate = false; + globals.printStatus('Verifying pubspecs...'); + for (final Directory directory in packages) { + PubspecYaml pubspec; + try { + pubspec = PubspecYaml(directory); + } on String catch (message) { + throwToolExit(message); + } + globals.printTrace('Reading pubspec.yaml from ${directory.path}'); + if (pubspec.checksum.value == null) { + // If the checksum is invalid or missing, we can just ask them run to run + // upgrade again to compute it. + globals.printError( + 'Warning: pubspec in ${directory.path} has out of date dependencies. ' + 'Please run "flutter update-packages --force-upgrade" to update them correctly.' + ); + needsUpdate = true; + } + // all dependencies in the pubspec sorted lexically. + final Map<String, String> checksumDependencies = <String, String>{}; + for (final PubspecLine data in pubspec.inputData) { + if (data is PubspecDependency && data.kind == DependencyKind.normal) { + checksumDependencies[data.name] = data.version; + } + } + final String checksum = _computeChecksum(checksumDependencies.keys, (String name) => checksumDependencies[name]); + if (checksum != pubspec.checksum.value) { + // If the checksum doesn't match, they may have added or removed some dependencies. + // we need to run update-packages to recapture the transitive deps. + globals.printError( + 'Warning: pubspec in ${directory.path} has updated or new dependencies. ' + 'Please run "flutter update-packages --force-upgrade" to update them correctly ' + '(checksum ${pubspec.checksum.value} != $checksum).' + ); + needsUpdate = true; + } else { + // everything is correct in the pubspec. + globals.printTrace('pubspec in ${directory.path} is up to date!'); + } + } + if (needsUpdate) { + throwToolExit( + 'Warning: one or more pubspecs have invalid dependencies. ' + 'Please run "flutter update-packages --force-upgrade" to update them correctly.', + exitCode: 1, + ); + } + globals.printStatus('All pubspecs were up to date.'); return FlutterCommandResult.success(); } + final Map<String, PubspecDependency> dependencies = <String, PubspecDependency>{}; + final bool doUpgrade = upgrade || isPrintPaths || isPrintTransitiveClosure; if (doUpgrade) { // This feature attempts to collect all the packages used across all the // pubspec.yamls in the repo (including via transitive dependencies), and @@ -195,116 +243,9 @@ class UpdatePackagesCommand extends FlutterCommand { globals.printStatus('Upgrading packages...'); } - // First, collect the dependencies: + // First, collect up the explicit dependencies: final List<PubspecYaml> pubspecs = <PubspecYaml>[]; - final Map<String, PubspecDependency> explicitDependencies = <String, PubspecDependency>{}; - final Map<String, PubspecDependency> allDependencies = <String, PubspecDependency>{}; final Set<String> specialDependencies = <String>{}; - _collectDependencies( - packages: packages, - pubspecs: pubspecs, - explicitDependencies: explicitDependencies, - allDependencies: allDependencies, - specialDependencies: specialDependencies, - doUpgrade: doUpgrade, - ); - - // Now that we have all the dependencies we care about, we are going to - // create a fake package and then run either "pub upgrade", if requested, - // followed by "pub get" on it. If upgrading, the pub tool will attempt to - // bring these dependencies up to the most recent possible versions while - // honoring all their constraints. If not upgrading the pub tool will only - // attempt to download any necessary package versions to the pub cache to - // warm the cache. - final PubDependencyTree tree = PubDependencyTree(); // object to collect results - final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_update_packages.'); - await _generateFakePackage( - tempDir: tempDir, - dependencies: doUpgrade ? explicitDependencies.values : allDependencies.values, - pubspecs: pubspecs, - tree: tree, - doUpgrade: doUpgrade, - ); - - if (doUpgrade) { - final bool done = _upgradePubspecs( - tree: tree, - pubspecs: pubspecs, - explicitDependencies: explicitDependencies, - specialDependencies: specialDependencies, - ); - - if (done) { - // Complete early if we were just printing data. - return FlutterCommandResult.success(); - } - } - - await _runPubGetOnPackages(packages); - - return FlutterCommandResult.success(); - } - - void _verifyPubspecs(List<Directory> packages) { - bool needsUpdate = false; - globals.printStatus('Verifying pubspecs...'); - for (final Directory directory in packages) { - PubspecYaml pubspec; - try { - pubspec = PubspecYaml(directory); - } on String catch (message) { - throwToolExit(message); - } - globals.printTrace('Reading pubspec.yaml from ${directory.path}'); - if (pubspec.checksum.value == null) { - // If the checksum is invalid or missing, we can just ask them run to run - // upgrade again to compute it. - globals.printWarning( - 'Warning: pubspec in ${directory.path} has out of date dependencies. ' - 'Please run "flutter update-packages --force-upgrade" to update them correctly.' - ); - needsUpdate = true; - } - // all dependencies in the pubspec sorted lexically. - final Map<String, String> checksumDependencies = <String, String>{}; - for (final PubspecLine data in pubspec.inputData) { - if (data is PubspecDependency && data.kind == DependencyKind.normal) { - checksumDependencies[data.name] = data.version; - } - } - final String checksum = _computeChecksum(checksumDependencies.keys, (String name) => checksumDependencies[name]); - if (checksum != pubspec.checksum.value) { - // If the checksum doesn't match, they may have added or removed some dependencies. - // we need to run update-packages to recapture the transitive deps. - globals.printWarning( - 'Warning: pubspec in ${directory.path} has updated or new dependencies. ' - 'Please run "flutter update-packages --force-upgrade" to update them correctly ' - '(checksum ${pubspec.checksum.value} != $checksum).' - ); - needsUpdate = true; - } else { - // everything is correct in the pubspec. - globals.printTrace('pubspec in ${directory.path} is up to date!'); - } - } - if (needsUpdate) { - throwToolExit( - 'Warning: one or more pubspecs have invalid dependencies. ' - 'Please run "flutter update-packages --force-upgrade" to update them correctly.', - exitCode: 1, - ); - } - globals.printStatus('All pubspecs were up to date.'); - } - - void _collectDependencies({ - @required List<Directory> packages, - @required List<PubspecYaml> pubspecs, - @required Set<String> specialDependencies, - @required Map<String, PubspecDependency> explicitDependencies, - @required Map<String, PubspecDependency> allDependencies, - @required bool doUpgrade, - }) { // Visit all the directories with pubspec.yamls we care about. for (final Directory directory in packages) { if (doUpgrade) { @@ -317,8 +258,8 @@ class UpdatePackagesCommand extends FlutterCommand { throwToolExit(message); } pubspecs.add(pubspec); // remember it for later - for (final PubspecDependency dependency in pubspec.allDependencies) { - if (allDependencies.containsKey(dependency.name)) { + for (final PubspecDependency dependency in pubspec.allDependencies) { // this is all the explicit dependencies + if (dependencies.containsKey(dependency.name)) { // If we've seen the dependency before, make sure that we are // importing it the same way. There's several ways to import a // dependency. Hosted (from pub via version number), by path (e.g. @@ -329,47 +270,17 @@ class UpdatePackagesCommand extends FlutterCommand { // This makes sure that we don't import a package in two different // ways, e.g. by saying "sdk: flutter" in one pubspec.yaml and // saying "path: ../../..." in another. - final PubspecDependency previous = allDependencies[dependency.name]; + final PubspecDependency previous = dependencies[dependency.name]; if (dependency.kind != previous.kind || dependency.lockTarget != previous.lockTarget) { throwToolExit( - 'Inconsistent requirements around ${dependency.name}; ' - 'saw ${dependency.kind} (${dependency.lockTarget}) in "${dependency.sourcePath}" ' - 'and ${previous.kind} (${previous.lockTarget}) in "${previous.sourcePath}".' - ); - } - if (dependency.version != previous.version) { - globals.printError( - 'Requiring multiple versions: multiple versions required by ${dependency.name}; ' - 'saw ${dependency.version} in "${dependency.sourcePath}" ' - 'and ${previous.version} in "${previous.sourcePath}".' - ); - } - } - allDependencies[dependency.name] = dependency; - } - for (final PubspecDependency dependency in pubspec.allExplicitDependencies) { - if (explicitDependencies.containsKey(dependency.name)) { - // If we've seen the dependency before, make sure that we are - // importing it the same way. There's several ways to import a - // dependency. Hosted (from pub via version number), by path (e.g. - // pointing at the version of a package we get from the Dart SDK - // that we download with Flutter), by SDK (e.g. the "flutter" - // package is explicitly from "sdk: flutter"). - // - // This makes sure that we don't import a package in two different - // ways, e.g. by saying "sdk: flutter" in one pubspec.yaml and - // saying "path: ../../..." in another. - final PubspecDependency previous = explicitDependencies[dependency.name]; - if (dependency.kind != previous.kind || dependency.lockTarget != previous.lockTarget) { - throwToolExit( - 'Inconsistent requirements around ${dependency.name}; ' - 'saw ${dependency.kind} (${dependency.lockTarget}) in "${dependency.sourcePath}" ' - 'and ${previous.kind} (${previous.lockTarget}) in "${previous.sourcePath}".' + 'Inconsistent requirements around ${dependency.name}; ' + 'saw ${dependency.kind} (${dependency.lockTarget}) in "${dependency.sourcePath}" ' + 'and ${previous.kind} (${previous.lockTarget}) in "${previous.sourcePath}".' ); } } // Remember this dependency by name so we can look it up again. - explicitDependencies[dependency.name] = dependency; + dependencies[dependency.name] = dependency; // Normal dependencies are those we get from pub. The others we // already implicitly pin since we pull down one version of the // Flutter and Dart SDKs, so we track which those are here so that we @@ -379,28 +290,29 @@ class UpdatePackagesCommand extends FlutterCommand { } } } - } - Future<void> _generateFakePackage({ - Directory tempDir, - Iterable<PubspecDependency> dependencies, - List<PubspecYaml> pubspecs, - PubDependencyTree tree, - bool doUpgrade, - }) async { + // Now that we have all the dependencies we explicitly care about, we are + // going to create a fake package and then run either "pub upgrade" or "pub + // get" on it, depending on whether we are upgrading or not. If upgrading, + // the pub tool will attempt to bring these dependencies up to the most + // recent possible versions while honoring all their constraints. If not + // upgrading the pub tool will attempt to download any necessary package + // versions to the pub cache to warm the cache. + final PubDependencyTree tree = PubDependencyTree(); // object to collect results + final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_update_packages.'); try { final File fakePackage = _pubspecFor(tempDir); fakePackage.createSync(); fakePackage.writeAsStringSync( _generateFakePubspec( - dependencies, + dependencies.values, useAnyVersion: doUpgrade, ), ); // Create a synthetic flutter SDK so that transitive flutter SDK // constraints are not affected by this upgrade. Directory temporaryFlutterSdk; - if (doUpgrade) { + if (upgrade) { temporaryFlutterSdk = createTemporaryFlutterSdk( globals.logger, globals.fs, @@ -409,14 +321,17 @@ class UpdatePackagesCommand extends FlutterCommand { ); } - // Next we run "pub get" on it in order to force the download of any - // needed packages to the pub cache, upgrading if requested. + // Next we run "pub upgrade" on this generated package, if we're doing + // an upgrade. Otherwise, we just run a regular "pub get" on it in order + // to force the download of any needed packages to the pub cache. await pub.get( context: PubContext.updatePackages, directory: tempDir.path, upgrade: doUpgrade, - offline: boolArg('offline'), - flutterRootOverride: doUpgrade ? temporaryFlutterSdk.path : null, + offline: offline, + flutterRootOverride: upgrade + ? temporaryFlutterSdk.path + : null, generateSyntheticPackage: false, ); // Cleanup the temporary SDK @@ -443,57 +358,54 @@ class UpdatePackagesCommand extends FlutterCommand { } finally { tempDir.deleteSync(recursive: true); } - } - bool _upgradePubspecs({ - @required PubDependencyTree tree, - @required List<PubspecYaml> pubspecs, - @required Set<String> specialDependencies, - @required Map<String, PubspecDependency> explicitDependencies, - }) { - // The transitive dependency tree for the fake package does not contain - // dependencies between Flutter SDK packages and pub packages. We add them - // here. - for (final PubspecYaml pubspec in pubspecs) { - final String package = pubspec.name; - specialDependencies.add(package); - tree._versions[package] = pubspec.version; - assert(!tree._dependencyTree.containsKey(package)); - tree._dependencyTree[package] = <String>{}; - for (final PubspecDependency dependency in pubspec.dependencies) { - if (dependency.kind == DependencyKind.normal) { - tree._dependencyTree[package].add(dependency.name); + if (doUpgrade) { + // The transitive dependency tree for the fake package does not contain + // dependencies between Flutter SDK packages and pub packages. We add them + // here. + for (final PubspecYaml pubspec in pubspecs) { + final String package = pubspec.name; + specialDependencies.add(package); + tree._versions[package] = pubspec.version; + assert(!tree._dependencyTree.containsKey(package)); + tree._dependencyTree[package] = <String>{}; + for (final PubspecDependency dependency in pubspec.dependencies) { + if (dependency.kind == DependencyKind.normal) { + tree._dependencyTree[package].add(dependency.name); + } } } - } - if (boolArg('transitive-closure')) { - tree._dependencyTree.forEach((String from, Set<String> to) { - globals.printStatus('$from -> $to'); - }); - return true; - } + if (isPrintTransitiveClosure) { + tree._dependencyTree.forEach((String from, Set<String> to) { + globals.printStatus('$from -> $to'); + }); + return FlutterCommandResult.success(); + } - if (boolArg('paths')) { - showDependencyPaths(from: stringArg('from'), to: stringArg('to'), tree: tree); - return true; - } + if (isPrintPaths) { + showDependencyPaths(from: stringArg('from'), to: stringArg('to'), tree: tree); + return FlutterCommandResult.success(); + } - // Now that we have collected all the data, we can apply our dependency - // versions to each pubspec.yaml that we collected. This mutates the - // pubspec.yaml files. - // - // The specialDependencies argument is the set of package names to not pin - // to specific versions because they are explicitly pinned by their - // constraints. Here we list the names we earlier established we didn't - // need to pin because they come from the Dart or Flutter SDKs. - for (final PubspecYaml pubspec in pubspecs) { - pubspec.apply(tree, specialDependencies); + // Now that we have collected all the data, we can apply our dependency + // versions to each pubspec.yaml that we collected. This mutates the + // pubspec.yaml files. + // + // The specialDependencies argument is the set of package names to not pin + // to specific versions because they are explicitly pinned by their + // constraints. Here we list the names we earlier established we didn't + // need to pin because they come from the Dart or Flutter SDKs. + for (final PubspecYaml pubspec in pubspecs) { + pubspec.apply(tree, specialDependencies); + } + + // Now that the pubspec.yamls are updated, we run "pub get" on each one so + // that the various packages are ready to use. This is what "flutter + // update-packages" does without --force-upgrade, so we can just fall into + // the regular code path. } - return false; - } - Future<void> _runPubGetOnPackages(List<Directory> packages) async { final Stopwatch timer = Stopwatch()..start(); int count = 0; @@ -508,7 +420,7 @@ class UpdatePackagesCommand extends FlutterCommand { 'Running "flutter pub get" in affected packages...', ); try { - final TaskQueue<void> queue = TaskQueue<void>(maxJobs: intArg('jobs')); + final TaskQueue<void> queue = TaskQueue<void>(); for (final Directory dir in packages) { unawaited(queue.add(() async { final Stopwatch stopwatch = Stopwatch(); @@ -516,9 +428,7 @@ class UpdatePackagesCommand extends FlutterCommand { await pub.get( context: PubContext.updatePackages, directory: dir.path, - // All dependencies should already have been downloaded by the fake - // package, so the concurrent checks can all happen offline. - offline: true, + offline: offline, generateSyntheticPackage: false, printProgress: false, ); @@ -546,6 +456,8 @@ class UpdatePackagesCommand extends FlutterCommand { final double seconds = timer.elapsedMilliseconds / 1000.0; globals.printStatus("\nRan 'pub get' $count time${count == 1 ? "" : "s"} and fetched coverage data in ${seconds.toStringAsFixed(1)}s."); + + return FlutterCommandResult.success(); } void showDependencyPaths({ @@ -832,27 +744,26 @@ class PubspecYaml { } /// This returns all the explicit dependencies that this pubspec.yaml lists under dependencies. - Iterable<PubspecDependency> get dependencies { + Iterable<PubspecDependency> get dependencies sync* { // It works by iterating over the parsed data from _parse above, collecting // all the dependencies that were found, ignoring any that are flagged as as // overridden by subsequent entries in the same file and any that have the // magic comment flagging them as auto-generated transitive dependencies // that we added in a previous run. - return inputData - .whereType<PubspecDependency>() - .where((PubspecDependency data) => data.kind != DependencyKind.overridden && !data.isTransitive && !data.isDevDependency); + for (final PubspecLine data in inputData) { + if (data is PubspecDependency && data.kind != DependencyKind.overridden && !data.isTransitive && !data.isDevDependency) { + yield data; + } + } } /// This returns all regular dependencies and all dev dependencies. - Iterable<PubspecDependency> get allExplicitDependencies { - return inputData - .whereType<PubspecDependency>() - .where((PubspecDependency data) => data.kind != DependencyKind.overridden && !data.isTransitive); - } - - /// This returns all dependencies. - Iterable<PubspecDependency> get allDependencies { - return inputData.whereType<PubspecDependency>(); + Iterable<PubspecDependency> get allDependencies sync* { + for (final PubspecLine data in inputData) { + if (data is PubspecDependency && data.kind != DependencyKind.overridden && !data.isTransitive) { + yield data; + } + } } /// Take a dependency graph with explicit version numbers, and apply them to @@ -911,8 +822,7 @@ class PubspecYaml { // We output data that matches the format that // PubspecDependency.parse can handle. The data.suffix is any // previously-specified trailing comment. - assert(versions.contains(data.name), - "versions doesn't contain ${data.name}"); + assert(versions.contains(data.name)); output.add(' ${data.name}: ${versions.versionFor(data.name)}${data.suffix}'); } else { // If it wasn't a regular dependency, then we output the line @@ -1506,26 +1416,23 @@ class PubDependencyTree { String package, { @required Set<String> seen, @required Set<String> exclude, - List<String>/*?*/ result, - }) { + }) sync* { assert(seen != null); assert(exclude != null); - result ??= <String>[]; if (!_dependencyTree.containsKey(package)) { // We have no transitive dependencies extracted for flutter_sdk packages // because they were omitted from pubspec.yaml used for 'pub upgrade' run. - return result; + return; } for (final String dependency in _dependencyTree[package]) { if (!seen.contains(dependency)) { if (!exclude.contains(dependency)) { - result.add(dependency); + yield dependency; } seen.add(dependency); - getTransitiveDependenciesFor(dependency, seen: seen, exclude: exclude, result: result); + yield* getTransitiveDependenciesFor(dependency, seen: seen, exclude: exclude); } } - return result; } /// The version that a particular package ended up with. @@ -1598,7 +1505,7 @@ Directory createTemporaryFlutterSdk( ..createSync(recursive: true); final PubspecYaml pubspecYaml = pubspecsByName[flutterPackage]; if (pubspecYaml == null) { - logger.printWarning( + logger.printError( "Unexpected package '$flutterPackage' found in packages directory", ); continue; diff --git a/packages/flutter_tools/lib/src/commands/upgrade.dart b/packages/flutter_tools/lib/src/commands/upgrade.dart index 3ed0cff563abe..f67689dedac0c 100644 --- a/packages/flutter_tools/lib/src/commands/upgrade.dart +++ b/packages/flutter_tools/lib/src/commands/upgrade.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:meta/meta.dart'; import '../base/common.dart'; @@ -10,8 +12,7 @@ import '../base/os.dart'; import '../base/process.dart'; import '../cache.dart'; import '../dart/pub.dart'; -import '../globals.dart' as globals; -import '../persistent_tool_state.dart'; +import '../globals_null_migrated.dart' as globals; import '../runner/flutter_command.dart'; import '../version.dart'; @@ -20,8 +21,8 @@ const String _flutterInstallDocs = 'https://flutter.dev/docs/get-started/install class UpgradeCommand extends FlutterCommand { UpgradeCommand({ - required bool verboseHelp, - UpgradeCommandRunner? commandRunner, + @required bool verboseHelp, + UpgradeCommandRunner commandRunner, }) : _commandRunner = commandRunner ?? UpgradeCommandRunner() { argParser @@ -69,7 +70,7 @@ class UpgradeCommand extends FlutterCommand { @override Future<FlutterCommandResult> runCommand() { - _commandRunner.workingDirectory = stringArg('working-directory') ?? Cache.flutterRoot!; + _commandRunner.workingDirectory = stringArg('working-directory') ?? Cache.flutterRoot; return _commandRunner.runCommand( force: boolArg('force'), continueFlow: boolArg('continue'), @@ -86,15 +87,15 @@ class UpgradeCommand extends FlutterCommand { @visibleForTesting class UpgradeCommandRunner { - String? workingDirectory; + String workingDirectory; Future<FlutterCommandResult> runCommand({ - required bool force, - required bool continueFlow, - required bool testFlow, - required GitTagVersion gitTagVersion, - required FlutterVersion flutterVersion, - required bool verifyOnly, + @required bool force, + @required bool continueFlow, + @required bool testFlow, + @required GitTagVersion gitTagVersion, + @required FlutterVersion flutterVersion, + @required bool verifyOnly, }) async { if (!continueFlow) { await runCommandFirstHalf( @@ -111,11 +112,11 @@ class UpgradeCommandRunner { } Future<void> runCommandFirstHalf({ - required bool force, - required GitTagVersion gitTagVersion, - required FlutterVersion flutterVersion, - required bool testFlow, - required bool verifyOnly, + @required bool force, + @required GitTagVersion gitTagVersion, + @required FlutterVersion flutterVersion, + @required bool testFlow, + @required bool verifyOnly, }) async { final FlutterVersion upstreamVersion = await fetchLatestVersion(localVersion: flutterVersion); if (flutterVersion.frameworkRevision == upstreamVersion.frameworkRevision) { @@ -171,11 +172,11 @@ class UpgradeCommandRunner { } void recordState(FlutterVersion flutterVersion) { - final Channel? channel = getChannelForName(flutterVersion.channel); + final Channel channel = getChannelForName(flutterVersion.channel); if (channel == null) { return; } - globals.persistentToolState!.updateLastActiveVersion(flutterVersion.frameworkRevision, channel); + globals.persistentToolState.updateLastActiveVersion(flutterVersion.frameworkRevision, channel); } Future<void> flutterUpgradeContinue() async { @@ -199,13 +200,12 @@ class UpgradeCommandRunner { // re-entrantly with the `--continue` flag Future<void> runCommandSecondHalf(FlutterVersion flutterVersion) async { // Make sure the welcome message re-display is delayed until the end. - final PersistentToolState persistentToolState = globals.persistentToolState!; - persistentToolState.setShouldRedisplayWelcomeMessage(false); + globals.persistentToolState.setShouldRedisplayWelcomeMessage(false); await precacheArtifacts(); await updatePackages(flutterVersion); await runDoctor(); // Force the welcome message to re-display following the upgrade. - persistentToolState.setShouldRedisplayWelcomeMessage(true); + globals.persistentToolState.setShouldRedisplayWelcomeMessage(true); } Future<bool> hasUncommittedChanges() async { @@ -235,8 +235,7 @@ class UpgradeCommandRunner { /// Exits tool if the tracking remote is not standard. void verifyStandardRemote(FlutterVersion localVersion) { // If repositoryUrl of the local version is null, exit - final String? repositoryUrl = localVersion.repositoryUrl; - if (repositoryUrl == null) { + if (localVersion.repositoryUrl == null) { throwToolExit( 'Unable to upgrade Flutter: The tool could not determine the remote ' 'upstream which is being tracked by the SDK.\n' @@ -245,7 +244,7 @@ class UpgradeCommandRunner { } // Strip `.git` suffix before comparing the remotes - final String trackingUrl = stripDotGit(repositoryUrl); + final String trackingUrl = stripDotGit(localVersion.repositoryUrl); final String flutterGitUrl = stripDotGit(globals.flutterGit); // Exempt the official flutter git SSH remote from this check @@ -288,18 +287,18 @@ class UpgradeCommandRunner { // URLs without ".git" suffix will remain unaffected. String stripDotGit(String url) { final RegExp pattern = RegExp(r'(.*)(\.git)$'); - final RegExpMatch? match = pattern.firstMatch(url); + final RegExpMatch match = pattern.firstMatch(url); if (match == null) { return url; } - return match.group(1)!; + return match.group(1); } /// Returns the remote HEAD flutter version. /// /// Exits tool if HEAD isn't pointing to a branch, or there is no upstream. Future<FlutterVersion> fetchLatestVersion({ - required FlutterVersion localVersion, + @required FlutterVersion localVersion, }) async { String revision; try { @@ -381,13 +380,14 @@ class UpgradeCommandRunner { Future<void> updatePackages(FlutterVersion flutterVersion) async { globals.printStatus(''); globals.printStatus(flutterVersion.toString()); - final String? projectRoot = findProjectRoot(globals.fs); + final String projectRoot = findProjectRoot(globals.fs); if (projectRoot != null) { globals.printStatus(''); await pub.get( context: PubContext.pubUpgrade, directory: projectRoot, upgrade: true, + generateSyntheticPackage: false, ); } } diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart index 5ffd602c0157b..f09cce3667bb7 100644 --- a/packages/flutter_tools/lib/src/compile.dart +++ b/packages/flutter_tools/lib/src/compile.dart @@ -167,10 +167,9 @@ List<String> buildModeOptions(BuildMode mode, List<String> dartDefines) { switch (mode) { case BuildMode.debug: return <String>[ - // These checks allow the CLI to override the value of this define for unit + '-Ddart.vm.profile=false', + // This allows the CLI to override the value of this define for unit // testing the framework. - if (!dartDefines.any((String define) => define.startsWith('dart.vm.profile'))) - '-Ddart.vm.profile=false', if (!dartDefines.any((String define) => define.startsWith('dart.vm.product'))) '-Ddart.vm.product=false', '--enable-asserts', diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index 2d8eede3c5ab4..33ffa3c5b3165 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -44,7 +44,7 @@ import 'flutter_features.dart'; import 'fuchsia/fuchsia_device.dart' show FuchsiaDeviceTools; import 'fuchsia/fuchsia_sdk.dart' show FuchsiaSdk, FuchsiaArtifacts; import 'fuchsia/fuchsia_workflow.dart' show FuchsiaWorkflow, fuchsiaWorkflow; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; import 'ios/ios_workflow.dart'; import 'ios/iproxy.dart'; import 'ios/simulators.dart'; @@ -204,7 +204,6 @@ Future<T> runInContext<T>( platform: globals.platform, featureFlags: featureFlags, ), - fuchsiaSdk: globals.fuchsiaSdk, operatingSystemUtils: globals.os, terminal: globals.terminal, customDevicesConfig: globals.customDevicesConfig, diff --git a/packages/flutter_tools/lib/src/custom_devices/custom_device.dart b/packages/flutter_tools/lib/src/custom_devices/custom_device.dart index 8373d2c882a1e..d5fff62f939c3 100644 --- a/packages/flutter_tools/lib/src/custom_devices/custom_device.dart +++ b/packages/flutter_tools/lib/src/custom_devices/custom_device.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'dart:async'; import 'package:meta/meta.dart'; @@ -54,11 +56,7 @@ class CustomDeviceLogReader extends DeviceLogReader { @override final String name; - @visibleForTesting - final StreamController<String> logLinesController = StreamController<String>.broadcast(); - - @visibleForTesting - final List<StreamSubscription<String>> subscriptions = <StreamSubscription<String>>[]; + final StreamController<String> _logLinesController = StreamController<String>.broadcast(); /// Listen to [process]' stdout and stderr, decode them using [SystemEncoding] /// and add each decoded line to [logLines]. @@ -71,17 +69,13 @@ class CustomDeviceLogReader extends DeviceLogReader { void listenToProcessOutput(Process process, {Encoding encoding = systemEncoding}) { final Converter<List<int>, String> decoder = encoding.decoder; - subscriptions.add( - process.stdout.transform<String>(decoder) - .transform<String>(const LineSplitter()) - .listen(logLinesController.add), - ); + process.stdout.transform<String>(decoder) + .transform<String>(const LineSplitter()) + .listen(_logLinesController.add); - subscriptions.add( - process.stderr.transform<String>(decoder) - .transform<String>(const LineSplitter()) - .listen(logLinesController.add) - ); + process.stderr.transform<String>(decoder) + .transform<String>(const LineSplitter()) + .listen(_logLinesController.add); } /// Add all lines emitted by [lines] to this [CustomDeviceLogReader]s [logLines] @@ -92,39 +86,29 @@ class CustomDeviceLogReader extends DeviceLogReader { /// /// Useful when you want to combine the contents of multiple log readers. void listenToLinesStream(Stream<String> lines) { - subscriptions.add( - lines.listen(logLinesController.add) - ); + _logLinesController.addStream(lines); } /// Dispose this log reader, freeing all associated resources and marking /// [logLines] as done. @override - Future<void> dispose() async { - final List<Future<void>> futures = <Future<void>>[]; - - for (final StreamSubscription<String> subscription in subscriptions) { - futures.add(subscription.cancel()); - } - - futures.add(logLinesController.close()); - - await Future.wait(futures); + void dispose() { + _logLinesController.close(); } @override - Stream<String> get logLines => logLinesController.stream; + Stream<String> get logLines => _logLinesController.stream; } /// A [DevicePortForwarder] that uses commands to forward / unforward a port. class CustomDevicePortForwarder extends DevicePortForwarder { CustomDevicePortForwarder({ - required String deviceName, - required List<String> forwardPortCommand, - required RegExp forwardPortSuccessRegex, - this.numTries, - required ProcessManager processManager, - required Logger logger, + @required String deviceName, + @required List<String> forwardPortCommand, + @required RegExp forwardPortSuccessRegex, + this.numTries/*?*/, + @required ProcessManager processManager, + @required Logger logger, Map<String, String> additionalReplacementValues = const <String, String>{} }) : _deviceName = deviceName, _forwardPortCommand = forwardPortCommand, @@ -141,17 +125,17 @@ class CustomDevicePortForwarder extends DevicePortForwarder { final RegExp _forwardPortSuccessRegex; final ProcessManager _processManager; final ProcessUtils _processUtils; - final int? numTries; + final int numTries; final Map<String, String> _additionalReplacementValues; final List<ForwardedPort> _forwardedPorts = <ForwardedPort>[]; @override Future<void> dispose() async { // copy the list so we don't modify it concurrently - await Future.wait(List<ForwardedPort>.of(_forwardedPorts).map(unforward)); + return Future.wait(List<ForwardedPort>.of(_forwardedPorts).map(unforward)); } - Future<ForwardedPort?> tryForward(int devicePort, int hostPort) async { + Future<ForwardedPort> tryForward(int devicePort, int hostPort) async { final List<String> interpolated = interpolateCommand( _forwardPortCommand, <String, String>{ @@ -164,7 +148,7 @@ class CustomDevicePortForwarder extends DevicePortForwarder { // launch the forwarding command final Process process = await _processUtils.start(interpolated); - final Completer<ForwardedPort?> completer = Completer<ForwardedPort?>(); + final Completer<ForwardedPort> completer = Completer<ForwardedPort>(); // read the outputs of the process, if we find a line that matches // the configs forwardPortSuccessRegex, we complete with a successfully @@ -189,26 +173,26 @@ class CustomDevicePortForwarder extends DevicePortForwarder { })); unawaited(completer.future.whenComplete(() { - unawaited(logLinesSubscription.cancel()); - unawaited(reader.dispose()); + logLinesSubscription.cancel(); + reader.dispose(); })); return completer.future; } @override - Future<int> forward(int devicePort, {int? hostPort}) async { + Future<int> forward(int devicePort, {int hostPort}) async { int actualHostPort = (hostPort == 0 || hostPort == null) ? devicePort : hostPort; int tries = 0; - while ((numTries == null) || (tries < numTries!)) { + while ((numTries == null) || (tries < numTries)) { // when the desired host port is already forwarded by this Forwarder, // choose another one while (_forwardedPorts.any((ForwardedPort port) => port.hostPort == actualHostPort)) { actualHostPort += 1; } - final ForwardedPort? port = await tryForward(devicePort, actualHostPort); + final ForwardedPort port = await tryForward(devicePort, actualHostPort); if (port != null) { _forwardedPorts.add(port); @@ -233,10 +217,7 @@ class CustomDevicePortForwarder extends DevicePortForwarder { // since a forwarded port represents a running process launched with // the forwardPortCommand, unforwarding is as easy as killing the process - final int? pid = forwardedPort.context?.pid; - if (pid != null) { - _processManager.killPid(pid); - } + _processManager.killPid(forwardedPort.context.pid); _forwardedPorts.remove(forwardedPort); } } @@ -248,11 +229,11 @@ class CustomDevicePortForwarder extends DevicePortForwarder { /// kill to stop the app, maybe other things in the future. class CustomDeviceAppSession { CustomDeviceAppSession({ - required this.name, - required CustomDevice device, - required ApplicationPackage appPackage, - required Logger logger, - required ProcessManager processManager + @required this.name, + @required CustomDevice device, + @required ApplicationPackage appPackage, + @required Logger logger, + @required ProcessManager processManager }) : _appPackage = appPackage, _device = device, _logger = logger, @@ -271,8 +252,8 @@ class CustomDeviceAppSession { final ProcessUtils _processUtils; final CustomDeviceLogReader logReader; - Process? _process; - int? _forwardedHostPort; + Process _process; + int _forwardedHostPort; /// Get the engine options for the given [debuggingOptions], /// [traceStartup] and [route]. @@ -280,8 +261,8 @@ class CustomDeviceAppSession { /// [debuggingOptions] and [route] can be null. /// /// For example, `_getEngineOptions(null, false, null)` will return - /// `['enable-dart-profiling=true']` - List<String> _getEngineOptions(DebuggingOptions debuggingOptions, bool traceStartup, String? route) { + /// `['enable-dart-profiling=true', 'enable-background-compilation=true']` + List<String> _getEngineOptions(DebuggingOptions debuggingOptions, bool traceStartup, String route) { final List<String> options = <String>[]; void addFlag(String value) { @@ -289,6 +270,7 @@ class CustomDeviceAppSession { } addFlag('enable-dart-profiling=true'); + addFlag('enable-background-compilation=true'); if (traceStartup) { addFlag('trace-startup=true'); @@ -362,8 +344,8 @@ class CustomDeviceAppSession { /// [debuggingOptions] and [route] can be null. /// /// For example, `_getEngineOptionsForCmdline(null, false, null)` will return - /// `--enable-dart-profiling=true` - String _getEngineOptionsForCmdline(DebuggingOptions debuggingOptions, bool traceStartup, String? route) { + /// `--enable-dart-profiling=true --enable-background-compilation=true` + String _getEngineOptionsForCmdline(DebuggingOptions debuggingOptions, bool traceStartup, String route) { return _getEngineOptions(debuggingOptions, traceStartup, route).map((String e) => '--$e').join(' '); } @@ -376,24 +358,22 @@ class CustomDeviceAppSession { /// [ipv6] may not be respected since it depends on the device config whether /// it uses ipv6 or ipv4 Future<LaunchResult> start({ - String? mainPath, - String? route, - required DebuggingOptions debuggingOptions, - Map<String, Object?> platformArgs = const <String, Object>{}, + String mainPath, + String route, + DebuggingOptions debuggingOptions, + Map<String, dynamic> platformArgs = const <String, dynamic>{}, bool prebuiltApplication = false, bool ipv6 = false, - String? userIdentifier + String userIdentifier }) async { - final bool traceStartup = platformArgs['trace-startup'] as bool? ?? false; - final String? packageName = _appPackage.name; - if (packageName == null) { - throw ToolExit('Could not start app, name for $_appPackage is unknown.'); - } + platformArgs ??= <String, dynamic>{}; + + final bool traceStartup = platformArgs['trace-startup'] as bool ?? false; final List<String> interpolated = interpolateCommand( _device._config.runDebugCommand, <String, String>{ 'remotePath': '/tmp/', - 'appName': packageName, + 'appName': _appPackage.name, 'engineOptions': _getEngineOptionsForCmdline(debuggingOptions, traceStartup, route) } ); @@ -416,11 +396,11 @@ class CustomDeviceAppSession { // in the same microtask AFAICT but this way we're on the safe side. logReader.listenToProcessOutput(process); - final Uri? observatoryUri = await discovery.uri; + final Uri observatoryUri = await discovery.uri; await discovery.cancel(); if (_device._config.usesPortForwarding) { - _forwardedHostPort = observatoryUri?.port; + _forwardedHostPort = observatoryUri.port; } return LaunchResult.succeeded(observatoryUri: observatoryUri); @@ -446,7 +426,7 @@ class CustomDeviceAppSession { } _maybeUnforwardPort(); - final bool result = _processManager.killPid(_process!.pid); + final bool result = _processManager.killPid(_process.pid); _process = null; return result; } @@ -454,11 +434,11 @@ class CustomDeviceAppSession { void dispose() { if (_process != null) { _maybeUnforwardPort(); - _processManager.killPid(_process!.pid); + _processManager.killPid(_process.pid); _process = null; } - unawaited(logReader.dispose()); + logReader.dispose(); } } @@ -467,9 +447,9 @@ class CustomDeviceAppSession { /// used to construct it. class CustomDevice extends Device { CustomDevice({ - required CustomDeviceConfig config, - required Logger logger, - required ProcessManager processManager, + @required CustomDeviceConfig config, + @required Logger logger, + @required ProcessManager processManager, }) : _config = config, _logger = logger, _processManager = processManager, @@ -481,8 +461,8 @@ class CustomDevice extends Device { portForwarder = config.usesPortForwarding ? CustomDevicePortForwarder( deviceName: config.label, - forwardPortCommand: config.forwardPortCommand!, - forwardPortSuccessRegex: config.forwardPortSuccessRegex!, + forwardPortCommand: config.forwardPortCommand, + forwardPortSuccessRegex: config.forwardPortSuccessRegex, processManager: processManager, logger: logger, ) : const NoOpDevicePortForwarder(), @@ -537,7 +517,7 @@ class CustomDevice extends Device { /// will be reported in the log using [_logger.printError]. If [timeout] /// is null, it's treated as if it's an infinite timeout. Future<bool> tryPing({ - Duration? timeout, + Duration timeout, Map<String, String> replacementValues = const <String, String>{} }) async { final List<String> interpolated = interpolateCommand( @@ -557,10 +537,9 @@ class CustomDevice extends Device { // If the user doesn't configure a ping success regex, any ping with exitCode zero // is good enough. Otherwise we check if either stdout or stderr have a match of // the pingSuccessRegex. - final RegExp? pingSuccessRegex = _config.pingSuccessRegex; - return pingSuccessRegex == null - || pingSuccessRegex.hasMatch(result.stdout) - || pingSuccessRegex.hasMatch(result.stderr); + return _config.pingSuccessRegex == null + || _config.pingSuccessRegex.hasMatch(result.stdout) + || _config.pingSuccessRegex.hasMatch(result.stderr); } /// Tries to execute the configs postBuild command using [appName] for the @@ -576,15 +555,15 @@ class CustomDevice extends Device { /// will be reported in the log using [_logger.printError]. If [timeout] /// is null, it's treated as if it's an infinite timeout. Future<bool> _tryPostBuild({ - required String appName, - required String localPath, - Duration? timeout, + @required String appName, + @required String localPath, + Duration timeout, Map<String, String> additionalReplacementValues = const <String, String>{} }) async { assert(_config.postBuildCommand != null); final List<String> interpolated = interpolateCommand( - _config.postBuildCommand!, + _config.postBuildCommand, <String, String>{ 'appName': appName, 'localPath': localPath @@ -614,8 +593,8 @@ class CustomDevice extends Device { /// will be reported in the log using [_logger.printError]. If [timeout] /// is null, it's treated as if it's an infinite timeout. Future<bool> tryUninstall({ - required String appName, - Duration? timeout, + @required String appName, + Duration timeout, Map<String, String> additionalReplacementValues = const <String, String>{} }) async { final List<String> interpolated = interpolateCommand( @@ -648,9 +627,9 @@ class CustomDevice extends Device { /// [appName] is the name of the app to be installed. Substituted for any occurrence /// of `${appName}` in the custom device configs `install` command. Future<bool> tryInstall({ - required String localPath, - required String appName, - Duration? timeout, + @required String localPath, + @required String appName, + Duration timeout, Map<String, String> additionalReplacementValues = const <String, String>{} }) async { final List<String> interpolated = interpolateCommand( @@ -687,11 +666,11 @@ class CustomDevice extends Device { } @override - Future<String?> get emulatorId async => null; + Future<String> get emulatorId async => null; @override FutureOr<DeviceLogReader> getLogReader({ - covariant ApplicationPackage? app, + covariant ApplicationPackage app, bool includePastLogs = false }) { if (app != null) { @@ -702,22 +681,21 @@ class CustomDevice extends Device { } @override - Future<bool> installApp(covariant ApplicationPackage app, {String? userIdentifier}) async { - final String? appName = app.name; - if (appName == null || !await tryUninstall(appName: appName)) { + Future<bool> installApp(covariant ApplicationPackage app, {String userIdentifier}) async { + if (!await tryUninstall(appName: app.name)) { return false; } final bool result = await tryInstall( localPath: getAssetBuildDirectory(), - appName: appName, + appName: app.name ); return result; } @override - Future<bool> isAppInstalled(covariant ApplicationPackage app, {String? userIdentifier}) async { + Future<bool> isAppInstalled(covariant ApplicationPackage app, {String userIdentifier}) async { return false; } @@ -739,7 +717,7 @@ class CustomDevice extends Device { } final List<String> interpolated = interpolateCommand( - _config.screenshotCommand!, + _config.screenshotCommand, <String, String>{}, ); @@ -771,14 +749,14 @@ class CustomDevice extends Device { @override Future<LaunchResult> startApp( covariant ApplicationPackage package, { - String? mainPath, - String? route, - required DebuggingOptions debuggingOptions, - Map<String, Object?> platformArgs = const <String, Object>{}, + String mainPath, + String route, + DebuggingOptions debuggingOptions, + Map<String, dynamic> platformArgs, bool prebuiltApplication = false, bool ipv6 = false, - String? userIdentifier, - BundleBuilder? bundleBuilder, + String userIdentifier, + BundleBuilder bundleBuilder }) async { if (!prebuiltApplication) { final String assetBundleDir = getAssetBuildDirectory(); @@ -796,12 +774,8 @@ class CustomDevice extends Device { // if we have a post build step (needed for some embedders), execute it if (_config.postBuildCommand != null) { - final String? packageName = package.name; - if (packageName == null) { - throw ToolExit('Could not start app, name for $package is unknown.'); - } await _tryPostBuild( - appName: packageName, + appName: package.name, localPath: assetBundleDir, ); } @@ -824,7 +798,7 @@ class CustomDevice extends Device { } @override - Future<bool> stopApp(covariant ApplicationPackage app, {String? userIdentifier}) { + Future<bool> stopApp(covariant ApplicationPackage app, {String userIdentifier}) { return _getOrCreateAppSession(app).stop(); } @@ -832,12 +806,8 @@ class CustomDevice extends Device { Future<TargetPlatform> get targetPlatform async => _config.platform ?? TargetPlatform.linux_arm64; @override - Future<bool> uninstallApp(covariant ApplicationPackage app, {String? userIdentifier}) async { - final String? appName = app.name; - if (appName == null) { - return false; - } - return tryUninstall(appName: appName); + Future<bool> uninstallApp(covariant ApplicationPackage app, {String userIdentifier}) { + return tryUninstall(appName: app.name); } } @@ -847,10 +817,10 @@ class CustomDevices extends PollingDeviceDiscovery { /// Create a custom device discovery that pings all enabled devices in the /// given [CustomDevicesConfig]. CustomDevices({ - required FeatureFlags featureFlags, - required ProcessManager processManager, - required Logger logger, - required CustomDevicesConfig config + @required FeatureFlags featureFlags, + @required ProcessManager processManager, + @required Logger logger, + @required CustomDevicesConfig config }) : _customDeviceWorkflow = CustomDeviceWorkflow( featureFlags: featureFlags, ), @@ -885,7 +855,7 @@ class CustomDevices extends PollingDeviceDiscovery { } @override - Future<List<Device>> pollingGetDevices({Duration? timeout}) async { + Future<List<Device>> pollingGetDevices({Duration timeout}) async { if (!canListAnything) { return const <Device>[]; } diff --git a/packages/flutter_tools/lib/src/daemon.dart b/packages/flutter_tools/lib/src/daemon.dart deleted file mode 100644 index d5be7380a93a1..0000000000000 --- a/packages/flutter_tools/lib/src/daemon.dart +++ /dev/null @@ -1,241 +0,0 @@ -// 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:async'; - -import 'base/common.dart'; -import 'base/io.dart'; -import 'base/logger.dart'; -import 'base/utils.dart'; -import 'convert.dart'; - -/// Parse binary streams in the JSON RPC format understood by the daemon, and -/// convert it into a stream of JSON RPC messages. -Stream<Map<String, Object?>> _convertInputStream(Stream<List<int>> inputStream) { - return utf8.decoder.bind(inputStream) - .transform<String>(const LineSplitter()) - .where((String line) => line.startsWith('[{') && line.endsWith('}]')) - .map<Map<String, Object?>?>((String line) { - line = line.substring(1, line.length - 1); - return castStringKeyedMap(json.decode(line)); - }) - .where((Map<String, Object?>? entry) => entry != null) - .cast<Map<String, Object?>>(); -} - -/// A stream that a [DaemonConnection] uses to communicate with each other. -abstract class DaemonStreams { - /// Stream that contains input to the [DaemonConnection]. - Stream<Map<String, Object?>> get inputStream; - - /// Outputs a message through the connection. - void send(Map<String, Object?> message); - - /// Cleans up any resources used. - Future<void> dispose() async { } -} - -/// A [DaemonStream] that uses stdin and stdout as the underlying streams. -class StdioDaemonStreams extends DaemonStreams { - StdioDaemonStreams(Stdio stdio) : - _stdio = stdio, - inputStream = _convertInputStream(stdio.stdin); - - final Stdio _stdio; - - @override - final Stream<Map<String, Object?>> inputStream; - - @override - void send(Map<String, Object?> message) { - _stdio.stdoutWrite( - '[${json.encode(message)}]\n', - fallback: (String message, Object? error, StackTrace stack) { - throwToolExit('Failed to write daemon command response to stdout: $error'); - }, - ); - } -} - -/// A [DaemonStream] that uses [Socket] as the underlying stream. -class TcpDaemonStreams extends DaemonStreams { - /// Creates a [DaemonStreams] with an existing [Socket]. - TcpDaemonStreams( - Socket socket, { - required Logger logger, - }): _logger = logger { - _socket = Future<Socket>.value(_initializeSocket(socket)); - } - - /// Connects to a remote host and creates a [DaemonStreams] from the socket. - TcpDaemonStreams.connect( - String host, - int port, { - required Logger logger, - }) : _logger = logger { - _socket = Socket.connect(host, port).then(_initializeSocket); - } - - late final Future<Socket> _socket; - final StreamController<Map<String, Object?>> _commands = StreamController<Map<String, Object?>>(); - final Logger _logger; - - @override - Stream<Map<String, Object?>> get inputStream => _commands.stream; - - @override - void send(Map<String, Object?> message) { - _socket.then((Socket socket) { - try { - socket.write('[${json.encode(message)}]\n'); - } on SocketException catch (error) { - _logger.printError('Failed to write daemon command response to socket: $error'); - // Failed to send, close the connection - socket.close(); - } - }); - } - - Socket _initializeSocket(Socket socket) { - _commands.addStream(_convertInputStream(socket)); - return socket; - } - - @override - Future<void> dispose() async { - await (await _socket).close(); - } -} - -/// Connection between a flutter daemon and a client. -class DaemonConnection { - DaemonConnection({ - required DaemonStreams daemonStreams, - required Logger logger, - }): _logger = logger, - _daemonStreams = daemonStreams { - _commandSubscription = daemonStreams.inputStream.listen( - _handleData, - onError: (Object error, StackTrace stackTrace) { - // We have to listen for on error otherwise the error on the socket - // will end up in the Zone error handler. - // Do nothing here and let the stream close handlers handle shutting - // down the daemon. - } - ); - } - - final DaemonStreams _daemonStreams; - - final Logger _logger; - - late final StreamSubscription<Map<String, Object?>> _commandSubscription; - - int _outgoingRequestId = 0; - final Map<String, Completer<Object?>> _outgoingRequestCompleters = <String, Completer<Object?>>{}; - - final StreamController<Map<String, Object?>> _events = StreamController<Map<String, Object?>>.broadcast(); - final StreamController<Map<String, Object?>> _incomingCommands = StreamController<Map<String, Object?>>(); - - /// A stream that contains all the incoming requests. - Stream<Map<String, Object?>> get incomingCommands => _incomingCommands.stream; - - /// Listens to the event with the event name [eventToListen]. - Stream<Object?> listenToEvent(String eventToListen) { - return _events.stream - .where((Map<String, Object?> event) => event['event'] == eventToListen) - .map<Object?>((Map<String, Object?> event) => event['params']); - } - - /// Sends a request to the other end of the connection. - /// - /// Returns a [Future] that resolves with the content. - Future<Object?> sendRequest(String method, [Object? params]) async { - final String id = '${++_outgoingRequestId}'; - final Completer<Object?> completer = Completer<Object?>(); - _outgoingRequestCompleters[id] = completer; - final Map<String, Object?> data = <String, Object?>{ - 'id': id, - 'method': method, - if (params != null) 'params': params, - }; - _logger.printTrace('-> Sending to daemon, id = $id, method = $method'); - _daemonStreams.send(data); - return completer.future; - } - - /// Sends a response to the other end of the connection. - void sendResponse(Object id, [Object? result]) { - _daemonStreams.send(<String, Object?>{ - 'id': id, - if (result != null) 'result': result, - }); - } - - /// Sends an error response to the other end of the connection. - void sendErrorResponse(Object id, Object error, StackTrace trace) { - _daemonStreams.send(<String, Object?>{ - 'id': id, - 'error': error, - 'trace': '$trace', - }); - } - - /// Sends an event to the client. - void sendEvent(String name, [ Object? params ]) { - _daemonStreams.send(<String, Object?>{ - 'event': name, - if (params != null) 'params': params, - }); - } - - /// Handles the input from the stream. - /// - /// There are three kinds of data: Request, Response, Event. - /// - /// Request: - /// {"id": <Object>. "method": <String>, "params": <optional, Object?>} - /// - /// Response: - /// {"id": <Object>. "result": <optional, Object?>} for a successful response. - /// {"id": <Object>. "error": <Object>, "stackTrace": <String>} for an error response. - /// - /// Event: - /// {"event": <String>. "params": <optional, Object?>} - void _handleData(Map<String, Object?> data) { - if (data['id'] != null) { - if (data['method'] == null) { - // This is a response to previously sent request. - final String id = data['id']! as String; - if (data['error'] != null) { - // This is an error response. - _logger.printTrace('<- Error response received from daemon, id = $id'); - final Object error = data['error']!; - final String stackTrace = data['stackTrace'] as String? ?? ''; - _outgoingRequestCompleters.remove(id)?.completeError(error, StackTrace.fromString(stackTrace)); - } else { - _logger.printTrace('<- Response received from daemon, id = $id'); - final Object? result = data['result']; - _outgoingRequestCompleters.remove(id)?.complete(result); - } - } else { - _incomingCommands.add(data); - } - } else if (data['event'] != null) { - // This is an event - _logger.printTrace('<- Event received: ${data['event']}'); - _events.add(data); - } else { - _logger.printError('Unknown data received from daemon'); - } - } - - /// Cleans up any resources used in the connection. - Future<void> dispose() async { - await _commandSubscription.cancel(); - await _daemonStreams.dispose(); - unawaited(_events.close()); - unawaited(_incomingCommands.close()); - } -} diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart index 174458af5c0a8..1a0e5027967c2 100644 --- a/packages/flutter_tools/lib/src/dart/pub.dart +++ b/packages/flutter_tools/lib/src/dart/pub.dart @@ -101,7 +101,7 @@ abstract class Pub { bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, - String? flutterRootOverride, + String flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, bool printProgress = true, @@ -135,7 +135,7 @@ abstract class Pub { /// stdout/stderr stream of pub to the corresponding streams of this process. Future<void> interactively( List<String> arguments, { - String? directory, + String directory, required io.Stdio stdio, bool touchesPackageConfig = false, bool generateSyntheticPackage = false, diff --git a/packages/flutter_tools/lib/src/debug_adapters/README.md b/packages/flutter_tools/lib/src/debug_adapters/README.md index 7aa0b6e0df5bb..82ae0f77c2071 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/README.md +++ b/packages/flutter_tools/lib/src/debug_adapters/README.md @@ -34,9 +34,9 @@ Arguments specific to `launchRequest` are: - `bool? noDebug` - whether to run in debug or noDebug mode (if not supplied, defaults to debug) - `String program` - the path of the Flutter application to run - `List<String>? args` - arguments to be passed to the Flutter program -- `List<String>? toolArgs` - arguments for the `flutter run` or `flutter test` commands -- `String? customTool` - an optional tool to run instead of `flutter` - the custom tool must be completely compatible with the tool/command it is replacing -- `int? customToolReplacesArgs` - the number of arguments to delete from the beginning of the argument list when invoking `customTool` - e.g. setting `customTool` to `flutter_test_wrapper` and `customToolReplacesArgs` to `1` for a test run would invoke `flutter_test_wrapper foo_test.dart` instead of `flutter test foo_test.dart` (if larger than the number of computed arguments all arguments will be removed, if not supplied will default to `0`) +- `List<String>? toolArgs` - arguments for the `flutter` tool +- `String? console` - if set to `"terminal"` or `"externalTerminal"` will be run using the `runInTerminal` reverse-request; otherwise the debug adapter spawns the Dart process +- `bool? enableAsserts` - whether to enable asserts (if not supplied, defaults to `true`) `attachRequest` is not currently supported, but will be documented here when it is. @@ -66,19 +66,4 @@ Some custom requests are available for clients to call. Below are the Flutter-sp ## Custom Events -The debug adapter may emit several custom events that are useful to clients. Below are the Flutter-specific custom events, and the standard Dart DAP custom events are [documented here](https://github.com/dart-lang/sdk/blob/main/pkg/dds/tool/dap/README.md#custom-events). - -### `flutter.serviceExtensionStateChanged` - -When the value of a Flutter service extension changes, this event is emitted and includes the new value. Values are always encoded as strings, even if numeric/boolean. - -``` -{ - "type": "event", - "event": "flutter.serviceExtensionStateChanged", - "body": { - "extension": "ext.flutter.debugPaint", - "value": "true", - } -} -``` +The debug adapter may emit several custom events that are useful to clients. There are not currently any custom Flutter events, but the standard Dart DAP custom requests are [documented here](https://github.com/dart-lang/sdk/blob/main/pkg/dds/tool/dap/README.md#custom-events). diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart index e74c1a79555cc..27b1615249849 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart @@ -3,10 +3,8 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:math' as math; import 'package:dds/dap.dart' hide PidTracker, PackageConfigUtils; -import 'package:meta/meta.dart'; import 'package:vm_service/vm_service.dart' as vm; import '../base/file_system.dart'; @@ -50,11 +48,10 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments parseAttachArgs = FlutterAttachRequestArguments.fromJson; /// A completer that completes when the app.started event has been received. - @visibleForTesting - final Completer<void> appStartedCompleter = Completer<void>(); + final Completer<void> _appStartedCompleter = Completer<void>(); /// Whether or not the app.started event has been received. - bool get _receivedAppStarted => appStartedCompleter.isCompleted; + bool get _receivedAppStarted => _appStartedCompleter.isCompleted; /// The VM Service URI received from the app.debugPort event. Uri? _vmServiceUri; @@ -148,21 +145,6 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments terminatePids(ProcessSignal.sigkill); } - @override - Future<void> handleExtensionEvent(vm.Event event) async { - await super.handleExtensionEvent(event); - - switch (event.kind) { - case vm.EventKind.kExtension: - switch (event.extensionKind) { - case 'Flutter.ServiceExtensionStateChanged': - _sendServiceExtensionStateChanged(event.extensionData); - break; - } - break; - } - } - /// Called by [launchRequest] to request that we actually start the app to be run/debugged. /// /// For debugging, this should start paused, connect to the VM Service, set @@ -170,6 +152,7 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments @override Future<void> launchImpl() async { final FlutterLaunchRequestArguments args = this.args as FlutterLaunchRequestArguments; + final String flutterToolPath = fileSystem.path.join(Cache.flutterRoot!, 'bin', platform.isWindows ? 'flutter.bat' : 'flutter'); // "debug"/"noDebug" refers to the DAP "debug" mode and not the Flutter // debug mode (vs Profile/Release). It is possible for the user to "Run" @@ -183,14 +166,6 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments '--machine', if (debug) '--start-paused', ]; - - // Handle customTool and deletion of any arguments for it. - final String executable = args.customTool ?? fileSystem.path.join(Cache.flutterRoot!, 'bin', platform.isWindows ? 'flutter.bat' : 'flutter'); - final int? removeArgs = args.customToolReplacesArgs; - if (args.customTool != null && removeArgs != null) { - toolArgs.removeRange(0, math.min(removeArgs, toolArgs.length)); - } - final List<String> processArgs = <String>[ ...toolArgs, ...?args.toolArgs, @@ -220,21 +195,9 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments } } - await launchAsProcess(executable, processArgs); - - // Delay responding until the app is launched and (optionally) the debugger - // is connected. - await appStartedCompleter.future; - if (debug) { - await debuggerInitialized; - } - } - - @visibleForOverriding - Future<void> launchAsProcess(String executable, List<String> processArgs) async { - logger?.call('Spawning $executable with $processArgs in ${args.cwd}'); + logger?.call('Spawning $flutterToolPath with $processArgs in ${args.cwd}'); final Process process = await Process.start( - executable, + flutterToolPath, processArgs, workingDirectory: args.cwd, ); @@ -244,6 +207,13 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments process.stdout.transform(ByteToLineTransformer()).listen(_handleStdout); process.stderr.listen(_handleStderr); unawaited(process.exitCode.then(_handleExitCode)); + + // Delay responding until the app is launched and (optionally) the debugger + // is connected. + await _appStartedCompleter.future; + if (debug) { + await debuggerInitialized; + } } /// restart is called by the client when the user invokes a restart (for example with the button on the debug toolbar). @@ -322,7 +292,7 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments /// Handles the app.started event from Flutter. void _handleAppStarted() { - appStartedCompleter.complete(); + _appStartedCompleter.complete(); _connectDebuggerIfReady(); } @@ -475,14 +445,4 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments sendOutput('console', 'Failed to $action: $error'); } } - - void _sendServiceExtensionStateChanged(vm.ExtensionData? extensionData) { - final Map<String, dynamic>? data = extensionData?.data; - if (data != null) { - sendEvent( - RawEventBody(data), - eventType: 'flutter.serviceExtensionStateChanged', - ); - } - } } diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter_args.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter_args.dart index b5c15a29b53e1..ddd67b714979d 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter_args.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter_args.dart @@ -54,8 +54,6 @@ class FlutterLaunchRequestArguments required this.program, this.args, this.toolArgs, - this.customTool, - this.customToolReplacesArgs, Object? restart, String? name, String? cwd, @@ -82,8 +80,6 @@ class FlutterLaunchRequestArguments program = obj['program'] as String?, args = (obj['args'] as List<Object?>?)?.cast<String>(), toolArgs = (obj['toolArgs'] as List<Object?>?)?.cast<String>(), - customTool = obj['customTool'] as String?, - customToolReplacesArgs = obj['customToolReplacesArgs'] as int?, super.fromMap(obj); /// If noDebug is true the launch request should launch the program without enabling debugging. @@ -99,24 +95,6 @@ class FlutterLaunchRequestArguments /// Arguments to be passed to the tool that will run [program] (for example, the VM or Flutter tool). final List<String>? toolArgs; - /// An optional tool to run instead of "flutter". - /// - /// In combination with [customToolReplacesArgs] allows invoking a custom - /// tool instead of "flutter" to launch scripts/tests. The custom tool must be - /// completely compatible with the tool/command it is replacing. - /// - /// This field should be a full absolute path if the tool may not be available - /// in `PATH`. - final String? customTool; - - /// The number of arguments to delete from the beginning of the argument list - /// when invoking [customTool]. - /// - /// For example, setting [customTool] to `flutter_test_wrapper` and - /// `customToolReplacesArgs` to `1` for a test run would invoke - /// `flutter_test_wrapper foo_test.dart` instead of `flutter test foo_test.dart`. - final int? customToolReplacesArgs; - @override Map<String, Object?> toJson() => <String, Object?>{ ...super.toJson(), @@ -124,8 +102,6 @@ class FlutterLaunchRequestArguments if (program != null) 'program': program, if (args != null) 'args': args, if (toolArgs != null) 'toolArgs': toolArgs, - if (customTool != null) 'customTool': customTool, - if (customToolReplacesArgs != null) 'customToolReplacesArgs': customToolReplacesArgs, }; static FlutterLaunchRequestArguments fromJson(Map<String, Object?> obj) => diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart index 8613f563daea6..215195473392d 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart @@ -3,10 +3,8 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:math' as math; import 'package:dds/dap.dart' hide PidTracker, PackageConfigUtils; -import 'package:meta/meta.dart'; import 'package:vm_service/vm_service.dart' as vm; import '../base/file_system.dart'; @@ -92,6 +90,7 @@ class FlutterTestDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArgum @override Future<void> launchImpl() async { final FlutterLaunchRequestArguments args = this.args as FlutterLaunchRequestArguments; + final String flutterToolPath = fileSystem.path.join(Cache.flutterRoot!, 'bin', platform.isWindows ? 'flutter.bat' : 'flutter'); final bool debug = !(args.noDebug ?? false); final String? program = args.program; @@ -101,14 +100,6 @@ class FlutterTestDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArgum '--machine', if (debug) '--start-paused', ]; - - // Handle customTool and deletion of any arguments for it. - final String executable = args.customTool ?? fileSystem.path.join(Cache.flutterRoot!, 'bin', platform.isWindows ? 'flutter.bat' : 'flutter'); - final int? removeArgs = args.customToolReplacesArgs; - if (args.customTool != null && removeArgs != null) { - toolArgs.removeRange(0, math.min(removeArgs, toolArgs.length)); - } - final List<String> processArgs = <String>[ ...toolArgs, ...?args.toolArgs, @@ -135,19 +126,9 @@ class FlutterTestDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArgum } } - await launchAsProcess(executable, processArgs); - - // Delay responding until the debugger is connected. - if (debug) { - await debuggerInitialized; - } - } - - @visibleForOverriding - Future<void> launchAsProcess(String executable, List<String> processArgs) async { - logger?.call('Spawning $executable with $processArgs in ${args.cwd}'); + logger?.call('Spawning $flutterToolPath with $processArgs in ${args.cwd}'); final Process process = await Process.start( - executable, + flutterToolPath, processArgs, workingDirectory: args.cwd, ); @@ -157,6 +138,11 @@ class FlutterTestDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArgum process.stdout.transform(ByteToLineTransformer()).listen(_handleStdout); process.stderr.listen(_handleStderr); unawaited(process.exitCode.then(_handleExitCode)); + + // Delay responding until the debugger is connected. + if (debug) { + await debuggerInitialized; + } } /// Called by [terminateRequest] to request that we gracefully shut down the app being run (or in the case of an attach, disconnect). diff --git a/packages/flutter_tools/lib/src/desktop_device.dart b/packages/flutter_tools/lib/src/desktop_device.dart index e3eae9e6db8b4..c9f7e1de5d7b1 100644 --- a/packages/flutter_tools/lib/src/desktop_device.dart +++ b/packages/flutter_tools/lib/src/desktop_device.dart @@ -235,6 +235,7 @@ abstract class DesktopDevice extends Device { } addFlag('enable-dart-profiling=true'); + addFlag('enable-background-compilation=true'); if (traceStartup) { addFlag('trace-startup=true'); diff --git a/packages/flutter_tools/lib/src/devfs.dart b/packages/flutter_tools/lib/src/devfs.dart index 0fd9cba37b9a0..e8670eb92df99 100644 --- a/packages/flutter_tools/lib/src/devfs.dart +++ b/packages/flutter_tools/lib/src/devfs.dart @@ -616,12 +616,6 @@ class DevFS { }); if (bundle != null) { - // Mark processing of bundle started for testability of starting the compile - // before processing bundle. - _logger.printTrace('Processing bundle.'); - // await null to give time for telling the compiler to compile. - await null; - // The tool writes the assets into the AssetBundle working dir so that they // are in the same location in DevFS and the iOS simulator. final String assetBuildDirPrefix = _asUriPath(getAssetBuildDirectory()); @@ -642,10 +636,6 @@ class DevFS { assetPathsToEvict.add(archivePath); } }); - - // Mark processing of bundle done for testability of starting the compile - // before processing bundle. - _logger.printTrace('Bundle processing done.'); } final CompilerOutput? compilerOutput = await pendingCompilerOutput; if (compilerOutput == null || compilerOutput.errorCount > 0) { diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index 3a9d229d03357..5b691193a2f70 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -490,7 +490,7 @@ abstract class Device { /// Specify [userIdentifier] to check if installed for a particular user (Android only). Future<bool> isAppInstalled( covariant ApplicationPackage app, { - String? userIdentifier, + String userIdentifier, }); /// Check if the latest build of the [app] is already installed. @@ -635,9 +635,9 @@ abstract class Device { @override String toString() => name; - static Future<List<String>> descriptions(List<Device> devices) async { + static Stream<String> descriptions(List<Device> devices) async* { if (devices.isEmpty) { - return const <String>[]; + return; } // Extract device information @@ -665,14 +665,13 @@ abstract class Device { } // Join columns into lines of text - return <String>[ - for (final List<String> row in table) - indices.map<String>((int i) => row[i].padRight(widths[i])).followedBy(<String>[row.last]).join(' • '), - ]; + for (final List<String> row in table) { + yield indices.map<String>((int i) => row[i].padRight(widths[i])).followedBy(<String>[row.last]).join(' • '); + } } static Future<void> printDevices(List<Device> devices, Logger logger) async { - (await descriptions(devices)).forEach(logger.printStatus); + await descriptions(devices).forEach(logger.printStatus); } static List<String> devicesPlatformTypes(List<Device> devices) { diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index a110b92b1726e..67f2ecac9ff7a 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:meta/meta.dart'; import 'package:process/process.dart'; import 'android/android_studio_validator.dart'; @@ -11,7 +10,6 @@ import 'artifacts.dart'; import 'base/async_guard.dart'; import 'base/context.dart'; import 'base/file_system.dart'; -import 'base/io.dart'; import 'base/logger.dart'; import 'base/os.dart'; import 'base/platform.dart'; @@ -23,8 +21,7 @@ import 'device.dart'; import 'doctor_validator.dart'; import 'features.dart'; import 'fuchsia/fuchsia_workflow.dart'; -import 'globals.dart' as globals; -import 'http_host_validator.dart'; +import 'globals_null_migrated.dart' as globals; import 'intellij/intellij_validator.dart'; import 'linux/linux_doctor.dart'; import 'linux/linux_workflow.dart'; @@ -94,7 +91,6 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider { fileSystem: globals.fs, platform: globals.platform, flutterVersion: () => globals.flutterVersion, - devToolsVersion: () => globals.cache.devToolsVersion, processManager: globals.processManager, userMessages: userMessages, artifacts: globals.artifacts!, @@ -135,11 +131,6 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider { deviceManager: globals.deviceManager, userMessages: globals.userMessages, ), - HttpHostValidator( - platform: globals.platform, - featureFlags: featureFlags, - httpClient: globals.httpClientFactory?.call() ?? HttpClient(), - ), ]; return _validators!; } @@ -291,17 +282,11 @@ class Doctor { } /// Print information about the state of installed tooling. - /// - /// To exclude personally identifiable information like device names and - /// paths, set [showPii] to false. Future<bool> diagnose({ bool androidLicenses = false, bool verbose = true, bool showColor = true, AndroidLicenseValidator? androidLicenseValidator, - bool showPii = true, - List<ValidatorTask>? startedValidatorTasks, - bool sendEvent = true, }) async { if (androidLicenses && androidLicenseValidator != null) { return androidLicenseValidator.runLicenseManager(); @@ -313,7 +298,7 @@ class Doctor { bool doctorResult = true; int issues = 0; - for (final ValidatorTask validatorTask in startedValidatorTasks ?? startValidatorTasks()) { + for (final ValidatorTask validatorTask in startValidatorTasks()) { final DoctorValidator validator = validatorTask.validator; final Status status = _logger.startSpinner(); ValidationResult result; @@ -341,9 +326,8 @@ class Doctor { case ValidationType.installed: break; } - if (sendEvent) { - DoctorResultEvent(validator: validator, result: result).send(); - } + + DoctorResultEvent(validator: validator, result: result).send(); final String leadingBox = showColor ? result.coloredLeadingBox : result.leadingBox; if (result.statusInfo != null) { @@ -359,7 +343,7 @@ class Doctor { int hangingIndent = 2; int indent = 4; final String indicator = showColor ? message.coloredIndicator : message.indicator; - for (final String line in '$indicator ${showPii ? message.message : message.piiStrippedMessage}'.split('\n')) { + for (final String line in '$indicator ${message.message}'.split('\n')) { _logger.printStatus(line, hangingIndent: hangingIndent, indent: indent, emphasis: true); // Only do hanging indent for the first line. hangingIndent = 0; @@ -410,7 +394,6 @@ class FlutterValidator extends DoctorValidator { FlutterValidator({ required Platform platform, required FlutterVersion Function() flutterVersion, - required String Function() devToolsVersion, required UserMessages userMessages, required FileSystem fileSystem, required Artifacts artifacts, @@ -418,7 +401,6 @@ class FlutterValidator extends DoctorValidator { required String Function() flutterRoot, required OperatingSystemUtils operatingSystemUtils, }) : _flutterVersion = flutterVersion, - _devToolsVersion = devToolsVersion, _platform = platform, _userMessages = userMessages, _fileSystem = fileSystem, @@ -430,7 +412,6 @@ class FlutterValidator extends DoctorValidator { final Platform _platform; final FlutterVersion Function() _flutterVersion; - final String Function() _devToolsVersion; final String Function() _flutterRoot; final UserMessages _userMessages; final FileSystem _fileSystem; @@ -465,7 +446,6 @@ class FlutterValidator extends DoctorValidator { ))); messages.add(ValidationMessage(_userMessages.engineRevision(version.engineRevisionShort))); messages.add(ValidationMessage(_userMessages.dartRevision(version.dartSdkVersion))); - messages.add(ValidationMessage(_userMessages.devToolsVersion(_devToolsVersion()))); final String? pubUrl = _platform.environment['PUB_HOSTED_URL']; if (pubUrl != null) { messages.add(ValidationMessage(_userMessages.pubMirrorURL(pubUrl))); @@ -535,7 +515,7 @@ class DeviceValidator extends DoctorValidator { final List<Device> devices = await _deviceManager.getAllConnectedDevices(); List<ValidationMessage> installedMessages = <ValidationMessage>[]; if (devices.isNotEmpty) { - installedMessages = (await Device.descriptions(devices)) + installedMessages = await Device.descriptions(devices) .map<ValidationMessage>((String msg) => ValidationMessage(msg)).toList(); } @@ -565,34 +545,3 @@ class DeviceValidator extends DoctorValidator { } } } - -/// Wrapper for doctor to run multiple times with PII and without, running the validators only once. -class DoctorText { - DoctorText( - BufferLogger logger, { - @visibleForTesting Doctor? doctor, - }) : _doctor = doctor ?? Doctor(logger: logger), _logger = logger; - - final BufferLogger _logger; - final Doctor _doctor; - bool _sendDoctorEvent = true; - - late final Future<String> text = _runDiagnosis(true); - late final Future<String> piiStrippedText = _runDiagnosis(false); - - // Start the validator tasks only once. - late final List<ValidatorTask> _validatorTasks = _doctor.startValidatorTasks(); - - Future<String> _runDiagnosis(bool showPii) async { - try { - await _doctor.diagnose(showColor: false, startedValidatorTasks: _validatorTasks, showPii: showPii, sendEvent: _sendDoctorEvent); - // Do not send the doctor event a second time. - _sendDoctorEvent = false; - final String text = _logger.statusText; - _logger.clear(); - return text; - } on Exception catch (error, trace) { - return 'encountered exception: $error\n\n${trace.toString().trim()}\n'; - } - } -} diff --git a/packages/flutter_tools/lib/src/doctor_validator.dart b/packages/flutter_tools/lib/src/doctor_validator.dart index 6530b5fd37948..634275800ebb3 100644 --- a/packages/flutter_tools/lib/src/doctor_validator.dart +++ b/packages/flutter_tools/lib/src/doctor_validator.dart @@ -6,7 +6,7 @@ import 'package:meta/meta.dart'; import 'base/async_guard.dart'; import 'base/terminal.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; class ValidatorTask { ValidatorTask(this.validator, this.result); @@ -221,27 +221,22 @@ class ValidationMessage { /// /// The [contextUrl] may be supplied to link to external resources. This /// is displayed after the informative message in verbose modes. - const ValidationMessage(this.message, { this.contextUrl, String? piiStrippedMessage }) - : type = ValidationMessageType.information, piiStrippedMessage = piiStrippedMessage ?? message; + const ValidationMessage(this.message, {this.contextUrl}) : type = ValidationMessageType.information; /// Create a validation message with information for a failing validator. - const ValidationMessage.error(this.message, { String? piiStrippedMessage }) + const ValidationMessage.error(this.message) : type = ValidationMessageType.error, - piiStrippedMessage = piiStrippedMessage ?? message, contextUrl = null; /// Create a validation message with information for a partially failing /// validator. - const ValidationMessage.hint(this.message, { String? piiStrippedMessage }) + const ValidationMessage.hint(this.message) : type = ValidationMessageType.hint, - piiStrippedMessage = piiStrippedMessage ?? message, contextUrl = null; final ValidationMessageType type; final String? contextUrl; final String message; - /// Optional message with PII stripped, to show instead of [message]. - final String piiStrippedMessage; bool get isError => type == ValidationMessageType.error; @@ -290,8 +285,7 @@ class NoIdeValidator extends DoctorValidator { @override Future<ValidationResult> validate() async { return ValidationResult( - // Info hint to user they do not have a supported IDE installed - ValidationType.notAvailable, + ValidationType.missing, globals.userMessages.noIdeInstallationInfo.map((String ideInfo) => ValidationMessage(ideInfo)).toList(), statusInfo: globals.userMessages.noIdeStatusInfo, ); diff --git a/packages/flutter_tools/lib/src/drive/web_driver_service.dart b/packages/flutter_tools/lib/src/drive/web_driver_service.dart index fb596428894a6..22ab5de40efb9 100644 --- a/packages/flutter_tools/lib/src/drive/web_driver_service.dart +++ b/packages/flutter_tools/lib/src/drive/web_driver_service.dart @@ -19,7 +19,7 @@ import '../base/process.dart'; import '../build_info.dart'; import '../convert.dart'; import '../device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../resident_runner.dart'; import '../web/web_runner.dart'; diff --git a/packages/flutter_tools/lib/src/emulator.dart b/packages/flutter_tools/lib/src/emulator.dart index c65520ed8d846..557c86b415710 100644 --- a/packages/flutter_tools/lib/src/emulator.dart +++ b/packages/flutter_tools/lib/src/emulator.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'dart:math' as math; import 'package:meta/meta.dart'; @@ -17,16 +19,16 @@ import 'base/process.dart'; import 'device.dart'; import 'ios/ios_emulators.dart'; -EmulatorManager? get emulatorManager => context.get<EmulatorManager>(); +EmulatorManager get emulatorManager => context.get<EmulatorManager>(); /// A class to get all available emulators. class EmulatorManager { EmulatorManager({ - AndroidSdk? androidSdk, - required Logger logger, - required ProcessManager processManager, - required AndroidWorkflow androidWorkflow, - required FileSystem fileSystem, + @required AndroidSdk androidSdk, + @required Logger logger, + @required ProcessManager processManager, + @required AndroidWorkflow androidWorkflow, + @required FileSystem fileSystem, }) : _androidSdk = androidSdk, _processUtils = ProcessUtils(logger: logger, processManager: processManager), _androidEmulators = AndroidEmulators( @@ -39,7 +41,7 @@ class EmulatorManager { _emulatorDiscoverers.add(_androidEmulators); } - final AndroidSdk? _androidSdk; + final AndroidSdk _androidSdk; final AndroidEmulators _androidEmulators; final ProcessUtils _processUtils; @@ -53,19 +55,14 @@ class EmulatorManager { final List<Emulator> emulators = await getAllAvailableEmulators(); searchText = searchText.toLowerCase(); bool exactlyMatchesEmulatorId(Emulator emulator) => - emulator.id.toLowerCase() == searchText || - emulator.name.toLowerCase() == searchText; + emulator.id?.toLowerCase() == searchText || + emulator.name?.toLowerCase() == searchText; bool startsWithEmulatorId(Emulator emulator) => - emulator.id.toLowerCase().startsWith(searchText) == true || - emulator.name.toLowerCase().startsWith(searchText) == true; - - Emulator? exactMatch; - for (final Emulator emulator in emulators) { - if (exactlyMatchesEmulatorId(emulator)) { - exactMatch = emulator; - break; - } - } + emulator.id?.toLowerCase()?.startsWith(searchText) == true || + emulator.name?.toLowerCase()?.startsWith(searchText) == true; + + final Emulator exactMatch = + emulators.firstWhere(exactlyMatchesEmulatorId, orElse: () => null); if (exactMatch != null) { return <Emulator>[exactMatch]; } @@ -88,7 +85,7 @@ class EmulatorManager { } /// Return the list of all available emulators. - Future<CreateEmulatorResult> createEmulator({ String? name }) async { + Future<CreateEmulatorResult> createEmulator({ String name }) async { if (name == null || name.isEmpty) { const String autoName = 'flutter_emulator'; // Don't use getEmulatorsMatching here, as it will only return one @@ -105,23 +102,21 @@ class EmulatorManager { name = '${autoName}_${++suffix}'; } } - final String emulatorName = name!; - final String? avdManagerPath = _androidSdk?.avdManagerPath; - if (avdManagerPath == null || !_androidEmulators.canLaunchAnything) { - return CreateEmulatorResult(emulatorName, + if (!_androidEmulators.canLaunchAnything) { + return CreateEmulatorResult(name, success: false, error: 'avdmanager is missing from the Android SDK' ); } - final String? device = await _getPreferredAvailableDevice(avdManagerPath); + final String device = await _getPreferredAvailableDevice(); if (device == null) { - return CreateEmulatorResult(emulatorName, + return CreateEmulatorResult(name, success: false, error: 'No device definitions are available'); } - final String? sdkId = await _getPreferredSdkId(avdManagerPath); + final String sdkId = await _getPreferredSdkId(); if (sdkId == null) { - return CreateEmulatorResult(emulatorName, + return CreateEmulatorResult(name, success: false, error: 'No suitable Android AVD system images are available. You may need to install these' @@ -133,7 +128,7 @@ class EmulatorManager { // to flutter users. Specifically: // - Removes lines that say "null" (!) // - Removes lines that tell the user to use '--force' to overwrite emulators - String? cleanError(String? error) { + String cleanError(String error) { if (error == null || error.trim() == '') { return null; } @@ -146,16 +141,16 @@ class EmulatorManager { .trim(); } final RunResult runResult = await _processUtils.run(<String>[ - avdManagerPath, + _androidSdk?.avdManagerPath, 'create', 'avd', - '-n', emulatorName, + '-n', name, '-k', sdkId, '-d', device, ], environment: _androidSdk?.sdkManagerEnv, ); return CreateEmulatorResult( - emulatorName, + name, success: runResult.exitCode == 0, output: runResult.stdout, error: cleanError(runResult.stderr), @@ -167,9 +162,9 @@ class EmulatorManager { 'pixel_xl', ]; - Future<String?> _getPreferredAvailableDevice(String avdManagerPath) async { + Future<String> _getPreferredAvailableDevice() async { final List<String> args = <String>[ - avdManagerPath, + _androidSdk?.avdManagerPath, 'list', 'device', '-c', @@ -185,21 +180,19 @@ class EmulatorManager { .where((String l) => preferredDevices.contains(l.trim())) .toList(); - for (final String device in preferredDevices) { - if (availableDevices.contains(device)) { - return device; - } - } - return null; + return preferredDevices.firstWhere( + (String d) => availableDevices.contains(d), + orElse: () => null, + ); } static final RegExp _androidApiVersion = RegExp(r';android-(\d+);'); - Future<String?> _getPreferredSdkId(String avdManagerPath) async { + Future<String> _getPreferredSdkId() async { // It seems that to get the available list of images, we need to send a // request to create without the image and it'll provide us a list :-( final List<String> args = <String>[ - avdManagerPath, + _androidSdk?.avdManagerPath, 'create', 'avd', '-n', 'temp', @@ -216,7 +209,7 @@ class EmulatorManager { .toList(); final List<int> availableApiVersions = availableIDs - .map<String>((String id) => _androidApiVersion.firstMatch(id)!.group(1)!) + .map<String>((String id) => _androidApiVersion.firstMatch(id).group(1)) .map<int>((String apiVersion) => int.parse(apiVersion)) .toList(); @@ -227,12 +220,10 @@ class EmulatorManager { // We're out of preferences, we just have to return the first one with the high // API version. - for (final String id in availableIDs) { - if (id.contains(';android-$apiVersion;')) { - return id; - } - } - return null; + return availableIDs.firstWhere( + (String id) => id.contains(';android-$apiVersion;'), + orElse: () => null, + ); } /// Whether we're capable of listing any emulators given the current environment configuration. @@ -261,7 +252,7 @@ abstract class Emulator { final String id; final bool hasConfig; String get name; - String? get manufacturer; + String get manufacturer; Category get category; PlatformType get platformType; @@ -291,10 +282,10 @@ abstract class Emulator { final List<List<String>> table = <List<String>>[ for (final Emulator emulator in emulators) <String>[ - emulator.id, - emulator.name, + emulator.id ?? '', + emulator.name ?? '', emulator.manufacturer ?? '', - emulator.platformType.toString(), + emulator.platformType?.toString() ?? '', ], ]; @@ -324,10 +315,10 @@ abstract class Emulator { } class CreateEmulatorResult { - CreateEmulatorResult(this.emulatorName, {required this.success, this.output, this.error}); + CreateEmulatorResult(this.emulatorName, {this.success, this.output, this.error}); final bool success; final String emulatorName; - final String? output; - final String? error; + final String output; + final String error; } diff --git a/packages/flutter_tools/lib/src/flutter_application_package.dart b/packages/flutter_tools/lib/src/flutter_application_package.dart index a0f924bef9eb7..b4c2181ab884e 100644 --- a/packages/flutter_tools/lib/src/flutter_application_package.dart +++ b/packages/flutter_tools/lib/src/flutter_application_package.dart @@ -2,6 +2,9 @@ // 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:meta/meta.dart'; import 'package:process/process.dart'; import 'android/android_sdk.dart'; @@ -13,7 +16,7 @@ import 'base/process.dart'; import 'base/user_messages.dart'; import 'build_info.dart'; import 'fuchsia/application_package.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; import 'ios/application_package.dart'; import 'linux/application_package.dart'; import 'macos/application_package.dart'; @@ -25,11 +28,11 @@ import 'windows/application_package.dart'; /// A package factory that supports all Flutter target platforms. class FlutterApplicationPackageFactory extends ApplicationPackageFactory { FlutterApplicationPackageFactory({ - required AndroidSdk androidSdk, - required ProcessManager processManager, - required Logger logger, - required UserMessages userMessages, - required FileSystem fileSystem, + @required AndroidSdk androidSdk, + @required ProcessManager processManager, + @required Logger logger, + @required UserMessages userMessages, + @required FileSystem fileSystem, }) : _androidSdk = androidSdk, _processManager = processManager, _logger = logger, @@ -46,10 +49,10 @@ class FlutterApplicationPackageFactory extends ApplicationPackageFactory { final FileSystem _fileSystem; @override - Future<ApplicationPackage?> getPackageForPlatform( + Future<ApplicationPackage> getPackageForPlatform( TargetPlatform platform, { - BuildInfo? buildInfo, - File? applicationBinary, + BuildInfo buildInfo, + File applicationBinary, }) async { switch (platform) { case TargetPlatform.android: @@ -108,5 +111,7 @@ class FlutterApplicationPackageFactory extends ApplicationPackageFactory { case TargetPlatform.windows_uwp_x64: return BuildableUwpApp(project: FlutterProject.current().windowsUwp); } + assert(platform != null); + return null; } } diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart index dd8468c809d76..ae479b4e9f69a 100644 --- a/packages/flutter_tools/lib/src/flutter_cache.dart +++ b/packages/flutter_tools/lib/src/flutter_cache.dart @@ -18,7 +18,7 @@ import 'base/process.dart'; import 'cache.dart'; import 'dart/package_map.dart'; import 'dart/pub.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; /// An implementation of the [Cache] which provides all of Flutter's default artifacts. class FlutterCache extends Cache { diff --git a/packages/flutter_tools/lib/src/flutter_device_manager.dart b/packages/flutter_tools/lib/src/flutter_device_manager.dart index d2587bb94c5cd..fc9a46ce85dab 100644 --- a/packages/flutter_tools/lib/src/flutter_device_manager.dart +++ b/packages/flutter_tools/lib/src/flutter_device_manager.dart @@ -2,6 +2,9 @@ // 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:meta/meta.dart'; import 'package:process/process.dart'; import 'android/android_device_discovery.dart'; @@ -39,27 +42,26 @@ import 'windows/windows_workflow.dart'; /// A provider for all of the device discovery instances. class FlutterDeviceManager extends DeviceManager { FlutterDeviceManager({ - required Logger logger, - required Platform platform, - required ProcessManager processManager, - required FileSystem fileSystem, - required AndroidSdk androidSdk, - required FeatureFlags featureFlags, - required IOSSimulatorUtils iosSimulatorUtils, - required XCDevice xcDevice, - required AndroidWorkflow androidWorkflow, - required IOSWorkflow iosWorkflow, - required FuchsiaWorkflow fuchsiaWorkflow, - required FlutterVersion flutterVersion, - required Artifacts artifacts, - required MacOSWorkflow macOSWorkflow, - required FuchsiaSdk fuchsiaSdk, - required UserMessages userMessages, - required OperatingSystemUtils operatingSystemUtils, - required WindowsWorkflow windowsWorkflow, - required Terminal terminal, - required CustomDevicesConfig customDevicesConfig, - required UwpTool uwptool, + @required Logger logger, + @required Platform platform, + @required ProcessManager processManager, + @required FileSystem fileSystem, + @required AndroidSdk androidSdk, + @required FeatureFlags featureFlags, + @required IOSSimulatorUtils iosSimulatorUtils, + @required XCDevice xcDevice, + @required AndroidWorkflow androidWorkflow, + @required IOSWorkflow iosWorkflow, + @required FuchsiaWorkflow fuchsiaWorkflow, + @required FlutterVersion flutterVersion, + @required Artifacts artifacts, + @required MacOSWorkflow macOSWorkflow, + @required UserMessages userMessages, + @required OperatingSystemUtils operatingSystemUtils, + @required WindowsWorkflow windowsWorkflow, + @required Terminal terminal, + @required CustomDevicesConfig customDevicesConfig, + @required UwpTool uwptool, }) : deviceDiscoverers = <DeviceDiscovery>[ AndroidDevices( logger: logger, diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart index 4f4dcb090537e..89d3066c3b1c6 100644 --- a/packages/flutter_tools/lib/src/flutter_manifest.dart +++ b/packages/flutter_tools/lib/src/flutter_manifest.dart @@ -339,11 +339,11 @@ class FlutterManifest { final YamlList? fontFiles = fontFamily['fonts'] as YamlList?; final String? familyName = fontFamily['family'] as String?; if (familyName == null) { - _logger.printWarning('Warning: Missing family name for font.', emphasis: true); + _logger.printError('Warning: Missing family name for font.', emphasis: true); continue; } if (fontFiles == null) { - _logger.printWarning('Warning: No fonts specified for font $familyName', emphasis: true); + _logger.printError('Warning: No fonts specified for font $familyName', emphasis: true); continue; } @@ -351,7 +351,7 @@ class FlutterManifest { for (final Map<Object?, Object?> fontFile in fontFiles.cast<Map<Object?, Object?>>()) { final String? asset = fontFile['asset'] as String?; if (asset == null) { - _logger.printWarning('Warning: Missing asset in fonts for $familyName', emphasis: true); + _logger.printError('Warning: Missing asset in fonts for $familyName', emphasis: true); continue; } diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index 2520df5e3e716..d099e2630dc3e 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -20,7 +20,7 @@ import 'convert.dart'; import 'dart/language_version.dart'; import 'dart/package_map.dart'; import 'features.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; import 'platform_plugins.dart'; import 'plugins.dart'; import 'project.dart'; @@ -98,7 +98,6 @@ const String _kFlutterPluginsPluginListKey = 'plugins'; const String _kFlutterPluginsNameKey = 'name'; const String _kFlutterPluginsPathKey = 'path'; const String _kFlutterPluginsDependenciesKey = 'dependencies'; -const String _kFlutterPluginsHasNativeBuildKey = 'native_build'; /// Filters [plugins] to those supported by [platformKey]. List<Map<String, Object>> _filterPluginsByPlatform(List<Plugin> plugins, String platformKey) { @@ -109,13 +108,9 @@ List<Map<String, Object>> _filterPluginsByPlatform(List<Plugin> plugins, String final Set<String> pluginNames = platformPlugins.map((Plugin plugin) => plugin.name).toSet(); final List<Map<String, Object>> pluginInfo = <Map<String, Object>>[]; for (final Plugin plugin in platformPlugins) { - // This is guaranteed to be non-null due to the `where` filter above. - final PluginPlatform platformPlugin = plugin.platforms[platformKey]!; pluginInfo.add(<String, Object>{ _kFlutterPluginsNameKey: plugin.name, _kFlutterPluginsPathKey: globals.fsUtils.escapePath(plugin.path), - if (platformPlugin is NativeOrDartPlugin) - _kFlutterPluginsHasNativeBuildKey: (platformPlugin as NativeOrDartPlugin).isNative(), _kFlutterPluginsDependenciesKey: <String>[...plugin.dependencies.where(pluginNames.contains)], }); } @@ -135,8 +130,7 @@ List<Map<String, Object>> _filterPluginsByPlatform(List<Plugin> plugins, String /// "dependencies": [ /// "plugin-a", /// "plugin-b" -/// ], -/// "native_build": true +/// ] /// } /// ], /// "android": [], @@ -399,7 +393,7 @@ Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> } } if (pluginsUsingV1.length > 1) { - globals.printWarning( + globals.printError( 'The plugins `${pluginsUsingV1.join(', ')}` use a deprecated version of the Android embedding.\n' 'To avoid unexpected runtime failures, or future build failures, try to see if these plugins ' 'support the Android V2 embedding. Otherwise, consider removing them since a future release ' @@ -408,7 +402,7 @@ Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> 'https://flutter.dev/go/android-plugin-migration.' ); } else if (pluginsUsingV1.isNotEmpty) { - globals.printWarning( + globals.printError( 'The plugin `${pluginsUsingV1.first}` uses a deprecated version of the Android embedding.\n' 'To avoid unexpected runtime failures, or future build failures, try to see if this plugin ' 'supports the Android V2 embedding. Otherwise, consider removing it since a future release ' @@ -420,7 +414,7 @@ Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> templateContent = _androidPluginRegistryTemplateNewEmbedding; break; case AndroidEmbeddingVersion.v1: - globals.printWarning( + globals.printError( 'This app is using a deprecated version of the Android embedding.\n' 'To avoid unexpected runtime failures, or future build failures, try to migrate this ' 'app to the V2 embedding.\n' @@ -1307,7 +1301,7 @@ Future<void> generateMainDartWithPluginRegistrant( newMainDart.deleteSync(); } } on FileSystemException catch (error) { - globals.printWarning( + globals.printError( 'Unable to remove ${newMainDart.path}, received error: $error.\n' 'You might need to run flutter clean.' ); diff --git a/packages/flutter_tools/lib/src/fuchsia/application_package.dart b/packages/flutter_tools/lib/src/fuchsia/application_package.dart index 6ea2b80088707..fe0df61d68a61 100644 --- a/packages/flutter_tools/lib/src/fuchsia/application_package.dart +++ b/packages/flutter_tools/lib/src/fuchsia/application_package.dart @@ -5,7 +5,7 @@ import '../application_package.dart'; import '../base/file_system.dart'; import '../build_info.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; abstract class FuchsiaApp extends ApplicationPackage { @@ -33,7 +33,7 @@ abstract class FuchsiaApp extends ApplicationPackage { return null; } return PrebuiltFuchsiaApp( - applicationPackage: applicationBinary, + farArchive: applicationBinary.path, ); } @@ -44,20 +44,20 @@ abstract class FuchsiaApp extends ApplicationPackage { File farArchive(BuildMode buildMode); } -class PrebuiltFuchsiaApp extends FuchsiaApp implements PrebuiltApplicationPackage { +class PrebuiltFuchsiaApp extends FuchsiaApp { PrebuiltFuchsiaApp({ - required this.applicationPackage, - }) : // TODO(zanderso): Extract the archive and extract the id from meta/package. - super(projectBundleId: applicationPackage.path); + required String farArchive, + }) : _farArchive = farArchive, + // TODO(zanderso): Extract the archive and extract the id from meta/package. + super(projectBundleId: farArchive); - @override - File farArchive(BuildMode buildMode) => globals.fs.file(applicationPackage); + final String _farArchive; @override - String get name => applicationPackage.path; + File farArchive(BuildMode buildMode) => globals.fs.file(_farArchive); @override - final FileSystemEntity applicationPackage; + String get name => _farArchive; } class BuildableFuchsiaApp extends FuchsiaApp { diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart index df23f5fd1d0df..875e3953e8682 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart @@ -2,6 +2,10 @@ // 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:meta/meta.dart'; + import '../artifacts.dart'; import '../asset.dart'; import '../base/common.dart'; @@ -12,10 +16,11 @@ import '../build_info.dart'; import '../bundle_builder.dart'; import '../convert.dart'; import '../devfs.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import 'fuchsia_pm.dart'; +import 'fuchsia_sdk.dart'; Future<void> _timedBuildStep(String name, Future<void> Function() action) async { final Stopwatch sw = Stopwatch()..start(); @@ -40,13 +45,12 @@ Future<void> _validateCmxFile(FuchsiaProject fuchsiaProject) async { // 3. Using these manifests, use the Fuchsia SDK 'pm' tool to create the // Fuchsia package. Future<void> buildFuchsia({ - required FuchsiaProject fuchsiaProject, - required TargetPlatform targetPlatform, - String? target, // E.g., lib/main.dart + @required FuchsiaProject fuchsiaProject, + @required TargetPlatform targetPlatform, + @required String target, // E.g., lib/main.dart BuildInfo buildInfo = BuildInfo.debug, String runnerPackageSource = FuchsiaPackageServer.toolHost, }) async { - final String targetPath = target ??= 'lib/main.dart'; await _validateCmxFile(fuchsiaProject); final Directory outDir = globals.fs.directory(getFuchsiaBuildDirectory()); if (!outDir.existsSync()) { @@ -54,18 +58,18 @@ Future<void> buildFuchsia({ } await _timedBuildStep('fuchsia-kernel-compile', - () => globals.fuchsiaSdk!.fuchsiaKernelCompiler.build( - fuchsiaProject: fuchsiaProject, target: targetPath, buildInfo: buildInfo)); + () => fuchsiaSdk.fuchsiaKernelCompiler.build( + fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo)); if (buildInfo.usesAot) { await _timedBuildStep('fuchsia-gen-snapshot', - () => _genSnapshot(fuchsiaProject, targetPath, buildInfo, targetPlatform)); + () => _genSnapshot(fuchsiaProject, target, buildInfo, targetPlatform)); } await _timedBuildStep('fuchsia-build-assets', - () => _buildAssets(fuchsiaProject, targetPath, buildInfo)); + () => _buildAssets(fuchsiaProject, target, buildInfo)); await _timedBuildStep('fuchsia-build-package', - () => _buildPackage(fuchsiaProject, targetPath, buildInfo, runnerPackageSource)); + () => _buildPackage(fuchsiaProject, target, buildInfo, runnerPackageSource)); } Future<void> _genSnapshot( @@ -80,7 +84,7 @@ Future<void> _genSnapshot( final String elf = globals.fs.path.join(outDir, 'elf.aotsnapshot'); - final String genSnapshot = globals.artifacts!.getArtifactPath( + final String genSnapshot = globals.artifacts.getArtifactPath( Artifact.genSnapshot, platform: targetPlatform, mode: buildInfo.mode, @@ -114,16 +118,12 @@ Future<void> _buildAssets( BuildInfo buildInfo, ) async { final String assetDir = getAssetBuildDirectory(); - final AssetBundle? assets = await buildAssets( + final AssetBundle assets = await buildAssets( manifestPath: fuchsiaProject.project.pubspecFile.path, packagesPath: fuchsiaProject.project.packagesFile.path, assetDirPath: assetDir, ); - if (assets == null) { - throwToolExit('Unable to find assets.', exitCode: 1); - } - final Map<String, DevFSContent> assetEntries = Map<String, DevFSContent>.of(assets.entries); await writeBundle(globals.fs.directory(assetDir), assetEntries); @@ -144,7 +144,7 @@ Future<void> _buildAssets( } void _rewriteCmx(BuildMode mode, String runnerPackageSource, File src, File dst) { - final Map<String, Object?> cmx = castStringKeyedMap(json.decode(src.readAsStringSync())) ?? <String, Object?>{}; + final Map<String, dynamic> cmx = castStringKeyedMap(json.decode(src.readAsStringSync())); // If the app author has already specified the runner in the cmx file, then // do not override it with something else. if (cmx.containsKey('runner')) { @@ -167,6 +167,7 @@ void _rewriteCmx(BuildMode mode, String runnerPackageSource, File src, File dst) break; default: throwToolExit('Fuchsia does not support build mode "$mode"'); + break; } cmx['runner'] = 'fuchsia-pkg://$runnerPackageSource/$runner#meta/$runner.cmx'; dst.writeAsStringSync(json.encode(cmx)); @@ -213,10 +214,7 @@ Future<void> _buildPackage( manifestFile.writeAsStringSync('meta/package=$pkgDir/meta/package\n', mode: FileMode.append); - final FuchsiaPM? fuchsiaPM = globals.fuchsiaSdk?.fuchsiaPM; - if (fuchsiaPM == null) { - return; - } + final FuchsiaPM fuchsiaPM = fuchsiaSdk.fuchsiaPM; if (!await fuchsiaPM.init(pkgDir, appName)) { return; } diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart index 4e30c37d393e0..78e79c2463524 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart @@ -2,10 +2,11 @@ // 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:meta/meta.dart'; -import 'package:vm_service/vm_service.dart' as vm_service; import '../application_package.dart'; import '../artifacts.dart'; @@ -21,7 +22,7 @@ import '../base/time.dart'; import '../build_info.dart'; import '../device.dart'; import '../device_port_forwarder.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../vmservice.dart'; @@ -35,13 +36,19 @@ import 'session_control.dart'; import 'tiles_ctl.dart'; /// The [FuchsiaDeviceTools] instance. -FuchsiaDeviceTools get fuchsiaDeviceTools => context.get<FuchsiaDeviceTools>()!; +FuchsiaDeviceTools get fuchsiaDeviceTools => context.get<FuchsiaDeviceTools>(); /// Fuchsia device-side tools. class FuchsiaDeviceTools { - late final FuchsiaPkgctl pkgctl = FuchsiaPkgctl(); - late final FuchsiaTilesCtl tilesCtl = FuchsiaTilesCtl(); - late final FuchsiaSessionControl sessionControl = FuchsiaSessionControl(); + FuchsiaPkgctl _pkgctl; + FuchsiaPkgctl get pkgctl => _pkgctl ??= FuchsiaPkgctl(); + + FuchsiaTilesCtl _tilesCtl; + FuchsiaTilesCtl get tilesCtl => _tilesCtl ??= FuchsiaTilesCtl(); + + FuchsiaSessionControl _sessionControl; + FuchsiaSessionControl get sessionControl => + _sessionControl ??= FuchsiaSessionControl(); } final String _ipv4Loopback = InternetAddress.loopbackIPv4.address; @@ -74,21 +81,21 @@ class _FuchsiaLogReader extends DeviceLogReader { static final RegExp _flutterLogOutput = RegExp(r'INFO: \S+\(flutter\): '); final FuchsiaDevice _device; - final ApplicationPackage? _app; + final ApplicationPackage _app; final SystemClock _systemClock; @override String get name => _device.name; - Stream<String>? _logLines; + Stream<String> _logLines; @override Stream<String> get logLines { - final Stream<String>? logStream = globals.fuchsiaSdk?.syslogs(_device.id); + final Stream<String> logStream = fuchsiaSdk.syslogs(_device.id); _logLines ??= _processLogs(logStream); - return _logLines ?? const Stream<String>.empty(); + return _logLines; } - Stream<String>? _processLogs(Stream<String>? lines) { + Stream<String> _processLogs(Stream<String> lines) { if (lines == null) { return null; } @@ -97,10 +104,9 @@ class _FuchsiaLogReader extends DeviceLogReader { final DateTime startTime = _systemClock.now(); // Determine if line comes from flutter, and optionally whether it matches // the correct fuchsia module. - final ApplicationPackage? app = _app; - final RegExp matchRegExp = app == null + final RegExp matchRegExp = _app == null ? _flutterLogOutput - : RegExp('INFO: ${app.name}(\\.cmx)?\\(flutter\\): '); + : RegExp('INFO: ${_app.name}(\\.cmx)?\\(flutter\\): '); return Stream<String>.eventTransformed( lines, (EventSink<String> output) => _FuchsiaLogSink(output, matchRegExp, startTime), @@ -130,7 +136,7 @@ class _FuchsiaLogSink implements EventSink<String> { if (!_matchRegExp.hasMatch(line)) { return; } - final String? rawDate = _utcDateOutput.firstMatch(line)?.group(0); + final String rawDate = _utcDateOutput.firstMatch(line)?.group(0); if (rawDate == null) { return; } @@ -143,7 +149,7 @@ class _FuchsiaLogSink implements EventSink<String> { } @override - void addError(Object error, [StackTrace? stackTrace]) { + void addError(Object error, [StackTrace stackTrace]) { _outputSink.addError(error, stackTrace); } @@ -156,10 +162,10 @@ class _FuchsiaLogSink implements EventSink<String> { /// Device discovery for Fuchsia devices. class FuchsiaDevices extends PollingDeviceDiscovery { FuchsiaDevices({ - required Platform platform, - required FuchsiaWorkflow fuchsiaWorkflow, - required FuchsiaSdk fuchsiaSdk, - required Logger logger, + @required Platform platform, + @required FuchsiaWorkflow fuchsiaWorkflow, + @required FuchsiaSdk fuchsiaSdk, + @required Logger logger, }) : _platform = platform, _fuchsiaWorkflow = fuchsiaWorkflow, _fuchsiaSdk = fuchsiaSdk, @@ -178,12 +184,12 @@ class FuchsiaDevices extends PollingDeviceDiscovery { bool get canListAnything => _fuchsiaWorkflow.canListDevices; @override - Future<List<Device>> pollingGetDevices({ Duration? timeout }) async { + Future<List<Device>> pollingGetDevices({ Duration timeout }) async { if (!_fuchsiaWorkflow.canListDevices) { return <Device>[]; } // TODO(omerlevran): Remove once soft transition is complete fxb/67602. - final List<String>? text = (await _fuchsiaSdk.listDevices( + final List<String> text = (await _fuchsiaSdk.listDevices( timeout: timeout, ))?.split('\n'); if (text == null || text.isEmpty) { @@ -191,7 +197,7 @@ class FuchsiaDevices extends PollingDeviceDiscovery { } final List<FuchsiaDevice> devices = <FuchsiaDevice>[]; for (final String line in text) { - final FuchsiaDevice? device = await _parseDevice(line); + final FuchsiaDevice device = await _parseDevice(line); if (device == null) { continue; } @@ -203,7 +209,7 @@ class FuchsiaDevices extends PollingDeviceDiscovery { @override Future<List<String>> getDiagnostics() async => const <String>[]; - Future<FuchsiaDevice?> _parseDevice(String text) async { + Future<FuchsiaDevice> _parseDevice(String text) async { final String line = text.trim(); // ['ip', 'device name'] final List<String> words = line.split(' '); @@ -213,7 +219,7 @@ class FuchsiaDevices extends PollingDeviceDiscovery { final String name = words[1]; // TODO(omerlevran): Add support for resolve on the FuchsiaSdk Object. - final String? resolvedHost = await _fuchsiaSdk.fuchsiaFfx.resolve(name); + final String resolvedHost = await _fuchsiaSdk.fuchsiaFfx.resolve(name); if (resolvedHost == null) { _logger.printError('Failed to resolve host for Fuchsia device `$name`'); return null; @@ -227,7 +233,7 @@ class FuchsiaDevices extends PollingDeviceDiscovery { class FuchsiaDevice extends Device { - FuchsiaDevice(String id, {required this.name}) : super( + FuchsiaDevice(String id, {this.name}) : super( id, platformType: PlatformType.fuchsia, category: null, @@ -250,12 +256,14 @@ class FuchsiaDevice extends Device { Future<bool> get isLocalEmulator async => false; @override - Future<String?> get emulatorId async => null; + Future<String> get emulatorId async => null; @override bool get supportsStartPaused => false; - late final Future<bool> isSession = _initIsSession(); + bool _isSession; + + Future<bool> get isSession async => _isSession ??= await _initIsSession(); /// Determine if the Fuchsia device is running a session based build. /// @@ -272,7 +280,7 @@ class FuchsiaDevice extends Device { @override Future<bool> isAppInstalled( ApplicationPackage app, { - String? userIdentifier, + String userIdentifier, }) async => false; @override @@ -281,13 +289,13 @@ class FuchsiaDevice extends Device { @override Future<bool> installApp( ApplicationPackage app, { - String? userIdentifier, + String userIdentifier, }) => Future<bool>.value(false); @override Future<bool> uninstallApp( ApplicationPackage app, { - String? userIdentifier, + String userIdentifier, }) async => false; @override @@ -299,13 +307,13 @@ class FuchsiaDevice extends Device { @override Future<LaunchResult> startApp( covariant FuchsiaApp package, { - String? mainPath, - String? route, - required DebuggingOptions debuggingOptions, - Map<String, Object?> platformArgs = const <String, Object?>{}, + String mainPath, + String route, + DebuggingOptions debuggingOptions, + Map<String, dynamic> platformArgs, bool prebuiltApplication = false, bool ipv6 = false, - String? userIdentifier, + String userIdentifier, }) async { if (await isSession) { globals.printTrace('Running on a session framework based build.'); @@ -348,7 +356,7 @@ class FuchsiaDevice extends Device { final Status status = globals.logger.startProgress( 'Starting Fuchsia application $appName...', ); - FuchsiaPackageServer? fuchsiaPackageServer; + FuchsiaPackageServer fuchsiaPackageServer; bool serverRegistered = false; String fuchsiaUrl; try { @@ -371,7 +379,7 @@ class FuchsiaDevice extends Device { // Serve the flutter_runner. final File flutterRunnerArchive = - globals.fs.file(globals.artifacts!.getArtifactPath( + globals.fs.file(globals.artifacts.getArtifactPath( Artifact.fuchsiaFlutterRunner, platform: await targetPlatform, mode: debuggingOptions.buildInfo.mode, @@ -447,7 +455,7 @@ class FuchsiaDevice extends Device { } finally { // Try to un-teach the package controller about the package server if // needed. - if (serverRegistered && fuchsiaPackageServer != null) { + if (serverRegistered) { await fuchsiaDeviceTools.pkgctl.rmRepo(this, fuchsiaPackageServer); } // Shutdown the package server and delete the package repo; @@ -485,7 +493,7 @@ class FuchsiaDevice extends Device { @override Future<bool> stopApp( covariant FuchsiaApp app, { - String? userIdentifier, + String userIdentifier, }) async { if (await isSession) { // Currently there are no way to close a running app programmatically @@ -502,9 +510,11 @@ class FuchsiaDevice extends Device { return true; } + TargetPlatform _targetPlatform; + Future<TargetPlatform> _queryTargetPlatform() async { const TargetPlatform defaultTargetPlatform = TargetPlatform.fuchsia_arm64; - if (!globals.fuchsiaArtifacts!.hasSshConfig) { + if (!globals.fuchsiaArtifacts.hasSshConfig) { globals.printTrace('Could not determine Fuchsia target platform because ' 'Fuchsia ssh configuration is missing.\n' 'Defaulting to arm64.'); @@ -564,12 +574,12 @@ class FuchsiaDevice extends Device { } @override - late final Future<TargetPlatform> targetPlatform = _queryTargetPlatform(); + Future<TargetPlatform> get targetPlatform async => _targetPlatform ??= await _queryTargetPlatform(); @override Future<String> get sdkNameAndVersion async { const String defaultName = 'Fuchsia'; - if (!globals.fuchsiaArtifacts!.hasSshConfig) { + if (!globals.fuchsiaArtifacts.hasSshConfig) { globals.printTrace('Could not determine Fuchsia sdk name or version ' 'because Fuchsia ssh configuration is missing.'); return defaultName; @@ -590,18 +600,18 @@ class FuchsiaDevice extends Device { @override DeviceLogReader getLogReader({ - ApplicationPackage? app, + ApplicationPackage app, bool includePastLogs = false, }) { assert(!includePastLogs, 'Past log reading not supported on Fuchsia.'); return _logReader ??= _FuchsiaLogReader(this, globals.systemClock, app); } - _FuchsiaLogReader? _logReader; + _FuchsiaLogReader _logReader; @override DevicePortForwarder get portForwarder => _portForwarder ??= _FuchsiaPortForwarder(this); - DevicePortForwarder? _portForwarder; + DevicePortForwarder _portForwarder; @visibleForTesting set portForwarder(DevicePortForwarder forwarder) { @@ -611,12 +621,17 @@ class FuchsiaDevice extends Device { @override void clearLogs() {} + bool _ipv6; + /// [true] if the current host address is IPv6. - late final bool ipv6 = isIPv6Address(id); + bool get ipv6 => _ipv6 ??= isIPv6Address(id); /// Return the address that the device should use to communicate with the /// host. - late final Future<String> hostAddress = () async { + Future<String> get hostAddress async { + if (_cachedHostAddress != null) { + return _cachedHostAddress; + } final RunResult result = await shell(r'echo $SSH_CONNECTION'); void fail() { throwToolExit('Failed to get local address, aborting.\n$result'); @@ -632,8 +647,10 @@ class FuchsiaDevice extends Device { if (addr.isEmpty) { fail(); } - return addr; - }(); + return _cachedHostAddress = addr; + } + + String _cachedHostAddress; /// List the ports currently running a dart observatory. Future<List<int>> servicePorts() async { @@ -662,7 +679,7 @@ class FuchsiaDevice extends Device { if (line == '') { continue; } - final int? port = int.tryParse(line); + final int port = int.tryParse(line); if (port != null) { ports.add(port); } @@ -673,15 +690,14 @@ class FuchsiaDevice extends Device { /// Run `command` on the Fuchsia device shell. Future<RunResult> shell(String command) async { - final File? sshConfig = globals.fuchsiaArtifacts?.sshConfig; - if (sshConfig == null) { + if (globals.fuchsiaArtifacts.sshConfig == null) { throwToolExit('Cannot interact with device. No ssh config.\n' 'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.'); } return globals.processUtils.run(<String>[ 'ssh', '-F', - sshConfig.absolute.path, + globals.fuchsiaArtifacts.sshConfig.absolute.path, id, // Device's IP address. command, ]); @@ -689,15 +705,14 @@ class FuchsiaDevice extends Device { /// Transfer the file [origin] from the device to [destination]. Future<RunResult> scp(String origin, String destination) async { - final File? sshConfig = globals.fuchsiaArtifacts!.sshConfig; - if (sshConfig == null) { + if (globals.fuchsiaArtifacts.sshConfig == null) { throwToolExit('Cannot interact with device. No ssh config.\n' 'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.'); } return globals.processUtils.run(<String>[ 'scp', '-F', - sshConfig.absolute.path, + globals.fuchsiaArtifacts.sshConfig.absolute.path, '$id:$origin', destination, ]); @@ -718,13 +733,11 @@ class FuchsiaDevice extends Device { final FlutterVmService vmService = await connectToVmService(uri, logger: globals.logger); final List<FlutterView> flutterViews = await vmService.getFlutterViews(); for (final FlutterView flutterView in flutterViews) { - final vm_service.IsolateRef? uiIsolate = flutterView.uiIsolate; - if (uiIsolate == null) { + if (flutterView.uiIsolate == null) { continue; } - final int? port = vmService.httpAddress?.port; - if (port != null && uiIsolate.name?.contains(isolateName) == true) { - return port; + if (flutterView.uiIsolate.name.contains(isolateName)) { + return vmService.httpAddress.port; } } } on SocketException catch (err) { @@ -767,12 +780,12 @@ class FuchsiaIsolateDiscoveryProtocol { final Future<void> Function(Device, Uri, bool) _ddsStarter; // whether to only poll once. final bool _pollOnce; - Timer? _pollingTimer; - Status? _status; + Timer _pollingTimer; + Status _status; FutureOr<Uri> get uri { if (_uri != null) { - return _uri!; + return _uri; } _status ??= globals.logger.startProgress( 'Waiting for a connection from $_isolateName on ${_device.name}...', @@ -784,7 +797,7 @@ class FuchsiaIsolateDiscoveryProtocol { }); } - Uri? _uri; + Uri _uri; void dispose() { if (!_foundUri.isCompleted) { @@ -799,7 +812,7 @@ class FuchsiaIsolateDiscoveryProtocol { Future<void> _findIsolate() async { final List<int> ports = await _device.servicePorts(); for (final int port in ports) { - FlutterVmService? service; + FlutterVmService service; if (_ports.containsKey(port)) { service = _ports[port]; } else { @@ -807,32 +820,30 @@ class FuchsiaIsolateDiscoveryProtocol { try { final Uri uri = Uri.parse('http://[$_ipv6Loopback]:$localPort'); await _ddsStarter(_device, uri, true); - service = await _vmServiceConnector(_device.dds.uri!); + service = await _vmServiceConnector(_device.dds.uri); _ports[port] = service; } on SocketException catch (err) { globals.printTrace('Failed to connect to $localPort: $err'); continue; } } - final List<FlutterView> flutterViews = await service?.getFlutterViews() ?? <FlutterView>[]; + final List<FlutterView> flutterViews = await service.getFlutterViews(); for (final FlutterView flutterView in flutterViews) { - final vm_service.IsolateRef? uiIsolate = flutterView.uiIsolate; - if (uiIsolate == null) { + if (flutterView.uiIsolate == null) { continue; } - final int? port = service?.httpAddress?.port; - if (port != null && uiIsolate.name?.contains(_isolateName) == true) { + if (flutterView.uiIsolate.name.contains(_isolateName)) { _foundUri.complete(_device.ipv6 - ? Uri.parse('http://[$_ipv6Loopback]:$port/') - : Uri.parse('http://$_ipv4Loopback:$port/')); - _status?.stop(); + ? Uri.parse('http://[$_ipv6Loopback]:${service.httpAddress.port}/') + : Uri.parse('http://$_ipv4Loopback:${service.httpAddress.port}/')); + _status.stop(); return; } } } if (_pollOnce) { _foundUri.completeError(Exception('Max iterations exceeded')); - _status?.stop(); + _status.stop(); return; } _pollingTimer = Timer(_pollDuration, _findIsolate); @@ -846,23 +857,18 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { final Map<int, Process> _processes = <int, Process>{}; @override - Future<int> forward(int devicePort, {int? hostPort}) async { + Future<int> forward(int devicePort, {int hostPort}) async { hostPort ??= await globals.os.findFreePort(); if (hostPort == 0) { throwToolExit('Failed to forward port $devicePort. No free host-side ports'); } - final File? sshConfig = globals.fuchsiaArtifacts?.sshConfig; - if (sshConfig == null) { - throwToolExit('Cannot interact with device. No ssh config.\n' - 'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.'); - } // Note: the provided command works around a bug in -N, see US-515 // for more explanation. final List<String> command = <String>[ 'ssh', '-6', '-F', - sshConfig.absolute.path, + globals.fuchsiaArtifacts.sshConfig.absolute.path, '-nNT', '-vvv', '-f', @@ -889,17 +895,12 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { @override Future<void> unforward(ForwardedPort forwardedPort) async { _forwardedPorts.remove(forwardedPort); - final Process? process = _processes.remove(forwardedPort.hostPort); + final Process process = _processes.remove(forwardedPort.hostPort); process?.kill(); - final File? sshConfig = globals.fuchsiaArtifacts?.sshConfig; - if (sshConfig == null) { - // Nothing to cancel. - return; - } final List<String> command = <String>[ 'ssh', '-F', - sshConfig.absolute.path, + globals.fuchsiaArtifacts.sshConfig.absolute.path, '-O', 'cancel', '-vvv', diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart index f7731fbf944f6..d8b0b45d77886 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart @@ -8,7 +8,7 @@ import '../artifacts.dart'; import '../base/common.dart'; import '../base/logger.dart'; import '../build_info.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; /// This is a simple wrapper around the custom kernel compiler from the Fuchsia diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart index eebe13235f006..4ed9973600fe5 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart @@ -8,7 +8,9 @@ import '../base/io.dart'; import '../base/net.dart'; import '../base/process.dart'; import '../convert.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; + +import 'fuchsia_sdk.dart'; /// This is a basic wrapper class for the Fuchsia SDK's `pm` tool. class FuchsiaPM { @@ -197,7 +199,7 @@ class FuchsiaPackageServer { return false; } // initialize a new repo. - final FuchsiaPM? fuchsiaPM = globals.fuchsiaSdk?.fuchsiaPM; + final FuchsiaPM? fuchsiaPM = fuchsiaSdk?.fuchsiaPM; if (fuchsiaPM == null || !await fuchsiaPM.newrepo(_repo)) { globals.printError('Failed to create a new package server repo'); return false; @@ -230,7 +232,7 @@ class FuchsiaPackageServer { if (_process == null) { return false; } - return (await globals.fuchsiaSdk?.fuchsiaPM.publish(_repo, package.path)) == true; + return (await fuchsiaSdk?.fuchsiaPM.publish(_repo, package.path)) == true; } @override diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart index 84fd9dce99798..4f8286170b2da 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart @@ -4,16 +4,20 @@ import 'dart:async'; +import '../base/context.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/platform.dart'; import '../convert.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import 'fuchsia_ffx.dart'; import 'fuchsia_kernel_compiler.dart'; import 'fuchsia_pm.dart'; +/// The [FuchsiaSdk] instance. +FuchsiaSdk? get fuchsiaSdk => context.get<FuchsiaSdk>(); + /// Returns [true] if the current platform supports Fuchsia targets. bool isFuchsiaSupportedPlatform(Platform platform) { return platform.isLinux || platform.isMacOS; diff --git a/packages/flutter_tools/lib/src/fuchsia/pkgctl.dart b/packages/flutter_tools/lib/src/fuchsia/pkgctl.dart index 523395054c812..26ff79ced0ab6 100644 --- a/packages/flutter_tools/lib/src/fuchsia/pkgctl.dart +++ b/packages/flutter_tools/lib/src/fuchsia/pkgctl.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../base/process.dart'; import 'fuchsia_device.dart'; diff --git a/packages/flutter_tools/lib/src/fuchsia/session_control.dart b/packages/flutter_tools/lib/src/fuchsia/session_control.dart index 42e11107cfa14..0d3283227cccf 100644 --- a/packages/flutter_tools/lib/src/fuchsia/session_control.dart +++ b/packages/flutter_tools/lib/src/fuchsia/session_control.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../base/process.dart'; import 'fuchsia_device.dart'; diff --git a/packages/flutter_tools/lib/src/fuchsia/tiles_ctl.dart b/packages/flutter_tools/lib/src/fuchsia/tiles_ctl.dart index e626e2eff0bf4..bcdb70d3923a8 100644 --- a/packages/flutter_tools/lib/src/fuchsia/tiles_ctl.dart +++ b/packages/flutter_tools/lib/src/fuchsia/tiles_ctl.dart @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../base/process.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import 'fuchsia_device.dart'; @@ -21,7 +23,7 @@ class FuchsiaTilesCtl { /// found. static Future<int> findAppKey(FuchsiaDevice device, String appName) async { final FuchsiaTilesCtl tilesCtl = fuchsiaDeviceTools.tilesCtl; - final Map<int, String>? runningApps = await tilesCtl.list(device); + final Map<int, String> runningApps = await tilesCtl.list(device); if (runningApps == null) { globals.printTrace('tiles_ctl is not running'); return -1; @@ -37,7 +39,7 @@ class FuchsiaTilesCtl { /// Ensures that tiles is running on the device. static Future<bool> ensureStarted(FuchsiaDevice device) async { final FuchsiaTilesCtl tilesCtl = fuchsiaDeviceTools.tilesCtl; - final Map<int, String>? runningApps = await tilesCtl.list(device); + final Map<int, String> runningApps = await tilesCtl.list(device); if (runningApps == null) { return tilesCtl.start(device); } @@ -56,7 +58,7 @@ class FuchsiaTilesCtl { /// /// Returns an empty mapping if tiles_ctl is running but no apps are running. /// Returns null if tiles_ctl is not running. - Future<Map<int, String>?> list(FuchsiaDevice device) async { + Future<Map<int, String>> list(FuchsiaDevice device) async { // Output of tiles_ctl list has the format: // Found 1 tiles: // Tile key 1 url fuchsia-pkg://fuchsia.com/stocks#meta/stocks.cmx ... @@ -73,11 +75,9 @@ class FuchsiaTilesCtl { for (final String line in result.stdout.split('\n')) { final List<String> words = line.split(' '); if (words.isNotEmpty && words[0] == 'Tile') { - final int? key = int.tryParse(words[2]); - if (key != null) { - final String url = words[4]; - tiles[key] = url; - } + final int key = int.tryParse(words[2]); + final String url = words[4]; + tiles[key] = url; } } return tiles; diff --git a/packages/flutter_tools/lib/src/globals.dart b/packages/flutter_tools/lib/src/globals.dart index 35fe0291b07d1..61bd13cb4a12f 100644 --- a/packages/flutter_tools/lib/src/globals.dart +++ b/packages/flutter_tools/lib/src/globals.dart @@ -2,282 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:process/process.dart'; +// TODO(jmagman): Remove globals_null_migrated.dart, move into globals.dart. -import 'android/android_sdk.dart'; -import 'android/android_studio.dart'; -import 'android/gradle_utils.dart'; -import 'artifacts.dart'; -import 'base/bot_detector.dart'; -import 'base/config.dart'; -import 'base/context.dart'; -import 'base/error_handling_io.dart'; -import 'base/file_system.dart'; -import 'base/io.dart'; -import 'base/logger.dart'; -import 'base/net.dart'; -import 'base/os.dart'; -import 'base/platform.dart'; -import 'base/process.dart'; -import 'base/signals.dart'; -import 'base/template.dart'; -import 'base/terminal.dart'; -import 'base/time.dart'; -import 'base/user_messages.dart'; -import 'build_system/build_system.dart'; -import 'cache.dart'; -import 'custom_devices/custom_devices_config.dart'; -import 'device.dart'; -import 'doctor.dart'; -import 'fuchsia/fuchsia_sdk.dart'; -import 'ios/ios_workflow.dart'; -import 'ios/plist_parser.dart'; -import 'ios/simulators.dart'; -import 'ios/xcodeproj.dart'; -import 'macos/cocoapods.dart'; -import 'macos/cocoapods_validator.dart'; -import 'macos/xcdevice.dart'; -import 'macos/xcode.dart'; -import 'persistent_tool_state.dart'; -import 'pre_run_validator.dart'; -import 'project.dart'; -import 'reporting/crash_reporting.dart'; -import 'reporting/reporting.dart'; -import 'runner/local_engine.dart'; -import 'version.dart'; - -/// The flutter GitHub repository. -String get flutterGit => platform.environment['FLUTTER_GIT_URL'] ?? 'https://github.com/flutter/flutter.git'; - -Artifacts? get artifacts => context.get<Artifacts>(); -BuildSystem get buildSystem => context.get<BuildSystem>()!; -Cache get cache => context.get<Cache>()!; -CocoaPodsValidator? get cocoapodsValidator => context.get<CocoaPodsValidator>(); -Config get config => context.get<Config>()!; -CrashReporter? get crashReporter => context.get<CrashReporter>(); -DeviceManager? get deviceManager => context.get<DeviceManager>(); -Doctor? get doctor => context.get<Doctor>(); -HttpClientFactory? get httpClientFactory => context.get<HttpClientFactory>(); -IOSSimulatorUtils? get iosSimulatorUtils => context.get<IOSSimulatorUtils>(); -Logger get logger => context.get<Logger>()!; -OperatingSystemUtils get os => context.get<OperatingSystemUtils>()!; -Signals get signals => context.get<Signals>() ?? LocalSignals.instance; -AndroidStudio? get androidStudio => context.get<AndroidStudio>(); -AndroidSdk? get androidSdk => context.get<AndroidSdk>(); -FlutterVersion get flutterVersion => context.get<FlutterVersion>()!; -FuchsiaArtifacts? get fuchsiaArtifacts => context.get<FuchsiaArtifacts>(); -FuchsiaSdk? get fuchsiaSdk => context.get<FuchsiaSdk>(); -Usage get flutterUsage => context.get<Usage>()!; -XcodeProjectInterpreter? get xcodeProjectInterpreter => context.get<XcodeProjectInterpreter>(); -XCDevice? get xcdevice => context.get<XCDevice>(); -Xcode? get xcode => context.get<Xcode>(); -IOSWorkflow? get iosWorkflow => context.get<IOSWorkflow>(); -LocalEngineLocator? get localEngineLocator => context.get<LocalEngineLocator>(); - -PersistentToolState? get persistentToolState => PersistentToolState.instance; - -BotDetector get botDetector => context.get<BotDetector>() ?? _defaultBotDetector; -final BotDetector _defaultBotDetector = BotDetector( - httpClientFactory: context.get<HttpClientFactory>() ?? () => HttpClient(), - platform: platform, - persistentToolState: persistentToolState ?? PersistentToolState( - fileSystem: fs, - logger: logger, - platform: platform, - ), -); -Future<bool> get isRunningOnBot => botDetector.isRunningOnBot; - -/// Currently active implementation of the file system. -/// -/// By default it uses local disk-based implementation. Override this in tests -/// with [MemoryFileSystem]. -FileSystem get fs => ErrorHandlingFileSystem( - delegate: context.get<FileSystem>() ?? localFileSystem, - platform: platform, -); - -FileSystemUtils get fsUtils => context.get<FileSystemUtils>() ?? FileSystemUtils( - fileSystem: fs, - platform: platform, -); - -const ProcessManager _kLocalProcessManager = LocalProcessManager(); - -/// The active process manager. -ProcessManager get processManager => context.get<ProcessManager>() ?? _kLocalProcessManager; -ProcessUtils get processUtils => context.get<ProcessUtils>()!; - -const Platform _kLocalPlatform = LocalPlatform(); -Platform get platform => context.get<Platform>() ?? _kLocalPlatform; - -UserMessages get userMessages => context.get<UserMessages>()!; - -final OutputPreferences _default = OutputPreferences( - wrapText: stdio.hasTerminal, - showColor: platform.stdoutSupportsAnsi, - stdio: stdio, -); -OutputPreferences get outputPreferences => context.get<OutputPreferences>() ?? _default; - -/// The current system clock instance. -SystemClock get systemClock => context.get<SystemClock>() ?? _systemClock; -SystemClock _systemClock = const SystemClock(); - -ProcessInfo get processInfo => context.get<ProcessInfo>()!; - -/// Display an error level message to the user. Commands should use this if they -/// fail in some way. -/// -/// Set [emphasis] to true to make the output bold if it's supported. -/// Set [color] to a [TerminalColor] to color the output, if the logger -/// supports it. The [color] defaults to [TerminalColor.red]. -void printError( - String message, { - StackTrace? stackTrace, - bool? emphasis, - TerminalColor? color, - int? indent, - int? hangingIndent, - bool? wrap, - }) { - logger.printError( - message, - stackTrace: stackTrace, - emphasis: emphasis ?? false, - color: color, - indent: indent, - hangingIndent: hangingIndent, - wrap: wrap, - ); -} - -/// Display a warning level message to the user. Commands should use this if they -/// have important warnings to convey that aren't fatal. -/// -/// Set [emphasis] to true to make the output bold if it's supported. -/// Set [color] to a [TerminalColor] to color the output, if the logger -/// supports it. The [color] defaults to [TerminalColor.cyan]. -void printWarning( - String message, { - bool? emphasis, - TerminalColor? color, - int? indent, - int? hangingIndent, - bool? wrap, - }) { - logger.printWarning( - message, - emphasis: emphasis ?? false, - color: color, - indent: indent, - hangingIndent: hangingIndent, - wrap: wrap, - ); -} - -/// Display normal output of the command. This should be used for things like -/// progress messages, success messages, or just normal command output. -/// -/// Set `emphasis` to true to make the output bold if it's supported. -/// -/// Set `newline` to false to skip the trailing linefeed. -/// -/// If `indent` is provided, each line of the message will be prepended by the -/// specified number of whitespaces. -void printStatus( - String message, { - bool? emphasis, - bool? newline, - TerminalColor? color, - int? indent, - int? hangingIndent, - bool? wrap, - }) { - logger.printStatus( - message, - emphasis: emphasis ?? false, - color: color, - newline: newline ?? true, - indent: indent, - hangingIndent: hangingIndent, - wrap: wrap, - ); -} - - -/// Display the [message] inside a box. -/// -/// For example, this is the generated output: -/// -/// ┌─ [title] ─┐ -/// │ [message] │ -/// └───────────┘ -/// -/// If a terminal is attached, the lines in [message] are automatically wrapped based on -/// the available columns. -void printBox(String message, { - String? title, -}) { - logger.printBox(message, title: title); -} - -/// Use this for verbose tracing output. Users can turn this output on in order -/// to help diagnose issues with the toolchain or with their setup. -void printTrace(String message) => logger.printTrace(message); - -AnsiTerminal get terminal { - return context.get<AnsiTerminal>() ?? _defaultAnsiTerminal; -} - -final AnsiTerminal _defaultAnsiTerminal = AnsiTerminal( - stdio: stdio, - platform: platform, - now: DateTime.now(), -); - -/// The global Stdio wrapper. -Stdio get stdio => context.get<Stdio>() ?? (_stdioInstance ??= Stdio()); -Stdio? _stdioInstance; - -PlistParser get plistParser => context.get<PlistParser>() ?? ( - _plistInstance ??= PlistParser( - fileSystem: fs, - processManager: processManager, - logger: logger, - )); -PlistParser? _plistInstance; - -/// The global template renderer. -TemplateRenderer get templateRenderer => context.get<TemplateRenderer>()!; - -ShutdownHooks? get shutdownHooks => context.get<ShutdownHooks>(); - -// Unless we're in a test of this class's signal handling features, we must -// have only one instance created with the singleton LocalSignals instance -// and the catchable signals it considers to be fatal. -LocalFileSystem? _instance; -LocalFileSystem get localFileSystem => _instance ??= LocalFileSystem( - LocalSignals.instance, - Signals.defaultExitSignals, - shutdownHooks, -); - -/// Gradle utils in the current [AppContext]. -GradleUtils? get gradleUtils => context.get<GradleUtils>(); - -CocoaPods? get cocoaPods => context.get<CocoaPods>(); - -FlutterProjectFactory get projectFactory { - return context.get<FlutterProjectFactory>() ?? FlutterProjectFactory( - logger: logger, - fileSystem: fs, - ); -} - -CustomDevicesConfig get customDevicesConfig => context.get<CustomDevicesConfig>()!; - -PreRunValidator get preRunValidator => context.get<PreRunValidator>() ?? const NoOpPreRunValidator(); - -// TODO(fujino): Migrate to 'main' https://github.com/flutter/flutter/issues/95041 -const String kDefaultFrameworkChannel = 'master'; +export 'globals_null_migrated.dart'; diff --git a/packages/flutter_tools/lib/src/globals_null_migrated.dart b/packages/flutter_tools/lib/src/globals_null_migrated.dart new file mode 100644 index 0000000000000..29b24239017fe --- /dev/null +++ b/packages/flutter_tools/lib/src/globals_null_migrated.dart @@ -0,0 +1,238 @@ +// 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 'package:process/process.dart'; + +import 'android/android_sdk.dart'; +import 'android/android_studio.dart'; +import 'android/gradle_utils.dart'; +import 'artifacts.dart'; +import 'base/bot_detector.dart'; +import 'base/config.dart'; +import 'base/context.dart'; +import 'base/error_handling_io.dart'; +import 'base/file_system.dart'; +import 'base/io.dart'; +import 'base/logger.dart'; +import 'base/net.dart'; +import 'base/os.dart'; +import 'base/platform.dart'; +import 'base/process.dart'; +import 'base/signals.dart'; +import 'base/template.dart'; +import 'base/terminal.dart'; +import 'base/time.dart'; +import 'base/user_messages.dart'; +import 'build_system/build_system.dart'; +import 'cache.dart'; +import 'custom_devices/custom_devices_config.dart'; +import 'device.dart'; +import 'doctor.dart'; +import 'fuchsia/fuchsia_sdk.dart'; +import 'ios/ios_workflow.dart'; +import 'ios/plist_parser.dart'; +import 'ios/simulators.dart'; +import 'ios/xcodeproj.dart'; +import 'macos/cocoapods.dart'; +import 'macos/cocoapods_validator.dart'; +import 'macos/xcdevice.dart'; +import 'macos/xcode.dart'; +import 'persistent_tool_state.dart'; +import 'pre_run_validator.dart'; +import 'project.dart'; +import 'reporting/crash_reporting.dart'; +import 'reporting/reporting.dart'; +import 'runner/local_engine.dart'; +import 'version.dart'; + +/// The flutter GitHub repository. +String get flutterGit => platform.environment['FLUTTER_GIT_URL'] ?? 'https://github.com/flutter/flutter.git'; + +Artifacts? get artifacts => context.get<Artifacts>(); +BuildSystem? get buildSystem => context.get<BuildSystem>(); +Cache get cache => context.get<Cache>()!; +CocoaPodsValidator? get cocoapodsValidator => context.get<CocoaPodsValidator>(); +Config get config => context.get<Config>()!; +CrashReporter? get crashReporter => context.get<CrashReporter>(); +DeviceManager? get deviceManager => context.get<DeviceManager>(); +Doctor? get doctor => context.get<Doctor>(); +HttpClientFactory? get httpClientFactory => context.get<HttpClientFactory>(); +IOSSimulatorUtils? get iosSimulatorUtils => context.get<IOSSimulatorUtils>(); +Logger get logger => context.get<Logger>()!; +OperatingSystemUtils get os => context.get<OperatingSystemUtils>()!; +Signals get signals => context.get<Signals>() ?? LocalSignals.instance; +AndroidStudio? get androidStudio => context.get<AndroidStudio>(); +AndroidSdk? get androidSdk => context.get<AndroidSdk>(); +FlutterVersion get flutterVersion => context.get<FlutterVersion>()!; +FuchsiaArtifacts? get fuchsiaArtifacts => context.get<FuchsiaArtifacts>(); +Usage get flutterUsage => context.get<Usage>()!; +XcodeProjectInterpreter? get xcodeProjectInterpreter => context.get<XcodeProjectInterpreter>(); +XCDevice? get xcdevice => context.get<XCDevice>(); +Xcode? get xcode => context.get<Xcode>(); +IOSWorkflow? get iosWorkflow => context.get<IOSWorkflow>(); +LocalEngineLocator? get localEngineLocator => context.get<LocalEngineLocator>(); + +PersistentToolState? get persistentToolState => PersistentToolState.instance; + +BotDetector get botDetector => context.get<BotDetector>() ?? _defaultBotDetector; +final BotDetector _defaultBotDetector = BotDetector( + httpClientFactory: context.get<HttpClientFactory>() ?? () => HttpClient(), + platform: platform, + persistentToolState: persistentToolState ?? PersistentToolState( + fileSystem: fs, + logger: logger, + platform: platform, + ), +); +Future<bool> get isRunningOnBot => botDetector.isRunningOnBot; + +/// Currently active implementation of the file system. +/// +/// By default it uses local disk-based implementation. Override this in tests +/// with [MemoryFileSystem]. +FileSystem get fs => ErrorHandlingFileSystem( + delegate: context.get<FileSystem>() ?? localFileSystem, + platform: platform, +); + +FileSystemUtils get fsUtils => context.get<FileSystemUtils>() ?? FileSystemUtils( + fileSystem: fs, + platform: platform, +); + +const ProcessManager _kLocalProcessManager = LocalProcessManager(); + +/// The active process manager. +ProcessManager get processManager => context.get<ProcessManager>() ?? _kLocalProcessManager; +ProcessUtils get processUtils => context.get<ProcessUtils>()!; + +const Platform _kLocalPlatform = LocalPlatform(); +Platform get platform => context.get<Platform>() ?? _kLocalPlatform; + +UserMessages get userMessages => context.get<UserMessages>()!; + +final OutputPreferences _default = OutputPreferences( + wrapText: stdio.hasTerminal, + showColor: platform.stdoutSupportsAnsi, + stdio: stdio, +); +OutputPreferences get outputPreferences => context.get<OutputPreferences>() ?? _default; + +/// The current system clock instance. +SystemClock get systemClock => context.get<SystemClock>() ?? _systemClock; +SystemClock _systemClock = const SystemClock(); + +ProcessInfo get processInfo => context.get<ProcessInfo>()!; + +/// Display an error level message to the user. Commands should use this if they +/// fail in some way. +/// +/// Set [emphasis] to true to make the output bold if it's supported. +/// Set [color] to a [TerminalColor] to color the output, if the logger +/// supports it. The [color] defaults to [TerminalColor.red]. +void printError( + String message, { + StackTrace? stackTrace, + bool? emphasis, + TerminalColor? color, + int? indent, + int? hangingIndent, + bool? wrap, +}) { + logger.printError( + message, + stackTrace: stackTrace, + emphasis: emphasis ?? false, + color: color, + indent: indent, + hangingIndent: hangingIndent, + wrap: wrap, + ); +} + +/// Display normal output of the command. This should be used for things like +/// progress messages, success messages, or just normal command output. +/// +/// Set `emphasis` to true to make the output bold if it's supported. +/// +/// Set `newline` to false to skip the trailing linefeed. +/// +/// If `indent` is provided, each line of the message will be prepended by the +/// specified number of whitespaces. +void printStatus( + String message, { + bool? emphasis, + bool? newline, + TerminalColor? color, + int? indent, + int? hangingIndent, + bool? wrap, +}) { + logger.printStatus( + message, + emphasis: emphasis ?? false, + color: color, + newline: newline ?? true, + indent: indent, + hangingIndent: hangingIndent, + wrap: wrap, + ); +} + +/// Use this for verbose tracing output. Users can turn this output on in order +/// to help diagnose issues with the toolchain or with their setup. +void printTrace(String message) => logger.printTrace(message); + +AnsiTerminal get terminal { + return context.get<AnsiTerminal>() ?? _defaultAnsiTerminal; +} + +final AnsiTerminal _defaultAnsiTerminal = AnsiTerminal( + stdio: stdio, + platform: platform, + now: DateTime.now(), +); + +/// The global Stdio wrapper. +Stdio get stdio => context.get<Stdio>() ?? (_stdioInstance ??= Stdio()); +Stdio? _stdioInstance; + +PlistParser get plistParser => context.get<PlistParser>() ?? ( + _plistInstance ??= PlistParser( + fileSystem: fs, + processManager: processManager, + logger: logger, +)); +PlistParser? _plistInstance; + +/// The global template renderer. +TemplateRenderer get templateRenderer => context.get<TemplateRenderer>()!; + +ShutdownHooks? get shutdownHooks => context.get<ShutdownHooks>(); + +// Unless we're in a test of this class's signal handling features, we must +// have only one instance created with the singleton LocalSignals instance +// and the catchable signals it considers to be fatal. +LocalFileSystem? _instance; +LocalFileSystem get localFileSystem => _instance ??= LocalFileSystem( + LocalSignals.instance, + Signals.defaultExitSignals, + shutdownHooks, +); + +/// Gradle utils in the current [AppContext]. +GradleUtils? get gradleUtils => context.get<GradleUtils>(); + +CocoaPods? get cocoaPods => context.get<CocoaPods>(); + +FlutterProjectFactory get projectFactory { + return context.get<FlutterProjectFactory>() ?? FlutterProjectFactory( + logger: logger, + fileSystem: fs, + ); +} + +CustomDevicesConfig get customDevicesConfig => context.get<CustomDevicesConfig>()!; + +PreRunValidator get preRunValidator => context.get<PreRunValidator>() ?? const NoOpPreRunValidator(); diff --git a/packages/flutter_tools/lib/src/http_host_validator.dart b/packages/flutter_tools/lib/src/http_host_validator.dart deleted file mode 100644 index 76b748a8717df..0000000000000 --- a/packages/flutter_tools/lib/src/http_host_validator.dart +++ /dev/null @@ -1,126 +0,0 @@ -// 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:async'; - -import 'base/io.dart'; -import 'base/platform.dart'; -import 'doctor_validator.dart'; -import 'features.dart'; - -// Overridable environment variables -const String kEnvPubHostedUrl = 'PUB_HOSTED_URL'; -const String kEnvCloudUrl = 'FLUTTER_STORAGE_BASE_URL'; -const String kDoctorHostTimeout = 'FLUTTER_DOCTOR_HOST_TIMEOUT'; - -/// Common Flutter HTTP hosts. -const String kPubDevHttpHost = 'https://pub.dev/'; -const String kgCloudHttpHost = 'https://cloud.google.com/'; - -/// Android specific required HTTP hosts. -const List<String> androidRequiredHttpHosts = <String>[ - 'https://maven.google.com/', -]; - -/// MacOS specific required HTTP hosts. -const List<String> macOSRequiredHttpHosts = <String>[ - 'https://cocoapods.org/', -]; - -// Validator that checks all provided hosts are reachable and responsive -class HttpHostValidator extends DoctorValidator { - HttpHostValidator( - {required Platform platform, - required FeatureFlags featureFlags, - required HttpClient httpClient}) - : _platform = platform, - _featureFlags = featureFlags, - _httpClient = httpClient, - super('HTTP Host Availability'); - - final Platform _platform; - final FeatureFlags _featureFlags; - final HttpClient _httpClient; - - @override - String get slowWarning => - 'HTTP Host availability check is taking a long time...'; - - List<String> get _requiredHosts => <String>[ - if (_featureFlags.isMacOSEnabled) ...macOSRequiredHttpHosts, - if (_featureFlags.isAndroidEnabled) ...androidRequiredHttpHosts, - _platform.environment[kEnvPubHostedUrl] ?? kPubDevHttpHost, - _platform.environment[kEnvCloudUrl] ?? kgCloudHttpHost, - ]; - - /// Make a head request to the HTTP host. HTTP Host is available if no exception happened - Future<_HostValidationResult> _checkHostAvailability(String host) async { - try { - final int timeout = - int.parse(_platform.environment[kDoctorHostTimeout] ?? '10'); - final HttpClientRequest req = await _httpClient.headUrl(Uri.parse(host)); - await req.close().timeout(Duration(seconds: timeout)); - // HTTP Host is available if no exception happened - return _HostValidationResult.success(host); - } on TimeoutException { - return _HostValidationResult.fail( - host, 'Failed to connect to $host in seconds'); - } on SocketException catch (e) { - return _HostValidationResult.fail( - host, 'An error occurred while checking the HTTP host: ${e.message}'); - } on HttpException catch (e) { - return _HostValidationResult.fail(host, - 'An error occurred while checking the HTTP host: ${e.toString()}'); - } on OSError catch (e) { - return _HostValidationResult.fail( - host, 'An error occurred while checking the HTTP host: ${e.message}'); - } - } - - @override - Future<ValidationResult> validate() async { - final List<ValidationMessage> messages = <ValidationMessage>[]; - final Iterable<Future<_HostValidationResult>> availabilityResultFutures = - _requiredHosts.map(_checkHostAvailability); - - final List<_HostValidationResult> availabilityResults = - (await Future.wait(availabilityResultFutures)).toList(); - - if (availabilityResults - .every((_HostValidationResult result) => result.available)) { - return ValidationResult( - ValidationType.installed, - messages - ..add(const ValidationMessage( - 'All required HTTP hosts are available'))); - } - - availabilityResults - .removeWhere((_HostValidationResult result) => result.available); - - for (final _HostValidationResult result in availabilityResults) { - messages.add(ValidationMessage.error( - 'HTTP host ${result.host} is not reachable. Reason: ${result.failResultInfo}')); - } - - return ValidationResult( - availabilityResults.length == _requiredHosts.length - ? ValidationType.notAvailable - : ValidationType.partial, - messages); - } -} - -class _HostValidationResult { - _HostValidationResult.success(this.host) - : failResultInfo = '', - available = true; - - _HostValidationResult.fail(this.host, this.failResultInfo) - : available = false; - - final String failResultInfo; - final String host; - final bool available; -} diff --git a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart index 9e9024c6f5050..d2fc4cf84cbf3 100644 --- a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart +++ b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart @@ -500,7 +500,7 @@ class IntelliJValidatorOnMac extends IntelliJValidator { @override String get version { - return _version ??= _plistParser.getStringValueFromFile( + return _version ??= _plistParser.getValueFromFile( plistFile, PlistParser.kCFBundleShortVersionStringKey, ) ?? 'unknown'; @@ -514,7 +514,7 @@ class IntelliJValidatorOnMac extends IntelliJValidator { } final String? altLocation = _plistParser - .getStringValueFromFile(plistFile, 'JetBrainsToolboxApp'); + .getValueFromFile(plistFile, 'JetBrainsToolboxApp'); if (altLocation != null) { _pluginsPath = '$altLocation.plugins'; diff --git a/packages/flutter_tools/lib/src/ios/application_package.dart b/packages/flutter_tools/lib/src/ios/application_package.dart index ed72de3076d34..ce97f97ef452a 100644 --- a/packages/flutter_tools/lib/src/ios/application_package.dart +++ b/packages/flutter_tools/lib/src/ios/application_package.dart @@ -5,7 +5,7 @@ import '../application_package.dart'; import '../base/file_system.dart'; import '../build_info.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../xcode_project.dart'; import 'plist_parser.dart'; @@ -23,14 +23,14 @@ abstract class IOSApp extends ApplicationPackage { 'File "${applicationBinary.path}" does not exist. Use an app bundle or an ipa.'); return null; } - Directory uncompressedBundle; + Directory bundleDir; if (entityType == FileSystemEntityType.directory) { final Directory directory = globals.fs.directory(applicationBinary); if (!_isBundleDirectory(directory)) { globals.printError('Folder "${applicationBinary.path}" is not an app bundle.'); return null; } - uncompressedBundle = globals.fs.directory(applicationBinary); + bundleDir = globals.fs.directory(applicationBinary); } else { // Try to unpack as an ipa. final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_app.'); @@ -44,19 +44,19 @@ abstract class IOSApp extends ApplicationPackage { return null; } try { - uncompressedBundle = payloadDir.listSync().whereType<Directory>().singleWhere(_isBundleDirectory); + bundleDir = payloadDir.listSync().whereType<Directory>().singleWhere(_isBundleDirectory); } on StateError { globals.printError( 'Invalid prebuilt iOS ipa. Does not contain a single app bundle.'); return null; } } - final String plistPath = globals.fs.path.join(uncompressedBundle.path, 'Info.plist'); + final String plistPath = globals.fs.path.join(bundleDir.path, 'Info.plist'); if (!globals.fs.file(plistPath).existsSync()) { globals.printError('Invalid prebuilt iOS app. Does not contain Info.plist.'); return null; } - final String? id = globals.plistParser.getStringValueFromFile( + final String? id = globals.plistParser.getValueFromFile( plistPath, PlistParser.kCFBundleIdentifierKey, ); @@ -66,14 +66,13 @@ abstract class IOSApp extends ApplicationPackage { } return PrebuiltIOSApp( - uncompressedBundle: uncompressedBundle, - bundleName: globals.fs.path.basename(uncompressedBundle.path), + bundleDir: bundleDir, + bundleName: globals.fs.path.basename(bundleDir.path), projectBundleId: id, - applicationPackage: applicationBinary, ); } - static Future<IOSApp?> fromIosProject(IosProject project, BuildInfo? buildInfo) async { + static Future<IOSApp?> fromIosProject(IosProject project, BuildInfo buildInfo) async { if (!globals.platform.isMacOS) { return null; } @@ -110,7 +109,7 @@ class BuildableIOSApp extends IOSApp { : _hostAppBundleName = hostAppBundleName, super(projectBundleId: projectBundleId); - static Future<BuildableIOSApp?> fromProject(IosProject project, BuildInfo? buildInfo) async { + static Future<BuildableIOSApp?> fromProject(IosProject project, BuildInfo buildInfo) async { final String? hostAppBundleName = await project.hostAppBundleName(buildInfo); final String? projectBundleId = await project.productBundleIdentifier(buildInfo); if (projectBundleId != null) { @@ -153,19 +152,14 @@ class BuildableIOSApp extends IOSApp { } } -class PrebuiltIOSApp extends IOSApp implements PrebuiltApplicationPackage { +class PrebuiltIOSApp extends IOSApp { PrebuiltIOSApp({ - required this.uncompressedBundle, + required this.bundleDir, this.bundleName, required String projectBundleId, - required this.applicationPackage, }) : super(projectBundleId: projectBundleId); - /// The uncompressed bundle of the application. - /// - /// [IOSApp.fromPrebuiltApp] will uncompress the application into a temporary - /// directory even when an `.ipa` file was used to create the [IOSApp] instance. - final Directory uncompressedBundle; + final Directory bundleDir; final String? bundleName; @override @@ -180,11 +174,5 @@ class PrebuiltIOSApp extends IOSApp implements PrebuiltApplicationPackage { @override String get deviceBundlePath => _bundlePath; - String get _bundlePath => uncompressedBundle.path; - - /// A [File] or [Directory] pointing to the application bundle. - /// - /// This can be either an `.ipa` file or an uncompressed `.app` directory. - @override - final FileSystemEntity applicationPackage; + String get _bundlePath => bundleDir.path; } diff --git a/packages/flutter_tools/lib/src/ios/bitcode.dart b/packages/flutter_tools/lib/src/ios/bitcode.dart index e07d89219dc59..8cbc785ca2c95 100644 --- a/packages/flutter_tools/lib/src/ios/bitcode.dart +++ b/packages/flutter_tools/lib/src/ios/bitcode.dart @@ -8,7 +8,7 @@ import '../base/context.dart'; import '../base/process.dart'; import '../base/version.dart'; import '../build_info.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../macos/xcode.dart'; const bool kBitcodeEnabledDefault = false; @@ -27,7 +27,7 @@ Future<void> validateBitcode(BuildMode buildMode, TargetPlatform targetPlatform, final String? clangVersion = clangResult?.stdout.split('\n').first; final String? engineClangVersion = flutterFrameworkPath == null ? null - : globals.plistParser.getStringValueFromFile( + : globals.plistParser.getValueFromFile( globals.fs.path.join(flutterFrameworkPath, 'Info.plist'), 'ClangVersion', ); diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index b5cb08a46dddb..67f613a2cbfb1 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -19,7 +19,7 @@ import '../build_info.dart'; import '../convert.dart'; import '../device.dart'; import '../device_port_forwarder.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../macos/xcdevice.dart'; import '../project.dart'; import '../protocol_discovery.dart'; diff --git a/packages/flutter_tools/lib/src/ios/ios_emulators.dart b/packages/flutter_tools/lib/src/ios/ios_emulators.dart index 6681a6327f501..de9da80e3e536 100644 --- a/packages/flutter_tools/lib/src/ios/ios_emulators.dart +++ b/packages/flutter_tools/lib/src/ios/ios_emulators.dart @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import '../base/common.dart'; +// @dart = 2.8 + import '../base/process.dart'; import '../device.dart'; import '../emulator.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import 'simulators.dart'; class IOSEmulators extends EmulatorDiscovery { @@ -14,7 +15,7 @@ class IOSEmulators extends EmulatorDiscovery { bool get supportsPlatform => globals.platform.isMacOS; @override - bool get canListAnything => globals.iosWorkflow?.canListEmulators == true; + bool get canListAnything => globals.iosWorkflow.canListEmulators; @override Future<List<Emulator>> get emulators async => getEmulators(); @@ -40,16 +41,12 @@ class IOSEmulator extends Emulator { @override Future<void> launch({bool coldBoot = false}) async { - final String? simulatorPath = globals.xcode?.getSimulatorPath(); - if (simulatorPath == null) { - throwToolExit('Could not find Simulator app'); - } Future<bool> launchSimulator(List<String> additionalArgs) async { final List<String> args = <String>[ 'open', ...additionalArgs, '-a', - simulatorPath, + globals.xcode.getSimulatorPath(), ]; final RunResult launchResult = await globals.processUtils.run(args); @@ -73,7 +70,7 @@ class IOSEmulator extends Emulator { /// Return the list of iOS Simulators (there can only be zero or one). List<IOSEmulator> getEmulators() { - final String? simulatorPath = globals.xcode?.getSimulatorPath(); + final String simulatorPath = globals.xcode.getSimulatorPath(); if (simulatorPath == null) { return <IOSEmulator>[]; } diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index ee902b38ac73a..c2f2ccad5adaa 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -16,7 +16,7 @@ import '../base/utils.dart'; import '../build_info.dart'; import '../cache.dart'; import '../flutter_manifest.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../macos/cocoapod_utils.dart'; import '../macos/xcode.dart'; import '../project.dart'; @@ -32,7 +32,6 @@ import 'migrations/remove_framework_link_and_embedding_migration.dart'; import 'migrations/xcode_build_system_migration.dart'; import 'xcode_build_settings.dart'; import 'xcodeproj.dart'; -import 'xcresult.dart'; class IMobileDevice { IMobileDevice({ @@ -316,97 +315,74 @@ Future<XcodeBuildResult> buildXcodeProject({ Status? buildSubStatus; Status? initialBuildStatus; + Directory? tempDir; + File? scriptOutputPipeFile; - RunResult? buildResult; - XCResult? xcResult; - - final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_ios_build_temp_dir'); - try { - if (globals.logger.hasTerminal) { - scriptOutputPipeFile = tempDir.childFile('pipe_to_stdout'); - globals.os.makePipe(scriptOutputPipeFile.path); - - Future<void> listenToScriptOutputLine() async { - final List<String> lines = await scriptOutputPipeFile!.readAsLines(); - for (final String line in lines) { - if (line == 'done' || line == 'all done') { - buildSubStatus?.stop(); - buildSubStatus = null; - if (line == 'all done') { - return; - } - } else { - initialBuildStatus?.cancel(); - initialBuildStatus = null; - buildSubStatus = globals.logger.startProgress( - line, - progressIndicatorPadding: kDefaultStatusPadding - 7, - ); + if (globals.logger.hasTerminal) { + tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_build_log_pipe.'); + scriptOutputPipeFile = tempDir.childFile('pipe_to_stdout'); + globals.os.makePipe(scriptOutputPipeFile.path); + + Future<void> listenToScriptOutputLine() async { + final List<String> lines = await scriptOutputPipeFile!.readAsLines(); + for (final String line in lines) { + if (line == 'done' || line == 'all done') { + buildSubStatus?.stop(); + buildSubStatus = null; + if (line == 'all done') { + // Free pipe file. + tempDir?.deleteSync(recursive: true); + return; } + } else { + initialBuildStatus?.cancel(); + initialBuildStatus = null; + buildSubStatus = globals.logger.startProgress( + line, + progressIndicatorPadding: kDefaultStatusPadding - 7, + ); } - await listenToScriptOutputLine(); } + await listenToScriptOutputLine(); + } - // Trigger the start of the pipe -> stdout loop. Ignore exceptions. - unawaited(listenToScriptOutputLine()); + // Trigger the start of the pipe -> stdout loop. Ignore exceptions. + unawaited(listenToScriptOutputLine()); - buildCommands.add('SCRIPT_OUTPUT_STREAM_FILE=${scriptOutputPipeFile.absolute.path}'); - } + buildCommands.add('SCRIPT_OUTPUT_STREAM_FILE=${scriptOutputPipeFile.absolute.path}'); + } + + // Don't log analytics for downstream Flutter commands. + // e.g. `flutter build bundle`. + buildCommands.add('FLUTTER_SUPPRESS_ANALYTICS=true'); + buildCommands.add('COMPILER_INDEX_STORE_ENABLE=NO'); + buildCommands.addAll(environmentVariablesAsXcodeBuildSettings(globals.platform)); + if (buildAction == XcodeBuildAction.archive) { buildCommands.addAll(<String>[ - '-resultBundlePath', - tempDir.childFile(_kResultBundlePath).absolute.path, - '-resultBundleVersion', - _kResultBundleVersion + '-archivePath', + globals.fs.path.absolute(app.archiveBundlePath), + 'archive', ]); + } - // Don't log analytics for downstream Flutter commands. - // e.g. `flutter build bundle`. - buildCommands.add('FLUTTER_SUPPRESS_ANALYTICS=true'); - buildCommands.add('COMPILER_INDEX_STORE_ENABLE=NO'); - buildCommands.addAll(environmentVariablesAsXcodeBuildSettings(globals.platform)); - - if (buildAction == XcodeBuildAction.archive) { - buildCommands.addAll(<String>[ - '-archivePath', - globals.fs.path.absolute(app.archiveBundlePath), - 'archive', - ]); - } - - final Stopwatch sw = Stopwatch()..start(); - initialBuildStatus = globals.logger.startProgress('Running Xcode build...'); + final Stopwatch sw = Stopwatch()..start(); + initialBuildStatus = globals.logger.startProgress('Running Xcode build...'); - buildResult = await _runBuildWithRetries(buildCommands, app); + final RunResult? buildResult = await _runBuildWithRetries(buildCommands, app); - // Notifies listener that no more output is coming. - scriptOutputPipeFile?.writeAsStringSync('all done'); - buildSubStatus?.stop(); - buildSubStatus = null; - initialBuildStatus?.cancel(); - initialBuildStatus = null; - globals.printStatus( - 'Xcode ${xcodeBuildActionToString(buildAction)} done.'.padRight(kDefaultStatusPadding + 1) - + getElapsedAsSeconds(sw.elapsed).padLeft(5), - ); - globals.flutterUsage.sendTiming(xcodeBuildActionToString(buildAction), 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds)); + // Notifies listener that no more output is coming. + scriptOutputPipeFile?.writeAsStringSync('all done'); + buildSubStatus?.stop(); + buildSubStatus = null; + initialBuildStatus?.cancel(); + initialBuildStatus = null; + globals.printStatus( + 'Xcode ${xcodeBuildActionToString(buildAction)} done.'.padRight(kDefaultStatusPadding + 1) + + getElapsedAsSeconds(sw.elapsed).padLeft(5), + ); + globals.flutterUsage.sendTiming(xcodeBuildActionToString(buildAction), 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds)); - if (tempDir.existsSync()) { - // Display additional warning and error message from xcresult bundle. - final Directory resultBundle = tempDir.childDirectory(_kResultBundlePath); - if (!resultBundle.existsSync()) { - globals.printTrace('The xcresult bundle are not generated. Displaying xcresult is disabled.'); - } else { - // Discard unwanted errors. See: https://github.com/flutter/flutter/issues/95354 - final XCResultIssueDiscarder warningDiscarder = XCResultIssueDiscarder(typeMatcher: XCResultIssueType.warning); - final XCResultIssueDiscarder dartBuildErrorDiscarder = XCResultIssueDiscarder(messageMatcher: RegExp(r'Command PhaseScriptExecution failed with a nonzero exit code')); - final XCResultGenerator xcResultGenerator = XCResultGenerator(resultPath: resultBundle.absolute.path, xcode: globals.xcode!, processUtils: globals.processUtils); - xcResult = await xcResultGenerator.generate(issueDiscarders: <XCResultIssueDiscarder>[warningDiscarder, dartBuildErrorDiscarder]); - } - } - } finally { - tempDir.deleteSync(recursive: true); - } if (buildResult != null && buildResult.exitCode != 0) { globals.printStatus('Failed to build iOS app'); if (buildResult.stderr.isNotEmpty) { @@ -427,7 +403,6 @@ Future<XcodeBuildResult> buildXcodeProject({ environmentType: environmentType, buildSettings: buildSettings, ), - xcResult: xcResult, ); } else { String? outputDir; @@ -462,7 +437,6 @@ Future<XcodeBuildResult> buildXcodeProject({ await globals.processUtils.run( <String>[ 'rsync', - '-8', // Avoid mangling filenames with encodings that do not match the current locale. '-av', '--delete', expectedOutputDirectory, @@ -492,7 +466,6 @@ Future<XcodeBuildResult> buildXcodeProject({ environmentType: environmentType, buildSettings: buildSettings, ), - xcResult: xcResult, ); } } @@ -612,19 +585,16 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result, Usage flutterUsa logger.printError(' open ios/Runner.xcworkspace'); return; } - - // Handle xcresult errors. - final XCResult? xcResult = result.xcResult; - if (xcResult == null) { - return; - } - if (!xcResult.parseSuccess) { - globals.printTrace('XCResult parsing error: ${xcResult.parsingErrorMessage}'); + if (result.stdout?.contains('Code Sign error') == true) { + logger.printError(''); + logger.printError('It appears that there was a problem signing your application prior to installation on the device.'); + logger.printError(''); + logger.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode'); + logger.printError(' open ios/Runner.xcworkspace'); + logger.printError(''); + logger.printError("Also try selecting 'Product > Build' to fix the problem:"); return; } - for (final XCResultIssue issue in xcResult.issues) { - _handleXCResultIssue(issue: issue, logger: logger); - } } /// xcodebuild <buildaction> parameter (see man xcodebuild for details). @@ -648,7 +618,6 @@ class XcodeBuildResult { this.stdout, this.stderr, this.xcodeBuildExecution, - this.xcResult }); final bool success; @@ -657,10 +626,6 @@ class XcodeBuildResult { final String? stderr; /// The invocation of the build that resulted in this result instance. final XcodeBuildExecution? xcodeBuildExecution; - /// Parsed information in xcresult bundle. - /// - /// Can be null if the bundle is not created during build. - final XCResult? xcResult; } /// Describes an invocation of a Xcode build command. @@ -721,38 +686,3 @@ bool upgradePbxProjWithFlutterAssets(IosProject project, Logger logger) { xcodeProjectFile.writeAsStringSync(buffer.toString()); return true; } - -void _handleXCResultIssue({required XCResultIssue issue, required Logger logger}) { - // Issue summary from xcresult. - final StringBuffer issueSummaryBuffer = StringBuffer(); - issueSummaryBuffer.write(issue.subType ?? 'Unknown'); - issueSummaryBuffer.write(' (Xcode): '); - issueSummaryBuffer.writeln(issue.message ?? ''); - if (issue.location != null ) { - issueSummaryBuffer.writeln(issue.location); - } - final String issueSummary = issueSummaryBuffer.toString(); - - switch (issue.type) { - case XCResultIssueType.error: - logger.printError(issueSummary); - break; - case XCResultIssueType.warning: - logger.printWarning(issueSummary); - break; - } - - // Add more custom output for flutter users. - if (issue.message != null && issue.message!.toLowerCase().contains('provisioning profile')) { - logger.printError(''); - logger.printError('It appears that there was a problem signing your application prior to installation on the device.'); - logger.printError(''); - logger.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode'); - logger.printError(' open ios/Runner.xcworkspace'); - logger.printError(''); - logger.printError("Also try selecting 'Product > Build' to fix the problem:"); - } -} - -const String _kResultBundlePath = 'temporary_xcresult_bundle'; -const String _kResultBundleVersion = '3'; diff --git a/packages/flutter_tools/lib/src/ios/plist_parser.dart b/packages/flutter_tools/lib/src/ios/plist_parser.dart index e17e83b7d8ff1..242c42ae12bf3 100644 --- a/packages/flutter_tools/lib/src/ios/plist_parser.dart +++ b/packages/flutter_tools/lib/src/ios/plist_parser.dart @@ -3,12 +3,12 @@ // found in the LICENSE file. import 'package:process/process.dart'; -import 'package:xml/xml.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; import '../base/process.dart'; +import '../base/utils.dart'; import '../convert.dart'; class PlistParser { @@ -28,109 +28,42 @@ class PlistParser { static const String kCFBundleShortVersionStringKey = 'CFBundleShortVersionString'; static const String kCFBundleExecutable = 'CFBundleExecutable'; - /// Returns the content, converted to XML, of the plist file located at - /// [plistFilePath]. + /// Parses the plist file located at [plistFilePath] and returns the + /// associated map of key/value property list pairs. /// /// If [plistFilePath] points to a non-existent file or a file that's not a - /// valid property list file, this will return null. + /// valid property list file, this will return an empty map. /// /// The [plistFilePath] argument must not be null. - String? plistXmlContent(String plistFilePath) { + Map<String, dynamic> parseFile(String plistFilePath) { + assert(plistFilePath != null); const String executable = '/usr/bin/plutil'; if (!_fileSystem.isFileSync(executable)) { throw const FileNotFoundException(executable); } - final List<String> args = <String>[ - executable, '-convert', 'xml1', '-o', '-', plistFilePath, - ]; + if (!_fileSystem.isFileSync(plistFilePath)) { + return const <String, dynamic>{}; + } + + final String normalizedPlistPath = _fileSystem.path.absolute(plistFilePath); + try { - final String xmlContent = _processUtils.runSync( + final List<String> args = <String>[ + executable, '-convert', 'json', '-o', '-', normalizedPlistPath, + ]; + final String jsonContent = _processUtils.runSync( args, throwOnError: true, ).stdout.trim(); - return xmlContent; + return castStringKeyedMap(json.decode(jsonContent)) ?? const <String, dynamic>{}; } on ProcessException catch (error) { _logger.printTrace('$error'); - return null; - } - } - - /// Parses the plist file located at [plistFilePath] and returns the - /// associated map of key/value property list pairs. - /// - /// If [plistFilePath] points to a non-existent file or a file that's not a - /// valid property list file, this will return an empty map. - /// - /// The [plistFilePath] argument must not be null. - Map<String, Object> parseFile(String plistFilePath) { - assert(plistFilePath != null); - if (!_fileSystem.isFileSync(plistFilePath)) { - return const <String, Object>{}; - } - - final String normalizedPlistPath = _fileSystem.path.absolute(plistFilePath); - - final String? xmlContent = plistXmlContent(normalizedPlistPath); - if (xmlContent == null) { - return const <String, Object>{}; - } - - return _parseXml(xmlContent); - } - - Map<String, Object> _parseXml(String xmlContent) { - final XmlDocument document = XmlDocument.parse(xmlContent); - // First element child is <plist>. The first element child of plist is <dict>. - final XmlElement dictObject = document.firstElementChild!.firstElementChild!; - return _parseXmlDict(dictObject); - } - - Map<String, Object> _parseXmlDict(XmlElement node) { - String? lastKey; - final Map<String, Object> result = <String, Object>{}; - for (final XmlNode child in node.children) { - if (child is XmlElement) { - if (child.name.local == 'key') { - lastKey = child.text; - } else { - assert(lastKey != null); - result[lastKey!] = _parseXmlNode(child)!; - lastKey = null; - } - } - } - - return result; - } - - static final RegExp _nonBase64Pattern = RegExp('[^a-zA-Z0-9+/=]+'); - - Object? _parseXmlNode(XmlElement node) { - switch (node.name.local){ - case 'string': - return node.text; - case 'real': - return double.parse(node.text); - case 'integer': - return int.parse(node.text); - case 'true': - return true; - case 'false': - return false; - case 'date': - return DateTime.parse(node.text); - case 'data': - return base64.decode(node.text.replaceAll(_nonBase64Pattern, '')); - case 'array': - return node.children.whereType<XmlElement>().map<Object?>(_parseXmlNode).whereType<Object>().toList(); - case 'dict': - return _parseXmlDict(node); + return const <String, dynamic>{}; } - return null; } - /// Parses the Plist file located at [plistFilePath] and returns the string - /// value that's associated with the specified [key] within the property list. + /// Parses the Plist file located at [plistFilePath] and returns the value + /// that's associated with the specified [key] within the property list. /// /// If [plistFilePath] points to a non-existent file or a file that's not a /// valid property list file, this will return null. @@ -138,8 +71,9 @@ class PlistParser { /// If [key] is not found in the property list, this will return null. /// /// The [plistFilePath] and [key] arguments must not be null. - String? getStringValueFromFile(String plistFilePath, String key) { + String? getValueFromFile(String plistFilePath, String key) { + assert(key != null); final Map<String, dynamic> parsed = parseFile(plistFilePath); - return parsed[key] as String?; + return parsed[key] as String; } } diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index de3d9bf0973fb..e0544843381fd 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart @@ -20,7 +20,7 @@ import '../convert.dart'; import '../devfs.dart'; import '../device.dart'; import '../device_port_forwarder.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../macos/xcode.dart'; import '../project.dart'; import '../protocol_discovery.dart'; @@ -495,7 +495,7 @@ class IOSSimulator extends Device { // parsing the xcodeproj or configuration files. // See https://github.com/flutter/flutter/issues/31037 for more information. final String plistPath = globals.fs.path.join(package.simulatorBundlePath, 'Info.plist'); - final String? bundleIdentifier = globals.plistParser.getStringValueFromFile(plistPath, PlistParser.kCFBundleIdentifierKey); + final String? bundleIdentifier = globals.plistParser.getValueFromFile(plistPath, PlistParser.kCFBundleIdentifierKey); if (bundleIdentifier == null) { globals.printError('Invalid prebuilt iOS app. Info.plist does not contain bundle identifier'); return LaunchResult.failed(); @@ -545,7 +545,6 @@ class IOSSimulator extends Device { deviceID: id, ); if (!buildResult.success) { - await diagnoseXcodeBuildFailure(buildResult, globals.flutterUsage, globals.logger); throwToolExit('Could not build the application for the simulator.'); } diff --git a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart index ac89218067f56..2f7be52870847 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart @@ -7,7 +7,7 @@ import '../base/file_system.dart'; import '../build_info.dart'; import '../cache.dart'; import '../flutter_manifest.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; String flutterMacOSFrameworkDir(BuildMode mode, FileSystem fileSystem, diff --git a/packages/flutter_tools/lib/src/ios/xcresult.dart b/packages/flutter_tools/lib/src/ios/xcresult.dart index 4f505735f9159..25418b247e8e1 100644 --- a/packages/flutter_tools/lib/src/ios/xcresult.dart +++ b/packages/flutter_tools/lib/src/ios/xcresult.dart @@ -35,11 +35,7 @@ class XCResultGenerator { /// /// Calls `xcrun xcresulttool get --path <resultPath> --format json`, /// then stores the useful information the json into an [XCResult] object. - /// - /// A`issueDiscarders` can be passed to discard any issues that matches the description of any [XCResultIssueDiscarder] in the list. - Future<XCResult> generate( - {List<XCResultIssueDiscarder> issueDiscarders = - const <XCResultIssueDiscarder>[]}) async { + Future<XCResult> generate() async { final RunResult result = await processUtils.run( <String>[ ...xcode.xcrunCommand(), @@ -66,7 +62,7 @@ class XCResultGenerator { return XCResult.failed( errorMessage: 'xcresult parser: Unrecognized top level json format.'); } - return XCResult(resultJson: resultJson, issueDiscarders: issueDiscarders); + return XCResult(resultJson: resultJson); } } @@ -76,21 +72,63 @@ class XCResultGenerator { /// The result contains useful information such as build errors and warnings. class XCResult { /// Parse the `resultJson` and stores useful informations in the returned `XCResult`. - factory XCResult({required Map<String, Object?> resultJson, List<XCResultIssueDiscarder> issueDiscarders = const <XCResultIssueDiscarder>[]}) { + factory XCResult({required Map<String, Object?> resultJson}) { final List<XCResultIssue> issues = <XCResultIssue>[]; - - final Object? issuesMap = resultJson['issues']; + final Object? actionsMap = resultJson['actions']; + if (actionsMap == null || actionsMap is! Map<String, Object?>) { + return XCResult.failed( + errorMessage: 'xcresult parser: Failed to parse the actions map.'); + } + final Object? actionValueList = actionsMap['_values']; + if (actionValueList == null || + actionValueList is! List<Object?> || + actionValueList.isEmpty) { + return XCResult.failed( + errorMessage: 'xcresult parser: Failed to parse the actions map.'); + } + final Object? actionMap = actionValueList.first; + if (actionMap == null || actionMap is! Map<String, Object?>) { + return XCResult.failed( + errorMessage: + 'xcresult parser: Failed to parse the first action map.'); + } + final Object? buildResultMap = actionMap['buildResult']; + if (buildResultMap == null || buildResultMap is! Map<String, Object?>) { + return XCResult.failed( + errorMessage: + 'xcresult parser: Failed to parse the buildResult map.'); + } + final Object? issuesMap = buildResultMap['issues']; if (issuesMap == null || issuesMap is! Map<String, Object?>) { return XCResult.failed( errorMessage: 'xcresult parser: Failed to parse the issues map.'); } + List<XCResultIssue> _parseIssuesFromIssueSummariesJson({ + required XCResultIssueType type, + required Map<String, Object?> issueSummariesJson, + }) { + final List<XCResultIssue> issues = <XCResultIssue>[]; + final Object? errorsList = issueSummariesJson['_values']; + if (errorsList is List<Object?>) { + for (final Object? issueJson in errorsList) { + if (issueJson == null || issueJson is! Map<String, Object?>) { + continue; + } + final XCResultIssue resultIssue = XCResultIssue( + type: type, + issueJson: issueJson, + ); + issues.add(resultIssue); + } + } + return issues; + } final Object? errorSummaries = issuesMap['errorSummaries']; if (errorSummaries is Map<String, Object?>) { issues.addAll(_parseIssuesFromIssueSummariesJson( type: XCResultIssueType.error, issueSummariesJson: errorSummaries, - issueDiscarder: issueDiscarders, )); } @@ -99,7 +137,6 @@ class XCResult { issues.addAll(_parseIssuesFromIssueSummariesJson( type: XCResultIssueType.warning, issueSummariesJson: warningSummaries, - issueDiscarder: issueDiscarders, )); } return XCResult._(issues: issues); @@ -141,9 +178,8 @@ class XCResultIssue { required XCResultIssueType type, required Map<String, Object?> issueJson, }) { - // Parse type. final Object? issueSubTypeMap = issueJson['issueType']; - String? subType; + String subType = ''; if (issueSubTypeMap is Map<String, Object?>) { final Object? subTypeValue = issueSubTypeMap['_value']; if (subTypeValue is String) { @@ -151,8 +187,7 @@ class XCResultIssue { } } - // Parse message. - String? message; + String message = ''; final Object? messageMap = issueJson['message']; if (messageMap is Map<String, Object?>) { final Object? messageValue = messageMap['_value']; @@ -161,31 +196,10 @@ class XCResultIssue { } } - final List<String> warnings = <String>[]; - // Parse url and convert it to a location String. - String? location; - final Object? documentLocationInCreatingWorkspaceMap = - issueJson['documentLocationInCreatingWorkspace']; - if (documentLocationInCreatingWorkspaceMap is Map<String, Object?>) { - final Object? urlMap = documentLocationInCreatingWorkspaceMap['url']; - if (urlMap is Map<String, Object?>) { - final Object? urlValue = urlMap['_value']; - if (urlValue is String) { - location = _convertUrlToLocationString(urlValue); - if (location == null) { - warnings.add( - '(XCResult) The `url` exists but it was failed to be parsed. url: $urlValue'); - } - } - } - } - return XCResultIssue._( type: type, subType: subType, message: message, - location: location, - warnings: warnings, ); } @@ -193,8 +207,6 @@ class XCResultIssue { required this.type, required this.subType, required this.message, - required this.location, - required this.warnings, }); /// The type of the issue. @@ -204,21 +216,12 @@ class XCResultIssue { /// /// This is a more detailed category about the issue. /// The possible values are `Warning`, `Semantic Issue'` etc. - final String? subType; + final String subType; /// Human readable message for the issue. /// /// This can be displayed to user for their information. - final String? message; - - /// The location where the issue occurs. - /// - /// This is a re-formatted version of the "url" value in the json. - /// The format looks like <FileLocation>:<StartingLineNumber>:<StartingColumnNumber>. - final String? location; - - /// Warnings when constructing the issue object. - final List<String> warnings; + final String message; } /// The type of an `XCResultIssue`. @@ -233,119 +236,3 @@ enum XCResultIssueType { /// This is for all the issues under the `errorSummaries` key in the xcresult. error, } - -/// Discards the [XCResultIssue] that matches any of the matchers. -class XCResultIssueDiscarder { - XCResultIssueDiscarder( - {this.typeMatcher, - this.subTypeMatcher, - this.messageMatcher, - this.locationMatcher}) - : assert(typeMatcher != null || - subTypeMatcher != null || - messageMatcher != null || - locationMatcher != null); - - /// The type of the discarder. - /// - /// A [XCResultIssue] should be discarded if its `type` equals to this. - final XCResultIssueType? typeMatcher; - - /// The subType of the discarder. - /// - /// A [XCResultIssue] should be discarded if its `subType` matches the RegExp. - final RegExp? subTypeMatcher; - - /// The message of the discarder. - /// - /// A [XCResultIssue] should be discarded if its `message` matches the RegExp. - final RegExp? messageMatcher; - - /// The location of the discarder. - /// - /// A [XCResultIssue] should be discarded if its `location` matches the RegExp. - final RegExp? locationMatcher; -} - -// A typical location url string looks like file:///foo.swift#CharacterRangeLen=0&EndingColumnNumber=82&EndingLineNumber=7&StartingColumnNumber=82&StartingLineNumber=7. -// -// This function converts it to something like: /foo.swift:<StartingLineNumber>:<StartingColumnNumber>. -String? _convertUrlToLocationString(String url) { - final Uri? fragmentLocation = Uri.tryParse(url); - if (fragmentLocation == null) { - return null; - } - // Parse the fragment as a query of key-values: - final Uri fileLocation = Uri( - path: fragmentLocation.path, - query: fragmentLocation.fragment, - ); - String startingLineNumber = - fileLocation.queryParameters['StartingLineNumber'] ?? ''; - if (startingLineNumber.isNotEmpty) { - startingLineNumber = ':$startingLineNumber'; - } - String startingColumnNumber = - fileLocation.queryParameters['StartingColumnNumber'] ?? ''; - if (startingColumnNumber.isNotEmpty) { - startingColumnNumber = ':$startingColumnNumber'; - } - return '${fileLocation.path}$startingLineNumber$startingColumnNumber'; -} - -// Determine if an `issue` should be discarded based on the `discarder`. -bool _shouldDiscardIssue( - {required XCResultIssue issue, required XCResultIssueDiscarder discarder}) { - if (issue.type == discarder.typeMatcher) { - return true; - } - if (issue.subType != null && - discarder.subTypeMatcher != null && - discarder.subTypeMatcher!.hasMatch(issue.subType!)) { - return true; - } - if (issue.message != null && - discarder.messageMatcher != null && - discarder.messageMatcher!.hasMatch(issue.message!)) { - return true; - } - if (issue.location != null && - discarder.locationMatcher != null && - discarder.locationMatcher!.hasMatch(issue.location!)) { - return true; - } - - return false; -} - -List<XCResultIssue> _parseIssuesFromIssueSummariesJson({ - required XCResultIssueType type, - required Map<String, Object?> issueSummariesJson, - required List<XCResultIssueDiscarder> issueDiscarder, -}) { - final List<XCResultIssue> issues = <XCResultIssue>[]; - final Object? errorsList = issueSummariesJson['_values']; - if (errorsList is List<Object?>) { - for (final Object? issueJson in errorsList) { - if (issueJson == null || issueJson is! Map<String, Object?>) { - continue; - } - final XCResultIssue resultIssue = XCResultIssue( - type: type, - issueJson: issueJson, - ); - bool discard = false; - for (final XCResultIssueDiscarder discarder in issueDiscarder) { - if (_shouldDiscardIssue(issue: resultIssue, discarder: discarder)) { - discard = true; - break; - } - } - if (discard) { - continue; - } - issues.add(resultIssue); - } - } - return issues; -} diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart index e9fd1d07b6881..750915466abf6 100644 --- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart +++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart @@ -35,7 +35,7 @@ import '../compile.dart'; import '../convert.dart'; import '../dart/package_map.dart'; import '../devfs.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../vmservice.dart'; import '../web/bootstrap.dart'; @@ -198,19 +198,19 @@ class WebAssetServer implements AssetReader { address = (await InternetAddress.lookup(hostname)).first; } HttpServer httpServer; - const int kMaxRetries = 4; - for (int i = 0; i <= kMaxRetries; i++) { + dynamic lastError; + for (int i = 0; i < 5; i += 1) { try { httpServer = await HttpServer.bind(address, port ?? await globals.os.findFreePort()); break; - } on SocketException catch (e, s) { - if (i >= kMaxRetries) { - globals.printError('Failed to bind web development server:\n$e', stackTrace: s); - throwToolExit('Failed to bind web development server:\n$e'); - } + } on SocketException catch (error) { + lastError = error; await Future<void>.delayed(const Duration(milliseconds: 100)); } } + if (httpServer == null) { + throwToolExit('Failed to bind web development server:\n$lastError'); + } // Allow rendering in a iframe. httpServer.defaultResponseHeaders.remove('x-frame-options', 'SAMEORIGIN'); @@ -240,11 +240,7 @@ class WebAssetServer implements AssetReader { webBuildDirectory: getWebBuildDirectory(), basePath: server.basePath, ); - runZonedGuarded(() { - shelf.serveRequests(httpServer, releaseAssetServer.handle); - }, (Object e, StackTrace s) { - globals.printTrace('Release asset server: error serving requests: $e:$s'); - }); + shelf.serveRequests(httpServer, releaseAssetServer.handle); return server; } @@ -270,8 +266,9 @@ class WebAssetServer implements AssetReader { }; } - logging.Logger.root.level = logging.Level.ALL; - logging.Logger.root.onRecord.listen(_log); + logging.Logger.root.onRecord.listen((logging.LogRecord event) { + globals.printTrace('${event.loggerName}: ${event.message}'); + }); // In debug builds, spin up DWDS and the full asset server. final Dwds dwds = await dwdsLauncher( @@ -305,11 +302,7 @@ class WebAssetServer implements AssetReader { pipeline.addHandler(server.handleRequest); final shelf.Cascade cascade = shelf.Cascade().add(dwds.handler).add(dwdsHandler); - runZonedGuarded(() { - shelf.serveRequests(httpServer, cascade.handler); - }, (Object e, StackTrace s) { - globals.printTrace('Dwds server: error serving requests: $e:$s'); - }); + shelf.serveRequests(httpServer, cascade.handler); server.dwds = dwds; return server; } @@ -455,11 +448,14 @@ class WebAssetServer implements AssetReader { // Attempt to determine the file's mime type. if this is not provided some // browsers will refuse to render images/show video etc. If the tool // cannot determine a mime type, fall back to application/octet-stream. - final String mimeType = mime.lookupMimeType( + String mimeType; + if (length >= 12) { + mimeType = mime.lookupMimeType( file.path, - headerBytes: await file.openRead(0, mime.defaultMagicNumbersMaxLength).first, - ) ?? _kDefaultMimeType; - + headerBytes: await file.openRead(0, 12).first, + ); + } + mimeType ??= _kDefaultMimeType; headers[HttpHeaders.contentLengthHeader] = length.toString(); headers[HttpHeaders.contentTypeHeader] = mimeType; headers[HttpHeaders.etagHeader] = etag; @@ -999,17 +995,6 @@ class ReleaseAssetServer { } } -void _log(logging.LogRecord event) { - final String error = event.error == null? '': 'Error: ${event.error}'; - if (event.level >= logging.Level.SEVERE) { - globals.printError('${event.loggerName}: ${event.message}$error', stackTrace: event.stackTrace); - } else if (event.level == logging.Level.WARNING) { - globals.printWarning('${event.loggerName}: ${event.message}$error'); - } else { - globals.printTrace('${event.loggerName}: ${event.message}$error'); - } -} - Future<Directory> _loadDwdsDirectory( FileSystem fileSystem, Logger logger) async { final String toolPackagePath = diff --git a/packages/flutter_tools/lib/src/linux/application_package.dart b/packages/flutter_tools/lib/src/linux/application_package.dart index 918cf465687df..0f99299244b08 100644 --- a/packages/flutter_tools/lib/src/linux/application_package.dart +++ b/packages/flutter_tools/lib/src/linux/application_package.dart @@ -7,7 +7,7 @@ import '../base/file_system.dart'; import '../build_info.dart'; import '../cmake.dart'; import '../cmake_project.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; abstract class LinuxApp extends ApplicationPackage { LinuxApp({required String projectBundleId}) : super(id: projectBundleId); diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart index 81c86d5122f4d..c5545e32ff4d7 100644 --- a/packages/flutter_tools/lib/src/linux/build_linux.dart +++ b/packages/flutter_tools/lib/src/linux/build_linux.dart @@ -15,7 +15,7 @@ import '../cmake.dart'; import '../cmake_project.dart'; import '../convert.dart'; import '../flutter_plugins.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../migrations/cmake_custom_command_migration.dart'; // Matches the following error and warning patterns: @@ -29,16 +29,15 @@ final RegExp errorMatcher = RegExp(r'(?:(?:.*:\d+:\d+|clang):\s)?(fatal\s)?(?:er Future<void> buildLinux( LinuxProject linuxProject, BuildInfo buildInfo, { - String? target, + String target = 'lib/main.dart', SizeAnalyzer? sizeAnalyzer, bool needCrossBuild = false, - required TargetPlatform targetPlatform, + TargetPlatform targetPlatform = TargetPlatform.linux_x64, String targetSysroot = '/', }) async { - target ??= 'lib/main.dart'; if (!linuxProject.cmakeFile.existsSync()) { throwToolExit('No Linux desktop project configured. See ' - 'https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' + 'https://flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' 'to learn about adding Linux support to a project.'); } diff --git a/packages/flutter_tools/lib/src/linux/linux_device.dart b/packages/flutter_tools/lib/src/linux/linux_device.dart index 8c0a06598b9f4..1dff8ae14668e 100644 --- a/packages/flutter_tools/lib/src/linux/linux_device.dart +++ b/packages/flutter_tools/lib/src/linux/linux_device.dart @@ -2,6 +2,9 @@ // 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:meta/meta.dart'; import 'package:process/process.dart'; import '../base/file_system.dart'; @@ -20,10 +23,10 @@ import 'linux_workflow.dart'; /// A device that represents a desktop Linux target. class LinuxDevice extends DesktopDevice { LinuxDevice({ - required ProcessManager processManager, - required Logger logger, - required FileSystem fileSystem, - required OperatingSystemUtils operatingSystemUtils, + @required ProcessManager processManager, + @required Logger logger, + @required FileSystem fileSystem, + @required OperatingSystemUtils operatingSystemUtils, }) : _operatingSystemUtils = operatingSystemUtils, super( 'linux', @@ -37,6 +40,8 @@ class LinuxDevice extends DesktopDevice { final OperatingSystemUtils _operatingSystemUtils; + TargetPlatform _targetPlatform; + @override bool isSupported() => true; @@ -44,12 +49,17 @@ class LinuxDevice extends DesktopDevice { String get name => 'Linux'; @override - late final Future<TargetPlatform> targetPlatform = () async { - if (_operatingSystemUtils.hostPlatform == HostPlatform.linux_x64) { - return TargetPlatform.linux_x64; + Future<TargetPlatform> get targetPlatform async { + if (_targetPlatform == null) { + if (_operatingSystemUtils.hostPlatform == HostPlatform.linux_x64) { + _targetPlatform = TargetPlatform.linux_x64; + } else { + _targetPlatform = TargetPlatform.linux_arm64; + } } - return TargetPlatform.linux_arm64; - }(); + + return _targetPlatform; + } @override bool isSupportedForProject(FlutterProject flutterProject) { @@ -59,14 +69,14 @@ class LinuxDevice extends DesktopDevice { @override Future<void> buildForDevice( covariant LinuxApp package, { - String? mainPath, - required BuildInfo buildInfo, + String mainPath, + BuildInfo buildInfo, }) async { await buildLinux( FlutterProject.current().linux, buildInfo, target: mainPath, - targetPlatform: await targetPlatform, + targetPlatform: _targetPlatform, ); } @@ -78,12 +88,12 @@ class LinuxDevice extends DesktopDevice { class LinuxDevices extends PollingDeviceDiscovery { LinuxDevices({ - required Platform platform, - required FeatureFlags featureFlags, - required OperatingSystemUtils operatingSystemUtils, - required FileSystem fileSystem, - required ProcessManager processManager, - required Logger logger, + @required Platform platform, + @required FeatureFlags featureFlags, + @required OperatingSystemUtils operatingSystemUtils, + @required FileSystem fileSystem, + @required ProcessManager processManager, + @required Logger logger, }) : _platform = platform, _linuxWorkflow = LinuxWorkflow( platform: platform, @@ -109,7 +119,7 @@ class LinuxDevices extends PollingDeviceDiscovery { bool get canListAnything => _linuxWorkflow.canListDevices; @override - Future<List<Device>> pollingGetDevices({ Duration? timeout }) async { + Future<List<Device>> pollingGetDevices({ Duration timeout }) async { if (!canListAnything) { return const <Device>[]; } diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart index 5695d1a5751be..40cd33c7e9591 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart @@ -87,7 +87,7 @@ List<String> generateMethodParameters(Message message) { assert(message.placeholders.isNotEmpty); final Placeholder? countPlaceholder = message.isPlural ? message.getCountPlaceholder() : null; return message.placeholders.map((Placeholder placeholder) { - final String? type = placeholder == countPlaceholder ? 'num' : placeholder.type; + final String? type = placeholder == countPlaceholder ? 'int' : placeholder.type; return '$type ${placeholder.name}'; }).toList(); } @@ -177,59 +177,6 @@ String generateNumberFormattingLogic(Message message) { return formatStatements.isEmpty ? '@(none)' : formatStatements.join(); } -/// To make it easier to parse plurals or select messages, temporarily replace -/// each "{placeholder}" parameter with "#placeholder#" for example. -String _replacePlaceholdersBraces( - String translationForMessage, - Iterable<Placeholder> placeholders, - String replacementBraces, -) { - assert(replacementBraces.length == 2); - String easyMessage = translationForMessage; - for (final Placeholder placeholder in placeholders) { - easyMessage = easyMessage.replaceAll( - '{${placeholder.name}}', - '${replacementBraces[0]}${placeholder.name}${replacementBraces[1]}', - ); - } - return easyMessage; -} - -/// Replaces message with the interpolated variable name of the given placeholders -/// with the ability to change braces to something other than {...}. -/// -/// Examples: -/// -/// * Replacing `{userName}`. -/// ```dart -/// final message = 'Hello my name is {userName}'; -/// final transformed = _replacePlaceholdersWithVariables(message, placeholders); -/// // transformed == 'Hello my name is $userName' -/// ``` -/// * Replacing `#choice#`. -/// ```dart -/// final message = 'I would like to have some #choice#'; -/// final transformed = _replacePlaceholdersWithVariables(message, placeholders, '##'); -/// transformed == 'I would like to have some $choice' -/// ``` -String _replacePlaceholdersWithVariables(String message, Iterable<Placeholder> placeholders, [String braces = '{}']) { - assert(braces.length == 2); - String messageWithValues = message; - for (final Placeholder placeholder in placeholders) { - String variable = placeholder.name; - if (placeholder.requiresFormatting) { - variable += 'String'; - } - messageWithValues = messageWithValues.replaceAll( - '${braces[0]}${placeholder.name}${braces[1]}', - _needsCurlyBracketStringInterpolation(messageWithValues, placeholder.name) - ? '\${$variable}' - : '\$$variable' - ); - } - return messageWithValues; -} - String _generatePluralMethod(Message message, String translationForMessage) { if (message.placeholders.isEmpty) { throw L10nException( @@ -239,7 +186,12 @@ String _generatePluralMethod(Message message, String translationForMessage) { ); } - final String easyMessage = _replacePlaceholdersBraces(translationForMessage, message.placeholders, '##'); + // To make it easier to parse the plurals message, temporarily replace each + // "{placeholder}" parameter with "#placeholder#". + String easyMessage = translationForMessage; + for (final Placeholder placeholder in message.placeholders) { + easyMessage = easyMessage.replaceAll('{${placeholder.name}}', '#${placeholder.name}#'); + } final Placeholder countPlaceholder = message.getCountPlaceholder(); const Map<String, String> pluralIds = <String, String>{ @@ -256,13 +208,25 @@ String _generatePluralMethod(Message message, String translationForMessage) { final RegExp expRE = RegExp('($pluralKey)\\s*{([^}]+)}'); final RegExpMatch? match = expRE.firstMatch(easyMessage); if (match != null && match.groupCount == 2) { - final String argValue = _replacePlaceholdersWithVariables(generateString(match.group(2)!), message.placeholders, '##'); + String argValue = generateString(match.group(2)!); + for (final Placeholder placeholder in message.placeholders) { + String variable = placeholder.name; + if (placeholder.requiresFormatting) { + variable += 'String'; + } + argValue = argValue.replaceAll( + '#${placeholder.name}#', + _needsCurlyBracketStringInterpolation(argValue, placeholder.name) + ? '\${$variable}' + : '\$$variable' + ); + } pluralLogicArgs.add(' ${pluralIds[pluralKey]}: $argValue'); } } final List<String> parameters = message.placeholders.map((Placeholder placeholder) { - final String? placeholderType = placeholder == countPlaceholder ? 'num' : placeholder.type; + final String? placeholderType = placeholder == countPlaceholder ? 'int' : placeholder.type; return '$placeholderType ${placeholder.name}'; }).toList(); @@ -317,11 +281,10 @@ String _generateSelectMethod(Message message, String translationForMessage) { ); } - final String easyMessage = _replacePlaceholdersBraces(translationForMessage, message.placeholders, '##'); - final List<String> cases = <String>[]; - final RegExpMatch? selectMatch = LocalizationsGenerator._selectRE.firstMatch(easyMessage); + final RegExpMatch? selectMatch = + LocalizationsGenerator._selectRE.firstMatch(translationForMessage); String? choice; if (selectMatch != null && selectMatch.groupCount == 2) { choice = selectMatch.group(1); @@ -329,10 +292,9 @@ String _generateSelectMethod(Message message, String translationForMessage) { final RegExp patternRE = RegExp(r'\s*([\w\d]+)\s*\{(.*?)\}'); for (final RegExpMatch patternMatch in patternRE.allMatches(pattern)) { if (patternMatch.groupCount == 2) { - String value = patternMatch.group(2)! + final String value = patternMatch.group(2)! .replaceAll("'", r"\'") .replaceAll('"', r'\"'); - value = _replacePlaceholdersWithVariables(value, message.placeholders, '##'); cases.add( " '${patternMatch.group(1)}': '$value'", ); @@ -412,7 +374,21 @@ bool _needsCurlyBracketStringInterpolation(String messageString, String placehol String _generateMethod(Message message, String translationForMessage) { String generateMessage() { - return _replacePlaceholdersWithVariables(generateString(translationForMessage), message.placeholders); + String messageValue = generateString(translationForMessage); + for (final Placeholder placeholder in message.placeholders) { + String variable = placeholder.name; + if (placeholder.requiresFormatting) { + variable += 'String'; + } + messageValue = messageValue.replaceAll( + '{${placeholder.name}}', + _needsCurlyBracketStringInterpolation(messageValue, placeholder.name) + ? '\${$variable}' + : '\$$variable' + ); + } + + return messageValue; } if (message.isPlural) { @@ -1191,12 +1167,6 @@ class LocalizationsGenerator { final String directory = _fs.path.basename(outputDirectory.path); final String outputFileName = _fs.path.basename(baseOutputFile.path); - if (!outputFileName.endsWith('.dart')) { - throw L10nException( - "The 'output-localization-file', $outputFileName, is invalid.\n" - 'The file name must have a .dart extension.' - ); - } final Iterable<String> supportedLocalesCode = supportedLocales.map((LocaleInfo locale) { final String languageCode = locale.languageCode; @@ -1219,18 +1189,10 @@ class LocalizationsGenerator { ); final List<LocaleInfo> allLocales = _allBundles.locales.toList()..sort(); - final int extensionIndex = outputFileName.indexOf('.'); - if (extensionIndex <= 0) { - throw L10nException( - "The 'output-localization-file', $outputFileName, is invalid.\n" - 'The base name cannot be empty.' - ); - } - final String fileName = outputFileName.substring(0, extensionIndex); - final String fileExtension = outputFileName.substring(extensionIndex + 1); + final String fileName = outputFileName.split('.')[0]; for (final LocaleInfo locale in allLocales) { if (isBaseClassLocale(locale, locale.languageCode)) { - final File languageMessageFile = outputDirectory.childFile('${fileName}_$locale.$fileExtension'); + final File languageMessageFile = outputDirectory.childFile('${fileName}_$locale.dart'); // Generate the template for the base class file. Further string // interpolation will be done to determine if there are @@ -1267,9 +1229,9 @@ class LocalizationsGenerator { .map((LocaleInfo locale) { final String library = '${fileName}_${locale.toString()}'; if (useDeferredLoading) { - return "import '$library.$fileExtension' deferred as $library;"; + return "import '$library.dart' deferred as $library;"; } else { - return "import '$library.$fileExtension';"; + return "import '$library.dart';"; } }) .toList() @@ -1315,9 +1277,7 @@ class LocalizationsGenerator { // A pubspec.yaml file is required when using a synthetic package. If it does not // exist, create a blank one. if (useSyntheticPackage) { - final Directory syntheticPackageDirectory = projectDirectory != null - ? projectDirectory!.childDirectory(_defaultSyntheticPackagePath(_fs)) - : _fs.directory(_defaultSyntheticPackagePath(_fs)); + final Directory syntheticPackageDirectory = _fs.directory(_defaultSyntheticPackagePath(_fs)); syntheticPackageDirectory.createSync(recursive: true); final File flutterGenPubspec = syntheticPackageDirectory.childFile('pubspec.yaml'); if (!flutterGenPubspec.existsSync()) { diff --git a/packages/flutter_tools/lib/src/macos/application_package.dart b/packages/flutter_tools/lib/src/macos/application_package.dart index 691a7f345093d..b528d7273ae08 100644 --- a/packages/flutter_tools/lib/src/macos/application_package.dart +++ b/packages/flutter_tools/lib/src/macos/application_package.dart @@ -7,7 +7,7 @@ import '../base/file_system.dart'; import '../base/io.dart'; import '../base/utils.dart'; import '../build_info.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../ios/plist_parser.dart'; import '../xcode_project.dart'; @@ -38,11 +38,10 @@ abstract class MacOSApp extends ApplicationPackage { } return PrebuiltMacOSApp( - uncompressedBundle: bundleInfo.uncompressedBundle, - bundleName: bundleInfo.uncompressedBundle.path, + bundleDir: bundleInfo.bundle, + bundleName: bundleInfo.bundle.path, projectBundleId: bundleInfo.id, executable: bundleInfo.executable, - applicationPackage: applicationBinary, ); } @@ -53,14 +52,14 @@ abstract class MacOSApp extends ApplicationPackage { globals.printError('File "${applicationBundle.path}" does not exist.'); return null; } - Directory uncompressedBundle; + Directory bundleDir; if (entityType == FileSystemEntityType.directory) { final Directory directory = globals.fs.directory(applicationBundle); if (!_isBundleDirectory(directory)) { globals.printError('Folder "${applicationBundle.path}" is not an app bundle.'); return null; } - uncompressedBundle = globals.fs.directory(applicationBundle); + bundleDir = globals.fs.directory(applicationBundle); } else { // Try to unpack as a zip. final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_app.'); @@ -71,7 +70,7 @@ abstract class MacOSApp extends ApplicationPackage { return null; } try { - uncompressedBundle = tempDir + bundleDir = tempDir .listSync() .whereType<Directory>() .singleWhere(_isBundleDirectory); @@ -80,7 +79,7 @@ abstract class MacOSApp extends ApplicationPackage { return null; } } - final String plistPath = globals.fs.path.join(uncompressedBundle.path, 'Contents', 'Info.plist'); + final String plistPath = globals.fs.path.join(bundleDir.path, 'Contents', 'Info.plist'); if (!globals.fs.file(plistPath).existsSync()) { globals.printError('Invalid prebuilt macOS app. Does not contain Info.plist.'); return null; @@ -96,11 +95,11 @@ abstract class MacOSApp extends ApplicationPackage { globals.printError('Invalid prebuilt macOS app. Info.plist does not contain bundle executable'); return null; } - final String executable = globals.fs.path.join(uncompressedBundle.path, 'Contents', 'MacOS', executableName); + final String executable = globals.fs.path.join(bundleDir.path, 'Contents', 'MacOS', executableName); if (!globals.fs.file(executable).existsSync()) { globals.printError('Could not find macOS binary at $executable'); } - return _BundleInfo(executable, id, uncompressedBundle); + return _BundleInfo(executable, id, bundleDir); } @override @@ -111,21 +110,16 @@ abstract class MacOSApp extends ApplicationPackage { String? executable(BuildMode buildMode); } -class PrebuiltMacOSApp extends MacOSApp implements PrebuiltApplicationPackage { +class PrebuiltMacOSApp extends MacOSApp { PrebuiltMacOSApp({ - required this.uncompressedBundle, + required this.bundleDir, required this.bundleName, required this.projectBundleId, required String executable, - required this.applicationPackage, }) : _executable = executable, super(projectBundleId: projectBundleId); - /// The uncompressed bundle of the application. - /// - /// [MacOSApp.fromPrebuiltApp] will uncompress the application into a temporary - /// directory even when an `.zip` file was used to create the [MacOSApp] instance. - final Directory uncompressedBundle; + final Directory bundleDir; final String bundleName; final String projectBundleId; @@ -135,16 +129,10 @@ class PrebuiltMacOSApp extends MacOSApp implements PrebuiltApplicationPackage { String get name => bundleName; @override - String? applicationBundle(BuildMode buildMode) => uncompressedBundle.path; + String? applicationBundle(BuildMode buildMode) => bundleDir.path; @override String? executable(BuildMode buildMode) => _executable; - - /// A [File] or [Directory] pointing to the application bundle. - /// - /// This can be either a `.zip` file or an uncompressed `.app` directory. - @override - final FileSystemEntity applicationPackage; } class BuildableMacOSApp extends MacOSApp { @@ -182,9 +170,9 @@ class BuildableMacOSApp extends MacOSApp { } class _BundleInfo { - _BundleInfo(this.executable, this.id, this.uncompressedBundle); + _BundleInfo(this.executable, this.id, this.bundle); - final Directory uncompressedBundle; + final Directory bundle; final String executable; final String id; } diff --git a/packages/flutter_tools/lib/src/macos/build_macos.dart b/packages/flutter_tools/lib/src/macos/build_macos.dart index c2177505ad0fa..718877743be94 100644 --- a/packages/flutter_tools/lib/src/macos/build_macos.dart +++ b/packages/flutter_tools/lib/src/macos/build_macos.dart @@ -9,7 +9,7 @@ import '../base/logger.dart'; import '../base/project_migrator.dart'; import '../build_info.dart'; import '../convert.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../ios/xcode_build_settings.dart'; import '../ios/xcodeproj.dart'; import '../project.dart'; @@ -31,7 +31,7 @@ Future<void> buildMacOS({ }) async { if (!flutterProject.macos.xcodeWorkspace.existsSync()) { throwToolExit('No macOS desktop project configured. ' - 'See https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' + 'See https://flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' 'to learn about adding macOS support to a project.'); } diff --git a/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart b/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart index fdfd30936962a..930fc187db6c0 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapod_utils.dart @@ -6,7 +6,7 @@ import '../base/fingerprint.dart'; import '../build_info.dart'; import '../cache.dart'; import '../flutter_plugins.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; /// For a given build, determines whether dependencies have changed since the diff --git a/packages/flutter_tools/lib/src/macos/cocoapods.dart b/packages/flutter_tools/lib/src/macos/cocoapods.dart index 8e7a08f62cedb..7a0a689501eae 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapods.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapods.dart @@ -176,7 +176,7 @@ class CocoaPods { final CocoaPodsStatus installation = await evaluateCocoaPodsInstallation; switch (installation) { case CocoaPodsStatus.notInstalled: - _logger.printWarning( + _logger.printError( 'Warning: CocoaPods not installed. Skipping pod install.\n' '$noCocoaPodsConsequence\n' 'To install $cocoaPodsInstallInstructions\n', @@ -184,7 +184,7 @@ class CocoaPods { ); return false; case CocoaPodsStatus.brokenInstall: - _logger.printWarning( + _logger.printError( 'Warning: CocoaPods is installed but broken. Skipping pod install.\n' '$brokenCocoaPodsConsequence\n' 'To re-install $cocoaPodsInstallInstructions\n', @@ -192,7 +192,7 @@ class CocoaPods { ); return false; case CocoaPodsStatus.unknownVersion: - _logger.printWarning( + _logger.printError( 'Warning: Unknown CocoaPods version installed.\n' '$unknownCocoaPodsConsequence\n' 'To upgrade $cocoaPodsInstallInstructions\n', @@ -200,7 +200,7 @@ class CocoaPods { ); break; case CocoaPodsStatus.belowMinimumVersion: - _logger.printWarning( + _logger.printError( 'Warning: CocoaPods minimum required version $cocoaPodsMinimumVersion or greater not installed. Skipping pod install.\n' '$noCocoaPodsConsequence\n' 'To upgrade $cocoaPodsInstallInstructions\n', @@ -208,7 +208,7 @@ class CocoaPods { ); return false; case CocoaPodsStatus.belowRecommendedVersion: - _logger.printWarning( + _logger.printError( 'Warning: CocoaPods recommended version $cocoaPodsRecommendedVersion or greater not installed.\n' 'Pods handling may fail on some projects involving plugins.\n' 'To upgrade $cocoaPodsInstallInstructions\n', @@ -360,7 +360,8 @@ class CocoaPods { ' pod repo update\n', emphasis: true, ); - } else if (stdout.contains('ffi_c.bundle') && stdout.contains('LoadError') && + } else if (stdout.contains('Init_ffi_c') && + stdout.contains('symbol not found') && _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm) { // https://github.com/flutter/flutter/issues/70796 UsageEvent( @@ -405,15 +406,15 @@ class CocoaPods { // plugin_pods = parse_KV_file('../.flutter-plugins') if (xcodeProject.podfile.existsSync() && xcodeProject.podfile.readAsStringSync().contains(".flutter-plugins'")) { - const String warning = 'Warning: Podfile is out of date\n' + const String error = 'Warning: Podfile is out of date\n' '$outOfDatePluginsPodfileConsequence\n' 'To regenerate the Podfile, run:\n'; if (isIos) { - throwToolExit('$warning\n$podfileIosMigrationInstructions\n'); + throwToolExit('$error\n$podfileIosMigrationInstructions\n'); } else { // The old macOS Podfile will work until `.flutter-plugins` is removed. // Warn instead of exit. - _logger.printWarning('$warning\n$podfileMacOSMigrationInstructions\n', emphasis: true); + _logger.printError('$error\n$podfileMacOSMigrationInstructions\n', emphasis: true); } } } diff --git a/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart b/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart index 6943e90325e99..3b34f451d67fa 100644 --- a/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart +++ b/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart @@ -2,8 +2,11 @@ // 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:meta/meta.dart'; import 'package:process/process.dart'; import '../application_package.dart'; @@ -23,10 +26,10 @@ import '../project.dart'; /// https://developer.apple.com/documentation/apple-silicon/running-your-ios-apps-on-macos class MacOSDesignedForIPadDevice extends DesktopDevice { MacOSDesignedForIPadDevice({ - required ProcessManager processManager, - required Logger logger, - required FileSystem fileSystem, - required OperatingSystemUtils operatingSystemUtils, + @required ProcessManager processManager, + @required Logger logger, + @required FileSystem fileSystem, + @required OperatingSystemUtils operatingSystemUtils, }) : _operatingSystemUtils = operatingSystemUtils, super( 'designed-for-ipad', @@ -55,18 +58,18 @@ class MacOSDesignedForIPadDevice extends DesktopDevice { } @override - String? executablePathForDevice(ApplicationPackage package, BuildMode buildMode) => null; + String executablePathForDevice(ApplicationPackage package, BuildMode buildMode) => null; @override Future<LaunchResult> startApp( IOSApp package, { - String? mainPath, - String? route, - required DebuggingOptions debuggingOptions, - Map<String, Object?> platformArgs = const <String, Object>{}, + String mainPath, + String route, + @required DebuggingOptions debuggingOptions, + Map<String, dynamic> platformArgs = const <String, dynamic>{}, bool prebuiltApplication = false, bool ipv6 = false, - String? userIdentifier, + String userIdentifier, }) async { // Only attaching to a running app launched from Xcode is supported. throw UnimplementedError('Building for "$name" is not supported.'); @@ -75,14 +78,14 @@ class MacOSDesignedForIPadDevice extends DesktopDevice { @override Future<bool> stopApp( IOSApp app, { - String? userIdentifier, + String userIdentifier, }) async => false; @override Future<void> buildForDevice( covariant IOSApp package, { - String? mainPath, - required BuildInfo buildInfo, + String mainPath, + BuildInfo buildInfo, }) async { // Only attaching to a running app launched from Xcode is supported. throw UnimplementedError('Building for "$name" is not supported.'); @@ -91,12 +94,12 @@ class MacOSDesignedForIPadDevice extends DesktopDevice { class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery { MacOSDesignedForIPadDevices({ - required Platform platform, - required IOSWorkflow iosWorkflow, - required ProcessManager processManager, - required Logger logger, - required FileSystem fileSystem, - required OperatingSystemUtils operatingSystemUtils, + @required Platform platform, + @required IOSWorkflow iosWorkflow, + @required ProcessManager processManager, + @required Logger logger, + @required FileSystem fileSystem, + @required OperatingSystemUtils operatingSystemUtils, }) : _logger = logger, _platform = platform, _iosWorkflow = iosWorkflow, @@ -125,7 +128,7 @@ class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery { static bool allowDiscovery = false; @override - Future<List<Device>> pollingGetDevices({Duration? timeout}) async { + Future<List<Device>> pollingGetDevices({Duration timeout}) async { if (!canListAnything) { return const <Device>[]; } diff --git a/packages/flutter_tools/lib/src/macos/xcdevice.dart b/packages/flutter_tools/lib/src/macos/xcdevice.dart index 77fa8a0ccd50b..dcd9d588ed055 100644 --- a/packages/flutter_tools/lib/src/macos/xcdevice.dart +++ b/packages/flutter_tools/lib/src/macos/xcdevice.dart @@ -15,7 +15,7 @@ import '../base/process.dart'; import '../build_info.dart'; import '../cache.dart'; import '../convert.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../ios/devices.dart'; import '../ios/ios_deploy.dart'; import '../ios/iproxy.dart'; @@ -415,7 +415,7 @@ class XCDevice { } else { cpuArchitecture = DarwinArch.arm64; } - _logger.printWarning( + _logger.printError( 'Unknown architecture $architecture, defaulting to ' '${getNameForDarwinArch(cpuArchitecture)}', ); diff --git a/packages/flutter_tools/lib/src/macos/xcode.dart b/packages/flutter_tools/lib/src/macos/xcode.dart index 322ff318c91f1..2f77b1e840e0b 100644 --- a/packages/flutter_tools/lib/src/macos/xcode.dart +++ b/packages/flutter_tools/lib/src/macos/xcode.dart @@ -18,11 +18,11 @@ import '../base/version.dart'; import '../build_info.dart'; import '../ios/xcodeproj.dart'; -Version get xcodeRequiredVersion => Version(12, 3, null, text: '12.3'); +Version get xcodeRequiredVersion => Version(12, 0, 1, text: '12.0.1'); /// Diverging this number from the minimum required version will provide a doctor /// warning, not error, that users should upgrade Xcode. -Version get xcodeRecommendedVersion => Version(13, null, null, text: '13'); +Version get xcodeRecommendedVersion => Version(13, 0, 0, text: '13.0.0'); /// SDK name passed to `xcrun --sdk`. Corresponds to undocumented Xcode /// SUPPORTED_PLATFORMS values. diff --git a/packages/flutter_tools/lib/src/mdns_discovery.dart b/packages/flutter_tools/lib/src/mdns_discovery.dart index b4dee608d76f0..75701b62a7085 100644 --- a/packages/flutter_tools/lib/src/mdns_discovery.dart +++ b/packages/flutter_tools/lib/src/mdns_discovery.dart @@ -110,7 +110,7 @@ class MDnsObservatoryDiscovery { return null; } if (srv.length > 1) { - _logger.printWarning('Unexpectedly found more than one observatory report for $domainName ' + _logger.printError('Unexpectedly found more than one observatory report for $domainName ' '- using first one (${srv.first.port}).'); } _logger.printTrace('Checking for authentication code for $domainName'); diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 166eb4767c938..01bd45ef809e2 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -18,9 +18,8 @@ import 'cmake_project.dart'; import 'features.dart'; import 'flutter_manifest.dart'; import 'flutter_plugins.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; import 'platform_plugins.dart'; -import 'reporting/reporting.dart'; import 'template.dart'; import 'xcode_project.dart'; @@ -283,7 +282,7 @@ class FlutterProject { /// registrants for app and module projects only. /// /// Will not create project platform directories if they do not already exist. - Future<void> regeneratePlatformSpecificTooling({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) async { + Future<void> regeneratePlatformSpecificTooling() async { return ensureReadyForPlatformSpecificTooling( androidPlatform: android.existsSync(), iosPlatform: ios.existsSync(), @@ -294,7 +293,6 @@ class FlutterProject { windowsPlatform: featureFlags.isWindowsEnabled && windows.existsSync(), webPlatform: featureFlags.isWebEnabled && web.existsSync(), winUwpPlatform: featureFlags.isWindowsUwpEnabled && windowsUwp.existsSync(), - deprecationBehavior: deprecationBehavior, ); } @@ -308,14 +306,13 @@ class FlutterProject { bool windowsPlatform = false, bool webPlatform = false, bool winUwpPlatform = false, - DeprecationBehavior deprecationBehavior = DeprecationBehavior.none, }) async { if (!directory.existsSync() || hasExampleApp || isPlugin) { return; } await refreshPluginsList(this, iosPlatform: iosPlatform, macOSPlatform: macOSPlatform); if (androidPlatform) { - await android.ensureReadyForPlatformSpecificTooling(deprecationBehavior: deprecationBehavior); + await android.ensureReadyForPlatformSpecificTooling(); } if (iosPlatform) { await ios.ensureReadyForPlatformSpecificTooling(); @@ -347,12 +344,6 @@ class FlutterProject { ); } - void checkForDeprecation({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) { - if (android.existsSync()) { - android.checkForDeprecation(deprecationBehavior: deprecationBehavior); - } - } - /// Returns a json encoded string containing the [appName], [version], and [buildNumber] that is used to generate version.json String getVersionInfo() { final String? buildName = manifest.buildName; @@ -417,9 +408,6 @@ class AndroidProject extends FlutterProjectPlatform { /// True if the parent Flutter project is a module. bool get isModule => parent.isModule; - /// True if the parent Flutter project is a plugin. - bool get isPlugin => parent.isPlugin; - /// True if the Flutter project is using the AndroidX support library. bool get usesAndroidX => parent.usesAndroidX; @@ -490,7 +478,24 @@ class AndroidProject extends FlutterProjectPlatform { return parent.directory.childDirectory('build'); } - Future<void> ensureReadyForPlatformSpecificTooling({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) async { + Future<void> ensureReadyForPlatformSpecificTooling() async { + if (getEmbeddingVersion() == AndroidEmbeddingVersion.v1) { + globals.printStatus( +""" +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Warning +────────────────────────────────────────────────────────────────────────────── +Your Flutter application is created using an older version of the Android +embedding. It's being deprecated in favor of Android embedding v2. Follow the +steps at + +https://flutter.dev/go/android-project-migration + +to migrate your project. +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +""" + ); + } if (isModule && _shouldRegenerateFromTemplate()) { await _regenerateLibrary(); // Add ephemeral host app, if an editable host app does not already exist. @@ -543,74 +548,19 @@ class AndroidProject extends FlutterProjectPlatform { 'projectName': parent.manifest.appName, 'androidIdentifier': androidIdentifier, 'androidX': usesAndroidX, - 'agpVersion': gradle.templateAndroidGradlePluginVersion, - 'kotlinVersion': gradle.templateKotlinGradlePluginVersion, - 'gradleVersion': gradle.templateDefaultGradleVersion, }, printStatusWhenWriting: false, ); } - void checkForDeprecation({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) { - if (deprecationBehavior == DeprecationBehavior.none) { - return; - } - - final AndroidEmbeddingVersionResult result = computeEmbeddingVersion(); - if (result.version != AndroidEmbeddingVersion.v1) { - return; - } - - globals.printStatus( -''' -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Warning -────────────────────────────────────────────────────────────────────────────── -Your Flutter application is created using an older version of the Android -embedding. It is being deprecated in favor of Android embedding v2. Follow the -steps at - -https://flutter.dev/go/android-project-migration - -to migrate your project. You may also pass the --ignore-deprecation flag to -ignore this check and continue with the deprecated v1 embedding. However, -the v1 Android embedding will be removed in future versions of Flutter. -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -The detected reason was: - - ${result.reason} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -'''); - if (deprecationBehavior == DeprecationBehavior.ignore) { - BuildEvent('deprecated-v1-android-embedding-ignored', type: 'gradle', flutterUsage: globals.flutterUsage).send(); - } else { // DeprecationBehavior.exit - BuildEvent('deprecated-v1-android-embedding-failed', type: 'gradle', flutterUsage: globals.flutterUsage).send(); - throwToolExit( - 'Build failed due to use of deprecated Android v1 embedding.', - exitCode: 1, - ); - } - } - AndroidEmbeddingVersion getEmbeddingVersion() { - return computeEmbeddingVersion().version; - } - - AndroidEmbeddingVersionResult computeEmbeddingVersion() { if (isModule) { // A module type's Android project is used in add-to-app scenarios and // only supports the V2 embedding. - return AndroidEmbeddingVersionResult(AndroidEmbeddingVersion.v2, 'Is add-to-app module'); - } - if (isPlugin) { - // Plugins do not use an appManifest, so we stop here. - // - // TODO(garyq): This method does not currently check for code references to - // the v1 embedding, we should check for this once removal is further along. - return AndroidEmbeddingVersionResult(AndroidEmbeddingVersion.v2, 'Is plugin'); + return AndroidEmbeddingVersion.v2; } if (appManifestFile == null || !appManifestFile.existsSync()) { - return AndroidEmbeddingVersionResult(AndroidEmbeddingVersion.v1, 'No `${appManifestFile.absolute.path}` file'); + return AndroidEmbeddingVersion.v1; } XmlDocument document; try { @@ -622,25 +572,19 @@ The detected reason was: throwToolExit('Error reading $appManifestFile even though it exists. ' 'Please ensure that you have read permission to this file and try again.'); } - for (final XmlElement application in document.findAllElements('application')) { - final String? applicationName = application.getAttribute('android:name'); - if (applicationName == 'io.flutter.app.FlutterApplication') { - return AndroidEmbeddingVersionResult(AndroidEmbeddingVersion.v1, '${appManifestFile.absolute.path} uses `android:name="io.flutter.app.FutterApplication"`'); - } - } for (final XmlElement metaData in document.findAllElements('meta-data')) { final String? name = metaData.getAttribute('android:name'); if (name == 'flutterEmbedding') { final String? embeddingVersionString = metaData.getAttribute('android:value'); if (embeddingVersionString == '1') { - return AndroidEmbeddingVersionResult(AndroidEmbeddingVersion.v1, '${appManifestFile.absolute.path} `<meta-data android:name="flutterEmbedding"` has value 1'); + return AndroidEmbeddingVersion.v1; } if (embeddingVersionString == '2') { - return AndroidEmbeddingVersionResult(AndroidEmbeddingVersion.v2, '${appManifestFile.absolute.path} `<meta-data android:name="flutterEmbedding"` has value 2'); + return AndroidEmbeddingVersion.v2; } } } - return AndroidEmbeddingVersionResult(AndroidEmbeddingVersion.v1, 'No `<meta-data android:name="flutterEmbedding" android:value="2"/>` in ${appManifestFile.absolute.path}'); + return AndroidEmbeddingVersion.v1; } } @@ -652,29 +596,6 @@ enum AndroidEmbeddingVersion { v2, } -/// Data class that holds the results of checking for embedding version. -/// -/// This class includes the reason why a particular embedding was selected. -class AndroidEmbeddingVersionResult { - AndroidEmbeddingVersionResult(this.version, this.reason); - - /// The embedding version. - AndroidEmbeddingVersion version; - - /// The reason why the embedding version was selected. - String reason; -} - -// What the tool should do when encountering deprecated API in applications. -enum DeprecationBehavior { - // The command being run does not care about deprecation status. - none, - // The command should continue and ignore the deprecation warning. - ignore, - // The command should exit the tool. - exit, -} - /// Represents the web sub-project of a Flutter project. class WebProject extends FlutterProjectPlatform { WebProject._(this.parent); diff --git a/packages/flutter_tools/lib/src/proxy_validator.dart b/packages/flutter_tools/lib/src/proxy_validator.dart index 31a9631d3dbbf..c2b7133a87905 100644 --- a/packages/flutter_tools/lib/src/proxy_validator.dart +++ b/packages/flutter_tools/lib/src/proxy_validator.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'base/io.dart'; import 'base/platform.dart'; import 'doctor_validator.dart'; @@ -44,7 +43,7 @@ class ProxyValidator extends DoctorValidator { else ...<ValidationMessage>[ ValidationMessage('NO_PROXY is $_noProxy'), - for (final String host in await _getLoopbackAddresses()) + for (String host in const <String>['127.0.0.1', 'localhost']) if (_noProxy.contains(host)) ValidationMessage('NO_PROXY contains $host') else @@ -60,21 +59,4 @@ class ProxyValidator extends DoctorValidator { messages, ); } - - Future<List<String>> _getLoopbackAddresses() async { - final List<String> loopBackAddresses = <String>['localhost']; - - final List<NetworkInterface> networkInterfaces = - await listNetworkInterfaces(includeLinkLocal: true, includeLoopback: true); - - for (final NetworkInterface networkInterface in networkInterfaces) { - for (final InternetAddress internetAddress in networkInterface.addresses) { - if (internetAddress.isLoopback) { - loopBackAddresses.add(internetAddress.address); - } - } - } - - return loopBackAddresses; - } } diff --git a/packages/flutter_tools/lib/src/reporting/crash_reporting.dart b/packages/flutter_tools/lib/src/reporting/crash_reporting.dart index da9b4cde9ab9a..d6f4f94ecea90 100644 --- a/packages/flutter_tools/lib/src/reporting/crash_reporting.dart +++ b/packages/flutter_tools/lib/src/reporting/crash_reporting.dart @@ -12,7 +12,6 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/os.dart'; import '../base/platform.dart'; -import '../doctor.dart'; import '../project.dart'; import 'github_template.dart'; import 'reporting.dart'; @@ -50,7 +49,7 @@ class CrashDetails { final String command; final Object error; final StackTrace stackTrace; - final DoctorText doctorText; + final String doctorText; } /// Reports information about the crash to the user. @@ -93,7 +92,7 @@ class CrashReporter { details.command, details.error, details.stackTrace, - await details.doctorText.piiStrippedText, + details.doctorText, ); _logger.printStatus('$gitHubTemplateURL\n', wrap: false); } diff --git a/packages/flutter_tools/lib/src/reporting/github_template.dart b/packages/flutter_tools/lib/src/reporting/github_template.dart index ed13ad1661f26..f98d1b038e72f 100644 --- a/packages/flutter_tools/lib/src/reporting/github_template.dart +++ b/packages/flutter_tools/lib/src/reporting/github_template.dart @@ -110,9 +110,8 @@ $doctorText ${_projectMetadataInformation()} '''; - final String fullURL = 'https://github.com/flutter/flutter/issues' - '/new' // We split this here to appease our lint that looks for bad "new bug" links. - '?title=${Uri.encodeQueryComponent(title)}' + final String fullURL = 'https://github.com/flutter/flutter/issues/new?' + 'title=${Uri.encodeQueryComponent(title)}' '&body=${Uri.encodeQueryComponent(body)}' '&labels=${Uri.encodeQueryComponent('tool,severe: crash')}'; diff --git a/packages/flutter_tools/lib/src/reporting/reporting.dart b/packages/flutter_tools/lib/src/reporting/reporting.dart index 60471274868ef..16fb3de475e7c 100644 --- a/packages/flutter_tools/lib/src/reporting/reporting.dart +++ b/packages/flutter_tools/lib/src/reporting/reporting.dart @@ -18,7 +18,7 @@ import '../build_info.dart'; import '../dart/language_version.dart'; import '../doctor_validator.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../version.dart'; import 'first_run.dart'; diff --git a/packages/flutter_tools/lib/src/resident_devtools_handler.dart b/packages/flutter_tools/lib/src/resident_devtools_handler.dart index 2b26ac53cab39..628c1a9f43f83 100644 --- a/packages/flutter_tools/lib/src/resident_devtools_handler.dart +++ b/packages/flutter_tools/lib/src/resident_devtools_handler.dart @@ -60,10 +60,7 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler { bool launchedInBrowser = false; @override - DevToolsServerAddress get activeDevToolsServer { - assert(!_readyToAnnounce || _devToolsLauncher?.activeDevToolsServer != null); - return _devToolsLauncher?.activeDevToolsServer; - } + DevToolsServerAddress get activeDevToolsServer => _devToolsLauncher?.activeDevToolsServer; @override bool get readyToAnnounce => _readyToAnnounce; @@ -75,7 +72,6 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler { Uri devToolsServerAddress, @required List<FlutterDevice> flutterDevices, }) async { - assert(!_readyToAnnounce); if (!_residentRunner.supportsServiceProtocol || _devToolsLauncher == null) { return; } @@ -86,20 +82,14 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler { _served = true; } await _devToolsLauncher.ready; - // Do not attempt to print debugger list if the connection has failed or if we're shutting down. - if (_devToolsLauncher.activeDevToolsServer == null || _shutdown) { - assert(!_readyToAnnounce); + // Do not attempt to print debugger list if the connection has failed. + if (_devToolsLauncher.activeDevToolsServer == null) { return; } final List<FlutterDevice> devicesWithExtension = await _devicesWithExtensions(flutterDevices); await _maybeCallDevToolsUriServiceExtension(devicesWithExtension); await _callConnectedVmServiceUriExtension(devicesWithExtension); - if (_shutdown) { - // If we're shutting down, no point reporting the debugger list. - return; - } _readyToAnnounce = true; - assert(_devToolsLauncher.activeDevToolsServer != null); if (_residentRunner.reportedDebuggers) { // Since the DevTools only just became available, we haven't had a chance to // report their URLs yet. Do so now. @@ -258,7 +248,6 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler { return; } _shutdown = true; - _readyToAnnounce = false; await _devToolsLauncher.close(); } } diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index f843809c4bea1..04c95973a9bc3 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -35,7 +35,7 @@ import 'convert.dart'; import 'devfs.dart'; import 'device.dart'; import 'features.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; import 'project.dart'; import 'resident_devtools_handler.dart'; import 'run_cold.dart'; @@ -1178,7 +1178,7 @@ abstract class ResidentRunner extends ResidentHandlers { ); if (!_lastBuild.success) { for (final ExceptionMeasurement exceptionMeasurement in _lastBuild.exceptions.values) { - globals.printError( + globals.logger.printError( exceptionMeasurement.exception.toString(), stackTrace: globals.logger.isVerbose ? exceptionMeasurement.stackTrace @@ -1186,7 +1186,7 @@ abstract class ResidentRunner extends ResidentHandlers { ); } } - globals.printTrace('complete'); + globals.logger.printTrace('complete'); } @protected @@ -1241,7 +1241,7 @@ abstract class ResidentRunner extends ResidentHandlers { if (_dillOutputPath != null) { return; } - globals.printTrace('Caching compiled dill'); + globals.logger.printTrace('Caching compiled dill'); final File outputDill = globals.fs.file(dillOutputPath); if (outputDill.existsSync()) { final String copyPath = getDefaultCachedKernelPath( @@ -1561,7 +1561,7 @@ class TerminalHandler { _logger.printTrace('Deleting pid file (${_actualPidFile.path}).'); _actualPidFile.deleteSync(); } on FileSystemException catch (error) { - _logger.printWarning('Failed to delete pid file (${_actualPidFile.path}): ${error.message}'); + _logger.printError('Failed to delete pid file (${_actualPidFile.path}): ${error.message}'); } _actualPidFile = null; } diff --git a/packages/flutter_tools/lib/src/run_cold.dart b/packages/flutter_tools/lib/src/run_cold.dart index 0656a99d7f8b5..431ed5fa24de6 100644 --- a/packages/flutter_tools/lib/src/run_cold.dart +++ b/packages/flutter_tools/lib/src/run_cold.dart @@ -13,7 +13,7 @@ import 'base/file_system.dart'; import 'base/logger.dart'; import 'build_info.dart'; import 'device.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; import 'resident_devtools_handler.dart'; import 'resident_runner.dart'; import 'tracing.dart'; @@ -77,8 +77,8 @@ class ColdRunner extends ResidentRunner { return result; } } - } on Exception catch (err, stack) { - globals.printError('$err\n$stack'); + } on Exception catch (err) { + globals.printError(err.toString()); appFailedToStart(); return 1; } diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 7f2460884bb6d..556347315b723 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -25,7 +25,7 @@ import 'dart/package_map.dart'; import 'devfs.dart'; import 'device.dart'; import 'features.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; import 'project.dart'; import 'reporting/reporting.dart'; import 'resident_devtools_handler.dart'; @@ -603,20 +603,14 @@ class HotRunner extends ResidentRunner { // are not thread-safe, and thus must be run on the same thread that // would be blocked by the pause. Simply un-pausing is not sufficient, // because this does not prevent the isolate from immediately hitting - // a breakpoint (for example if the breakpoint was placed in a loop - // or in a frequently called method) or an exception. Instead, all - // breakpoints are first disabled and exception pause mode set to - // None, and then the isolate resumed. - // These settings to not need restoring as Hot Restart results in - // new isolates, which will be configured by the editor as they are - // started. - final List<Future<void>> breakpointAndExceptionRemoval = <Future<void>>[ - device.vmService.service.setIsolatePauseMode(isolate.id, - exceptionPauseMode: vm_service.ExceptionPauseMode.kNone), + // a breakpoint, for example if the breakpoint was placed in a loop + // or in a frequently called method. Instead, all breakpoints are first + // disabled and then the isolate resumed. + final List<Future<void>> breakpointRemoval = <Future<void>>[ for (final vm_service.Breakpoint breakpoint in isolate.breakpoints) device.vmService.service.removeBreakpoint(isolate.id, breakpoint.id) ]; - await Future.wait(breakpointAndExceptionRemoval); + await Future.wait(breakpointRemoval); await device.vmService.service.resume(view.uiIsolate.id); } })); diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 6a69357e23388..339829997646b 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:args/args.dart'; import 'package:args/command_runner.dart'; import 'package:file/file.dart'; @@ -24,7 +26,7 @@ import '../dart/package_map.dart'; import '../dart/pub.dart'; import '../device.dart'; import '../features.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import 'flutter_command_runner.dart'; @@ -68,7 +70,7 @@ class FlutterCommandResult { /// Optional data that can be appended to the timing event. /// https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#timingLabel /// Do not add PII. - final List<String>? timingLabelParts; + final List<String> timingLabelParts; /// Optional epoch time when the command's non-interactive wait time is /// complete during the command's execution. Use to measure user perceivable @@ -76,7 +78,7 @@ class FlutterCommandResult { /// /// [FlutterCommand] will automatically measure and report the command's /// complete time if not overridden. - final DateTime? endTimeOverride; + final DateTime endTimeOverride; @override String toString() { @@ -90,6 +92,7 @@ class FlutterCommandResult { case ExitStatus.killed: return 'killed'; } + return null; // dead code, remove with null safety migration } } @@ -115,7 +118,6 @@ class FlutterOptions { static const String kDeferredComponents = 'deferred-components'; static const String kAndroidProjectArgs = 'android-project-arg'; static const String kInitializeFromDill = 'initialize-from-dill'; - static const String kFatalWarnings = 'fatal-warnings'; } /// flutter command categories for usage. @@ -129,7 +131,7 @@ abstract class FlutterCommand extends Command<void> { /// The currently executing command (or sub-command). /// /// Will be `null` until the top-most command has begun execution. - static FlutterCommand? get current => context.get<FlutterCommand>(); + static FlutterCommand get current => context.get<FlutterCommand>(); /// The option name for a custom observatory port. static const String observatoryPortOption = 'observatory-port'; @@ -166,7 +168,7 @@ abstract class FlutterCommand extends Command<void> { ); @override - FlutterCommandRunner? get runner => super.runner as FlutterCommandRunner?; + FlutterCommandRunner get runner => super.runner as FlutterCommandRunner; bool _requiresPubspecYaml = false; @@ -179,10 +181,6 @@ abstract class FlutterCommand extends Command<void> { bool _usesIpv6Flag = false; - bool _usesFatalWarnings = false; - - DeprecationBehavior get deprecationBehavior => DeprecationBehavior.none; - bool get shouldRunPub => _usesPubOption && boolArg('pub'); bool get shouldUpdateCache => true; @@ -199,7 +197,7 @@ abstract class FlutterCommand extends Command<void> { _requiresPubspecYaml = true; } - void usesWebOptions({ required bool verboseHelp }) { + void usesWebOptions({ @required bool verboseHelp }) { argParser.addOption('web-hostname', defaultsTo: 'localhost', help: @@ -210,6 +208,7 @@ abstract class FlutterCommand extends Command<void> { hide: !verboseHelp, ); argParser.addOption('web-port', + defaultsTo: null, help: 'The host port to serve the web application from. If not provided, the tool ' 'will select a random open port on the host.', hide: !verboseHelp, @@ -242,11 +241,13 @@ abstract class FlutterCommand extends Command<void> { hide: !verboseHelp, ); argParser.addFlag('web-allow-expose-url', + defaultsTo: false, help: 'Enables daemon-to-editor requests (app.exposeUrl) for exposing URLs ' 'when running on remote machines.', hide: !verboseHelp, ); argParser.addFlag('web-run-headless', + defaultsTo: false, help: 'Launches the browser in headless mode. Currently only Chrome ' 'supports this option.', hide: !verboseHelp, @@ -276,22 +277,12 @@ abstract class FlutterCommand extends Command<void> { _usesTargetOption = true; } - void usesFatalWarningsOption({ required bool verboseHelp }) { - argParser.addFlag(FlutterOptions.kFatalWarnings, - hide: !verboseHelp, - help: 'Causes the command to fail if warnings are sent to the console ' - 'during its execution.' - ); - _usesFatalWarnings = true; - } - String get targetFile { - if (argResults?.wasParsed('target') == true) { - return stringArg('target')!; + if (argResults.wasParsed('target')) { + return stringArg('target'); } - final List<String>? rest = argResults?.rest; - if (rest != null && rest.isNotEmpty) { - return rest.first; + if (argResults.rest.isNotEmpty) { + return argResults.rest.first; } return bundle.defaultMainPath; } @@ -299,12 +290,12 @@ abstract class FlutterCommand extends Command<void> { /// Path to the Dart's package config file. /// /// This can be overridden by some of its subclasses. - String? get packagesPath => globalResults?['packages'] as String?; + String get packagesPath => globalResults['packages'] as String; /// The value of the `--filesystem-scheme` argument. /// /// This can be overridden by some of its subclasses. - String? get fileSystemScheme => + String get fileSystemScheme => argParser.options.containsKey(FlutterOptions.kFileSystemScheme) ? stringArg(FlutterOptions.kFileSystemScheme) : null; @@ -312,7 +303,7 @@ abstract class FlutterCommand extends Command<void> { /// The values of the `--filesystem-root` argument. /// /// This can be overridden by some of its subclasses. - List<String>? get fileSystemRoots => + List<String> get fileSystemRoots => argParser.options.containsKey(FlutterOptions.kFileSystemRoot) ? stringsArg(FlutterOptions.kFileSystemRoot) : null; @@ -329,7 +320,7 @@ abstract class FlutterCommand extends Command<void> { /// /// The `hide` argument indicates whether or not to hide these options when /// the user asks for help. - void usesFilesystemOptions({ required bool hide }) { + void usesFilesystemOptions({ @required bool hide }) { argParser ..addOption('output-dill', hide: hide, @@ -351,7 +342,7 @@ abstract class FlutterCommand extends Command<void> { } /// Adds options for connecting to the Dart VM observatory port. - void usesPortOptions({ required bool verboseHelp }) { + void usesPortOptions({ @required bool verboseHelp }) { argParser.addOption(observatoryPortOption, help: '(deprecated; use host-vmservice-port instead) ' 'Listen to the given port for an observatory debugger connection.\n' @@ -373,7 +364,7 @@ abstract class FlutterCommand extends Command<void> { _usesPortOption = true; } - void addDevToolsOptions({required bool verboseHelp}) { + void addDevToolsOptions({@required bool verboseHelp}) { argParser.addFlag( kEnableDevTools, hide: !verboseHelp, @@ -391,7 +382,7 @@ abstract class FlutterCommand extends Command<void> { ); } - void addDdsOptions({required bool verboseHelp}) { + void addDdsOptions({@required bool verboseHelp}) { argParser.addOption('dds-port', help: 'When this value is provided, the Dart Development Service (DDS) will be ' 'bound to the provided port.\n' @@ -416,61 +407,55 @@ abstract class FlutterCommand extends Command<void> { ); } - late final bool enableDds = () { - bool ddsEnabled = false; - if (argResults?.wasParsed('disable-dds') == true) { - if (argResults?.wasParsed('dds') == true) { - throwToolExit( - 'The "--[no-]dds" and "--[no-]disable-dds" arguments are mutually exclusive. Only specify "--[no-]dds".'); - } - ddsEnabled = !boolArg('disable-dds'); - // TODO(ianh): enable the following code once google3 is migrated away from --disable-dds (and add test to flutter_command_test.dart) - if (false) { // ignore: dead_code - if (ddsEnabled) { - globals.printWarning('${globals.logger.terminal - .warningMark} The "--no-disable-dds" argument is deprecated and redundant, and should be omitted.'); - } else { - globals.printWarning('${globals.logger.terminal - .warningMark} The "--disable-dds" argument is deprecated. Use "--no-dds" instead.'); + bool _ddsEnabled; + bool get enableDds { + if (_ddsEnabled == null) { + if (argResults.wasParsed('disable-dds')) { + if (argResults.wasParsed('dds')) { + throwToolExit('The "--[no-]dds" and "--[no-]disable-dds" arguments are mutually exclusive. Only specify "--[no-]dds".'); + } + _ddsEnabled = !boolArg('disable-dds'); + // TODO(ianh): enable the following code once google3 is migrated away from --disable-dds (and add test to flutter_command_test.dart) + if (false) { // ignore: dead_code + if (_ddsEnabled) { + globals.printError('${globals.logger.terminal.warningMark} The "--no-disable-dds" argument is deprecated and redundant, and should be omitted.'); + } else { + globals.printError('${globals.logger.terminal.warningMark} The "--disable-dds" argument is deprecated. Use "--no-dds" instead.'); + } } + } else { + _ddsEnabled = boolArg('dds'); } - } else { - ddsEnabled = boolArg('dds'); } - return ddsEnabled; - }(); + return _ddsEnabled; + } - bool get _hostVmServicePortProvided => argResults?.wasParsed('observatory-port') == true || - argResults?.wasParsed('host-vmservice-port') == true; + bool get _hostVmServicePortProvided => argResults.wasParsed('observatory-port') || + argResults.wasParsed('host-vmservice-port'); int _tryParseHostVmservicePort() { - final String? observatoryPort = stringArg('observatory-port'); - final String? hostPort = stringArg('host-vmservice-port'); - if (observatoryPort == null && hostPort == null) { - throwToolExit('Invalid port for `--observatory-port/--host-vmservice-port`'); - } try { - return int.parse((observatoryPort ?? hostPort)!); + return int.parse(stringArg('observatory-port') ?? stringArg('host-vmservice-port')); } on FormatException catch (error) { throwToolExit('Invalid port for `--observatory-port/--host-vmservice-port`: $error'); } } int get ddsPort { - if (argResults?.wasParsed('dds-port') != true && _hostVmServicePortProvided) { + if (!argResults.wasParsed('dds-port') && _hostVmServicePortProvided) { // If an explicit DDS port is _not_ provided, use the host-vmservice-port for DDS. return _tryParseHostVmservicePort(); - } else if (argResults?.wasParsed('dds-port') == true) { + } else if (argResults.wasParsed('dds-port')) { // If an explicit DDS port is provided, use dds-port for DDS. - return int.tryParse(stringArg('dds-port')!) ?? 0; + return int.tryParse(stringArg('dds-port')) ?? 0; } // Otherwise, DDS can bind to a random port. return 0; } - Uri? get devToolsServerAddress { - if (argResults?.wasParsed(kDevToolsServerAddress) == true) { - final Uri? uri = Uri.tryParse(stringArg(kDevToolsServerAddress)!); + Uri get devToolsServerAddress { + if (argResults.wasParsed(kDevToolsServerAddress)) { + final Uri uri = Uri.tryParse(stringArg(kDevToolsServerAddress)); if (uri != null && uri.host.isNotEmpty && uri.port != 0) { return uri; } @@ -485,19 +470,19 @@ abstract class FlutterCommand extends Command<void> { /// specified. /// /// If no port is set, returns null. - int? get hostVmservicePort { + int get hostVmservicePort { if (!_usesPortOption || !_hostVmServicePortProvided) { return null; } - if (argResults?.wasParsed('observatory-port') == true && - argResults?.wasParsed('host-vmservice-port') == true) { + if (argResults.wasParsed('observatory-port') && + argResults.wasParsed('host-vmservice-port')) { throwToolExit('Only one of "--observatory-port" and ' '"--host-vmservice-port" may be specified.'); } // If DDS is enabled and no explicit DDS port is provided, use the // host-vmservice-port for DDS instead and bind the VM service to a random // port. - if (enableDds && argResults?.wasParsed('dds-port') != true) { + if (enableDds && !argResults.wasParsed('dds-port')) { return null; } return _tryParseHostVmservicePort(); @@ -506,13 +491,12 @@ abstract class FlutterCommand extends Command<void> { /// Gets the vmservice port provided to in the 'device-vmservice-port' option. /// /// If no port is set, returns null. - int? get deviceVmservicePort { - final String? devicePort = stringArg('device-vmservice-port'); - if (!_usesPortOption || devicePort == null) { + int get deviceVmservicePort { + if (!_usesPortOption || argResults['device-vmservice-port'] == null) { return null; } try { - return int.parse(devicePort); + return int.parse(stringArg('device-vmservice-port')); } on FormatException catch (error) { throwToolExit('Invalid port for `--device-vmservice-port`: $error'); } @@ -520,6 +504,7 @@ abstract class FlutterCommand extends Command<void> { void addPublishPort({ bool enabledByDefault = true, bool verboseHelp = false }) { argParser.addFlag('publish-port', + negatable: true, hide: !verboseHelp, help: 'Publish the VM service port over mDNS. Disable to prevent the ' 'local network permission app dialog in debug and profile build modes (iOS devices only).', @@ -529,7 +514,7 @@ abstract class FlutterCommand extends Command<void> { bool get disablePortPublication => !boolArg('publish-port'); - void usesIpv6Flag({required bool verboseHelp}) { + void usesIpv6Flag({@required bool verboseHelp}) { argParser.addFlag(ipv6Flag, negatable: false, help: 'Binds to IPv6 localhost instead of IPv4 when the flutter tool ' @@ -540,7 +525,7 @@ abstract class FlutterCommand extends Command<void> { _usesIpv6Flag = true; } - bool? get ipv6 => _usesIpv6Flag ? boolArg('ipv6') : null; + bool get ipv6 => _usesIpv6Flag ? boolArg('ipv6') : null; void usesBuildNumberOption() { argParser.addOption('build-number', @@ -607,20 +592,22 @@ abstract class FlutterCommand extends Command<void> { /// Whether this command should report null safety analytics. bool get reportNullSafety => false; - late final Duration? deviceDiscoveryTimeout = () { - if (argResults?.options.contains(FlutterOptions.kDeviceTimeout) == true - && argResults?.wasParsed(FlutterOptions.kDeviceTimeout) == true) { - final int? timeoutSeconds = int.tryParse(stringArg(FlutterOptions.kDeviceTimeout)!); + Duration get deviceDiscoveryTimeout { + if (_deviceDiscoveryTimeout == null + && argResults.options.contains(FlutterOptions.kDeviceTimeout) + && argResults.wasParsed(FlutterOptions.kDeviceTimeout)) { + final int timeoutSeconds = int.tryParse(stringArg(FlutterOptions.kDeviceTimeout)); if (timeoutSeconds == null) { throwToolExit( 'Could not parse "--${FlutterOptions.kDeviceTimeout}" argument. It must be an integer.'); } - return Duration(seconds: timeoutSeconds); + _deviceDiscoveryTimeout = Duration(seconds: timeoutSeconds); } - return null; - }(); + return _deviceDiscoveryTimeout; + } + Duration _deviceDiscoveryTimeout; void addBuildModeFlags({ - required bool verboseHelp, + @required bool verboseHelp, bool defaultToRelease = true, bool excludeDebug = false, bool excludeRelease = false, @@ -682,7 +669,7 @@ abstract class FlutterCommand extends Command<void> { ); } - void addBundleSkSLPathOption({ required bool hide }) { + void addBundleSkSLPathOption({ @required bool hide }) { argParser.addOption(FlutterOptions.kBundleSkSLPathOption, help: 'A path to a file containing precompiled SkSL shaders generated ' 'during "flutter run". These can be included in an application to ' @@ -693,24 +680,26 @@ abstract class FlutterCommand extends Command<void> { } void addTreeShakeIconsFlag({ - bool? enabledByDefault + bool enabledByDefault }) { argParser.addFlag('tree-shake-icons', + negatable: true, defaultsTo: enabledByDefault ?? kIconTreeShakerEnabledDefault, help: 'Tree shake icon fonts so that only glyphs used by the application remain.', ); } - void addShrinkingFlag({ required bool verboseHelp }) { + void addShrinkingFlag({ @required bool verboseHelp }) { argParser.addFlag('shrink', + negatable: true, hide: !verboseHelp, help: 'This flag has no effect. Code shrinking is always enabled in release builds. ' 'To learn more, see: https://developer.android.com/studio/build/shrink-code' ); } - void addNullSafetyModeOptions({ required bool hide }) { + void addNullSafetyModeOptions({ @required bool hide }) { argParser.addFlag(FlutterOptions.kNullSafety, help: 'Whether to override the inferred null safety mode. This allows null-safe ' @@ -731,12 +720,13 @@ abstract class FlutterCommand extends Command<void> { /// Enables support for the hidden options --extra-front-end-options and /// --extra-gen-snapshot-options. - void usesExtraDartFlagOptions({ required bool verboseHelp }) { + void usesExtraDartFlagOptions({ @required bool verboseHelp }) { argParser.addMultiOption(FlutterOptions.kExtraFrontEndOptions, aliases: <String>[ kExtraFrontEndOptions ], // supported for historical reasons help: 'A comma-separated list of additional command line arguments that will be passed directly to the Dart front end. ' 'For example, "--${FlutterOptions.kExtraFrontEndOptions}=--enable-experiment=nonfunction-type-aliases".', valueHelp: '--foo,--bar', + splitCommas: true, hide: !verboseHelp, ); argParser.addMultiOption(FlutterOptions.kExtraGenSnapshotOptions, @@ -745,6 +735,7 @@ abstract class FlutterCommand extends Command<void> { '(Only used in "--profile" or "--release" builds.) ' 'For example, "--${FlutterOptions.kExtraGenSnapshotOptions}=--no-strip".', valueHelp: '--foo,--bar', + splitCommas: true, hide: !verboseHelp, ); } @@ -766,7 +757,7 @@ abstract class FlutterCommand extends Command<void> { ); } - void addEnableExperimentation({ required bool hide }) { + void addEnableExperimentation({ @required bool hide }) { argParser.addMultiOption( FlutterOptions.kEnableExperiment, help: @@ -819,7 +810,7 @@ abstract class FlutterCommand extends Command<void> { ); } - void usesInitializeFromDillOption({ required bool hide }) { + void usesInitializeFromDillOption({ @required bool hide }) { argParser.addOption(FlutterOptions.kInitializeFromDill, help: 'Initializes the resident compiler with a specific kernel file instead of ' 'the default cached location.', @@ -829,6 +820,7 @@ abstract class FlutterCommand extends Command<void> { void addMultidexOption({ bool hide = false }) { argParser.addFlag('multidex', + negatable: true, defaultsTo: true, help: 'When enabled, indicates that the app should be built with multidex support. This ' 'flag adds the dependencies for multidex when the minimum android sdk is 20 or ' @@ -836,17 +828,8 @@ abstract class FlutterCommand extends Command<void> { ); } - void addIgnoreDeprecationOption({ bool hide = false }) { - argParser.addFlag('ignore-deprecation', - negatable: false, - help: 'Indicates that the app should ignore deprecation warnings and continue to build ' - 'using deprecated APIs. Use of this flag may cause your app to fail to build when ' - 'deprecated APIs are removed.', - ); - } - /// Adds build options common to all of the desktop build commands. - void addCommonDesktopBuildOptions({ required bool verboseHelp }) { + void addCommonDesktopBuildOptions({ @required bool verboseHelp }) { addBuildModeFlags(verboseHelp: verboseHelp); addBuildPerformanceFile(hide: !verboseHelp); addBundleSkSLPathOption(hide: !verboseHelp); @@ -867,7 +850,7 @@ abstract class FlutterCommand extends Command<void> { /// explicitly specified. /// /// Use [getBuildMode] to obtain the actual effective build mode. - BuildMode defaultBuildMode = BuildMode.debug; + BuildMode defaultBuildMode; BuildMode getBuildMode() { // No debug when _excludeDebug is true. @@ -883,7 +866,7 @@ abstract class FlutterCommand extends Command<void> { ]; if (modeFlags.where((bool flag) => flag).length > 1) { throw UsageException('Only one of "--debug", "--profile", "--jit-release", ' - 'or "--release" can be specified.', ''); + 'or "--release" can be specified.', null); } if (debugResult) { return BuildMode.debug; @@ -909,7 +892,7 @@ abstract class FlutterCommand extends Command<void> { ); } - void usesTrackWidgetCreation({ bool hasEffect = true, required bool verboseHelp }) { + void usesTrackWidgetCreation({ bool hasEffect = true, @required bool verboseHelp }) { argParser.addFlag( 'track-widget-creation', hide: !hasEffect && !verboseHelp, @@ -922,6 +905,7 @@ abstract class FlutterCommand extends Command<void> { void usesAnalyzeSizeFlag() { argParser.addFlag( FlutterOptions.kAnalyzeSize, + defaultsTo: false, help: 'Whether to produce additional profile information for artifact output size. ' 'This flag is only supported on "--release" builds. When building for Android, a single ' 'ABI must be specified at a time with the "--target-platform" flag. When building for iOS, ' @@ -944,11 +928,11 @@ abstract class FlutterCommand extends Command<void> { /// /// Throws a [ToolExit] if the current set of options is not compatible with /// each other. - Future<BuildInfo> getBuildInfo({ BuildMode? forcedBuildMode, File? forcedTargetFile }) async { + Future<BuildInfo> getBuildInfo({ BuildMode forcedBuildMode, File forcedTargetFile }) async { final bool trackWidgetCreation = argParser.options.containsKey('track-widget-creation') && boolArg('track-widget-creation'); - final String? buildNumber = argParser.options.containsKey('build-number') + final String buildNumber = argParser.options.containsKey('build-number') ? stringArg('build-number') : null; @@ -978,7 +962,7 @@ abstract class FlutterCommand extends Command<void> { } } - String? codeSizeDirectory; + String codeSizeDirectory; if (argParser.options.containsKey(FlutterOptions.kAnalyzeSize) && boolArg(FlutterOptions.kAnalyzeSize)) { Directory directory = globals.fsUtils.getUniqueDirectory( globals.fs.directory(getBuildDirectory()), @@ -996,13 +980,13 @@ abstract class FlutterCommand extends Command<void> { // Explicitly check for `true` and `false` so that `null` results in not // passing a flag. Examine the entrypoint file to determine if it // is opted in or out. - final bool wasNullSafetyFlagParsed = argResults?.wasParsed(FlutterOptions.kNullSafety) == true; + final bool wasNullSafetyFlagParsed = argResults.wasParsed(FlutterOptions.kNullSafety); if (!wasNullSafetyFlagParsed && (argParser.options.containsKey('target') || forcedTargetFile != null)) { final File entrypointFile = forcedTargetFile ?? globals.fs.file(targetFile); final LanguageVersion languageVersion = determineLanguageVersion( entrypointFile, packageConfig.packageOf(entrypointFile.absolute.uri), - Cache.flutterRoot!, + Cache.flutterRoot, ); // Extra frontend options are only provided if explicitly // requested. @@ -1027,7 +1011,7 @@ abstract class FlutterCommand extends Command<void> { final bool dartObfuscation = argParser.options.containsKey(FlutterOptions.kDartObfuscationOption) && boolArg(FlutterOptions.kDartObfuscationOption); - final String? splitDebugInfoPath = argParser.options.containsKey(FlutterOptions.kSplitDebugInfoOption) + final String splitDebugInfoPath = argParser.options.containsKey(FlutterOptions.kSplitDebugInfoOption) ? stringArg(FlutterOptions.kSplitDebugInfoOption) : null; @@ -1053,10 +1037,10 @@ abstract class FlutterCommand extends Command<void> { } final bool treeShakeIcons = argParser.options.containsKey('tree-shake-icons') - && buildMode.isPrecompiled == true + && buildMode.isPrecompiled && boolArg('tree-shake-icons'); - final String? bundleSkSLPath = argParser.options.containsKey(FlutterOptions.kBundleSkSLPathOption) + final String bundleSkSLPath = argParser.options.containsKey(FlutterOptions.kBundleSkSLPathOption) ? stringArg(FlutterOptions.kBundleSkSLPathOption) : null; @@ -1064,7 +1048,7 @@ abstract class FlutterCommand extends Command<void> { throwToolExit('No SkSL shader bundle found at $bundleSkSLPath.'); } - final String? performanceMeasurementFile = argParser.options.containsKey(FlutterOptions.kPerformanceMeasurementFile) + final String performanceMeasurementFile = argParser.options.containsKey(FlutterOptions.kPerformanceMeasurementFile) ? stringArg(FlutterOptions.kPerformanceMeasurementFile) : null; @@ -1073,7 +1057,7 @@ abstract class FlutterCommand extends Command<void> { : <String>[]; if (argParser.options.containsKey('web-renderer')) { - dartDefines = updateDartDefines(dartDefines, stringArg('web-renderer')!); + dartDefines = updateDartDefines(dartDefines, stringArg('web-renderer')); } return BuildInfo(buildMode, @@ -1081,10 +1065,10 @@ abstract class FlutterCommand extends Command<void> { ? stringArg('flavor') : null, trackWidgetCreation: trackWidgetCreation, - extraFrontEndOptions: extraFrontEndOptions.isNotEmpty + extraFrontEndOptions: extraFrontEndOptions?.isNotEmpty ?? false ? extraFrontEndOptions : null, - extraGenSnapshotOptions: extraGenSnapshotOptions.isNotEmpty + extraGenSnapshotOptions: extraGenSnapshotOptions?.isNotEmpty ?? false ? extraGenSnapshotOptions : null, fileSystemRoots: fileSystemRoots, @@ -1118,10 +1102,10 @@ abstract class FlutterCommand extends Command<void> { /// The path to send to Google Analytics. Return null here to disable /// tracking of the command. - Future<String?> get usagePath async { + Future<String> get usagePath async { if (parent is FlutterCommand) { - final FlutterCommand? commandParent = parent as FlutterCommand?; - final String? path = await commandParent?.usagePath; + final FlutterCommand commandParent = parent as FlutterCommand; + final String path = await commandParent.usagePath; // Don't report for parents that return null for usagePath. return path == null ? null : '$path/$name'; } else { @@ -1146,28 +1130,18 @@ abstract class FlutterCommand extends Command<void> { name: 'command', overrides: <Type, Generator>{FlutterCommand: () => this}, body: () async { - if (_usesFatalWarnings) { - globals.logger.fatalWarnings = boolArg(FlutterOptions.kFatalWarnings); - } // Prints the welcome message if needed. globals.flutterUsage.printWelcome(); _printDeprecationWarning(); - final String? commandPath = await usagePath; - if (commandPath != null) { - _registerSignalHandlers(commandPath, startTime); - } + final String commandPath = await usagePath; + _registerSignalHandlers(commandPath, startTime); FlutterCommandResult commandResult = FlutterCommandResult.fail(); try { commandResult = await verifyThenRunCommand(commandPath); } finally { final DateTime endTime = globals.systemClock.now(); globals.printTrace(userMessages.flutterElapsedTime(name, getElapsedAsMilliseconds(endTime.difference(startTime)))); - if (commandPath != null) { - _sendPostUsage(commandPath, commandResult, startTime, endTime); - } - if (_usesFatalWarnings) { - globals.logger.checkForFatalLogs(); - } + _sendPostUsage(commandPath, commandResult, startTime, endTime); } }, ); @@ -1175,12 +1149,13 @@ abstract class FlutterCommand extends Command<void> { void _printDeprecationWarning() { if (deprecated) { - globals.printWarning( + globals.printError( '${globals.logger.terminal.warningMark} The "$name" command is deprecated and ' 'will be removed in a future version of Flutter. ' 'See https://flutter.dev/docs/development/tools/sdk/releases ' - 'for previous releases of Flutter.\n', + 'for previous releases of Flutter.', ); + globals.printError(''); } } @@ -1192,10 +1167,7 @@ abstract class FlutterCommand extends Command<void> { && dartDefines.any((String d) => d.startsWith('FLUTTER_WEB_USE_SKIA='))) { dartDefinesSet.removeWhere((String d) => d.startsWith('FLUTTER_WEB_USE_SKIA=')); } - final Iterable<String>? webRendererDefine = _webRendererDartDefines[webRenderer]; - if (webRendererDefine != null) { - dartDefinesSet.addAll(webRendererDefine); - } + dartDefinesSet.addAll(_webRendererDartDefines[webRenderer]); return dartDefinesSet.toList(); } @@ -1235,7 +1207,7 @@ abstract class FlutterCommand extends Command<void> { if (commandResult.exitStatus != null) getEnumName(commandResult.exitStatus), if (commandResult.timingLabelParts?.isNotEmpty ?? false) - ...?commandResult.timingLabelParts, + ...commandResult.timingLabelParts, ]; final String label = labels @@ -1261,7 +1233,7 @@ abstract class FlutterCommand extends Command<void> { /// then call this method to execute the command /// rather than calling [runCommand] directly. @mustCallSuper - Future<FlutterCommandResult> verifyThenRunCommand(String? commandPath) async { + Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async { globals.preRunValidator.validate(); // Populate the cache. We call this before pub get below so that the // sky_engine package is available in the flutter cache for pub to find. @@ -1275,12 +1247,10 @@ abstract class FlutterCommand extends Command<void> { await validateCommand(); - final FlutterProject project = FlutterProject.current(); - project.checkForDeprecation(deprecationBehavior: deprecationBehavior); - if (shouldRunPub) { + final FlutterProject project = FlutterProject.current(); final Environment environment = Environment( - artifacts: globals.artifacts!, + artifacts: globals.artifacts, logger: globals.logger, cacheDir: globals.cache.getRoot(), engineVersion: globals.flutterVersion.engineRevision, @@ -1345,21 +1315,21 @@ abstract class FlutterCommand extends Command<void> { /// devices and criteria entered by the user on the command line. /// If no device can be found that meets specified criteria, /// then print an error message and return null. - Future<List<Device>?> findAllTargetDevices({ + Future<List<Device>> findAllTargetDevices({ bool includeUnsupportedDevices = false, }) async { - if (!globals.doctor!.canLaunchAnything) { + if (!globals.doctor.canLaunchAnything) { globals.printError(userMessages.flutterNoDevelopmentDevice); return null; } - final DeviceManager deviceManager = globals.deviceManager!; + final DeviceManager deviceManager = globals.deviceManager; List<Device> devices = await deviceManager.findTargetDevices( includeUnsupportedDevices ? null : FlutterProject.current(), timeout: deviceDiscoveryTimeout, ); if (devices.isEmpty && deviceManager.hasSpecifiedDeviceId) { - globals.printStatus(userMessages.flutterNoMatchingDevice(deviceManager.specifiedDeviceId!)); + globals.printStatus(userMessages.flutterNoMatchingDevice(deviceManager.specifiedDeviceId)); return null; } else if (devices.isEmpty) { if (deviceManager.hasSpecifiedAllDevices) { @@ -1372,12 +1342,12 @@ abstract class FlutterCommand extends Command<void> { final StringBuffer result = StringBuffer(); result.writeln(userMessages.flutterFoundButUnsupportedDevices); result.writeAll( - (await Device.descriptions(unsupportedDevices)) + await Device.descriptions(unsupportedDevices) .map((String desc) => desc) .toList(), '\n', ); - result.writeln(); + result.writeln(''); result.writeln(userMessages.flutterMissPlatformProjects( Device.devicesPlatformTypes(unsupportedDevices), )); @@ -1386,7 +1356,7 @@ abstract class FlutterCommand extends Command<void> { return null; } else if (devices.length > 1 && !deviceManager.hasSpecifiedAllDevices) { if (deviceManager.hasSpecifiedDeviceId) { - globals.printStatus(userMessages.flutterFoundSpecifiedDevices(devices.length, deviceManager.specifiedDeviceId!)); + globals.printStatus(userMessages.flutterFoundSpecifiedDevices(devices.length, deviceManager.specifiedDeviceId)); } else { globals.printStatus(userMessages.flutterSpecifyDeviceWithAllOption); devices = await deviceManager.getAllConnectedDevices(); @@ -1405,16 +1375,16 @@ abstract class FlutterCommand extends Command<void> { /// /// If [includeUnsupportedDevices] is true, the tool does not filter /// the list by the current project support list. - Future<Device?> findTargetDevice({ + Future<Device> findTargetDevice({ bool includeUnsupportedDevices = false, }) async { - List<Device>? deviceList = await findAllTargetDevices(includeUnsupportedDevices: includeUnsupportedDevices); + List<Device> deviceList = await findAllTargetDevices(includeUnsupportedDevices: includeUnsupportedDevices); if (deviceList == null) { return null; } if (deviceList.length > 1) { globals.printStatus(userMessages.flutterSpecifyDevice); - deviceList = await globals.deviceManager!.getAllConnectedDevices(); + deviceList = await globals.deviceManager.getAllConnectedDevices(); globals.printStatus(''); await Device.printDevices(deviceList, globals.logger); return null; @@ -1425,7 +1395,7 @@ abstract class FlutterCommand extends Command<void> { @protected @mustCallSuper Future<void> validateCommand() async { - if (_requiresPubspecYaml && globalResults?.wasParsed('packages') != true) { + if (_requiresPubspecYaml && !globalResults.wasParsed('packages')) { // Don't expect a pubspec.yaml file if the user passed in an explicit .packages file path. // If there is no pubspec in the current directory, look in the parent @@ -1464,26 +1434,23 @@ abstract class FlutterCommand extends Command<void> { description, '', 'Global options:', - '${runner?.argParser.usage}', + runner.argParser.usage, '', usageWithoutDescription, ].join('\n'); return help; } - ApplicationPackageFactory? applicationPackages; - - /// Gets the parsed command-line option named [name] as a `bool`. - bool boolArg(String name) => argResults?[name] as bool? ?? false; + ApplicationPackageFactory applicationPackages; - /// Gets the parsed command-line option named [name] as a `String`. - String? stringArg(String name) => argResults?[name] as String?; + /// Gets the parsed command-line option named [name] as `bool`. + bool boolArg(String name) => argResults[name] as bool; - /// Gets the parsed command-line option named [name] as an `int`. - int? intArg(String name) => argResults?[name] as int?; + /// Gets the parsed command-line option named [name] as `String`. + String stringArg(String name) => argResults[name] as String; /// Gets the parsed command-line option named [name] as `List<String>`. - List<String> stringsArg(String name) => argResults?[name] as List<String>? ?? <String>[]; + List<String> stringsArg(String name) => argResults[name] as List<String>; } /// A mixin which applies an implementation of [requiredArtifacts] that only @@ -1494,7 +1461,7 @@ mixin DeviceBasedDevelopmentArtifacts on FlutterCommand { // If there are no attached devices, use the default configuration. // Otherwise, only add development artifacts which correspond to a // connected device. - final List<Device> devices = await globals.deviceManager!.getDevices(); + final List<Device> devices = await globals.deviceManager.getDevices(); if (devices.isEmpty) { return super.requiredArtifacts; } @@ -1503,7 +1470,7 @@ mixin DeviceBasedDevelopmentArtifacts on FlutterCommand { }; for (final Device device in devices) { final TargetPlatform targetPlatform = await device.targetPlatform; - final DevelopmentArtifact? developmentArtifact = artifactFromTargetPlatform(targetPlatform); + final DevelopmentArtifact developmentArtifact = artifactFromTargetPlatform(targetPlatform); if (developmentArtifact != null) { artifacts.add(developmentArtifact); } @@ -1515,7 +1482,7 @@ mixin DeviceBasedDevelopmentArtifacts on FlutterCommand { // Returns the development artifact for the target platform, or null // if none is supported @protected -DevelopmentArtifact? artifactFromTargetPlatform(TargetPlatform targetPlatform) { +DevelopmentArtifact artifactFromTargetPlatform(TargetPlatform targetPlatform) { switch (targetPlatform) { case TargetPlatform.android: case TargetPlatform.android_arm: @@ -1552,6 +1519,7 @@ DevelopmentArtifact? artifactFromTargetPlatform(TargetPlatform targetPlatform) { } return null; } + return null; } /// Returns true if s is either null, empty or is solely made of whitespace characters (as defined by String.trim). diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart index 396756808e863..595772da8cc8f 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:args/args.dart'; import 'package:args/command_runner.dart'; import 'package:completion/completion.dart'; @@ -16,7 +18,7 @@ import '../base/user_messages.dart'; import '../base/utils.dart'; import '../cache.dart'; import '../convert.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../tester/flutter_tester.dart'; import '../web/web_device.dart'; @@ -43,12 +45,14 @@ class FlutterCommandRunner extends CommandRunner<void> { argParser.addFlag('prefixed-errors', negatable: false, help: 'Causes lines sent to stderr to be prefixed with "ERROR:".', - hide: !verboseHelp); + hide: !verboseHelp, + defaultsTo: false); argParser.addFlag('quiet', negatable: false, hide: !verboseHelp, help: 'Reduce the amount of output from some commands.'); argParser.addFlag('wrap', + negatable: true, hide: !verboseHelp, help: 'Toggles output word wrapping, regardless of whether or not the output is a terminal.', defaultsTo: true); @@ -56,7 +60,8 @@ class FlutterCommandRunner extends CommandRunner<void> { hide: !verboseHelp, help: 'Sets the output wrap column. If not set, uses the width of the terminal. No ' 'wrapping occurs if not writing to a terminal. Use "--no-wrap" to turn off wrapping ' - 'when connected to a terminal.'); + 'when connected to a terminal.', + defaultsTo: null); argParser.addOption('device-id', abbr: 'd', help: 'Target device id or name (prefixes allowed).'); @@ -68,10 +73,12 @@ class FlutterCommandRunner extends CommandRunner<void> { hide: !verboseHelp, help: 'When used with the "--version" flag, outputs the information using JSON.'); argParser.addFlag('color', + negatable: true, hide: !verboseHelp, help: 'Whether to use terminal colors (requires support for ANSI escape sequences).', defaultsTo: true); argParser.addFlag('version-check', + negatable: true, defaultsTo: true, hide: !verboseHelp, help: 'Allow Flutter to check for updates when this command runs.'); @@ -151,12 +158,12 @@ class FlutterCommandRunner extends CommandRunner<void> { usageException(error.message); } - Command<void>? command = commands[error.commands.first]; + Command<void> command = commands[error.commands.first]; for (final String commandName in error.commands.skip(1)) { - command = command?.subcommands[commandName]; + command = command.subcommands[commandName]; } - command!.usageException(error.message); + command.usageException(error.message); } } @@ -177,12 +184,12 @@ class FlutterCommandRunner extends CommandRunner<void> { @override Future<void> runCommand(ArgResults topLevelResults) async { - final Map<Type, Object?> contextOverrides = <Type, Object?>{}; + final Map<Type, dynamic> contextOverrides = <Type, dynamic>{}; // Don't set wrapColumns unless the user said to: if it's set, then all // wrapping will occur at this width explicitly, and won't adapt if the // terminal size changes during a run. - int? wrapColumn; + int wrapColumn; if (topLevelResults.wasParsed('wrap-column')) { try { wrapColumn = int.parse(topLevelResults['wrap-column'] as String); @@ -201,53 +208,53 @@ class FlutterCommandRunner extends CommandRunner<void> { : globals.stdio.terminalColumns != null && topLevelResults['wrap'] as bool; contextOverrides[OutputPreferences] = OutputPreferences( wrapText: useWrapping, - showColor: topLevelResults['color'] as bool?, + showColor: topLevelResults['color'] as bool, wrapColumn: wrapColumn, ); - if ((topLevelResults['show-test-device'] as bool?) == true || + if (topLevelResults['show-test-device'] as bool || topLevelResults['device-id'] == FlutterTesterDevices.kTesterDeviceId) { FlutterTesterDevices.showFlutterTesterDevice = true; } - if ((topLevelResults['show-web-server-device'] as bool?) == true || + if (topLevelResults['show-web-server-device'] as bool || topLevelResults['device-id'] == WebServerDevice.kWebServerDeviceId) { WebServerDevice.showWebServerDevice = true; } // Set up the tooling configuration. - final EngineBuildPaths? engineBuildPaths = await globals.localEngineLocator?.findEnginePath( - topLevelResults['local-engine-src-path'] as String?, - topLevelResults['local-engine'] as String?, - topLevelResults['packages'] as String?, + final EngineBuildPaths engineBuildPaths = await globals.localEngineLocator.findEnginePath( + topLevelResults['local-engine-src-path'] as String, + topLevelResults['local-engine'] as String, + topLevelResults['packages'] as String, ); if (engineBuildPaths != null) { - contextOverrides.addAll(<Type, Object?>{ + contextOverrides.addAll(<Type, dynamic>{ Artifacts: Artifacts.getLocalEngine(engineBuildPaths), }); } await context.run<void>( - overrides: contextOverrides.map<Type, Generator>((Type type, Object? value) { + overrides: contextOverrides.map<Type, Generator>((Type type, dynamic value) { return MapEntry<Type, Generator>(type, () => value); }), body: () async { - globals.logger.quiet = (topLevelResults['quiet'] as bool?) == true; + globals.logger.quiet = topLevelResults['quiet'] as bool; if (globals.platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') { await globals.cache.lock(); } - if ((topLevelResults['suppress-analytics'] as bool?) == true) { + if (topLevelResults['suppress-analytics'] as bool) { globals.flutterUsage.suppressAnalytics = true; } globals.flutterVersion.ensureVersionFile(); - final bool machineFlag = topLevelResults['machine'] as bool? ?? false; + final bool machineFlag = topLevelResults['machine'] as bool; final bool ci = await globals.botDetector.isRunningOnBot; final bool redirectedCompletion = !globals.stdio.hasTerminal && (topLevelResults.command?.name ?? '').endsWith('-completion'); final bool isMachine = machineFlag || ci || redirectedCompletion; - final bool versionCheckFlag = topLevelResults['version-check'] as bool? ?? false; + final bool versionCheckFlag = topLevelResults['version-check'] as bool; final bool explicitVersionCheckPassed = topLevelResults.wasParsed('version-check') && versionCheckFlag; if (topLevelResults.command?.name != 'upgrade' && @@ -256,16 +263,16 @@ class FlutterCommandRunner extends CommandRunner<void> { } // See if the user specified a specific device. - globals.deviceManager?.specifiedDeviceId = topLevelResults['device-id'] as String?; + globals.deviceManager.specifiedDeviceId = topLevelResults['device-id'] as String; - if ((topLevelResults['version'] as bool?) == true) { + if (topLevelResults['version'] as bool) { globals.flutterUsage.sendCommand('version'); globals.flutterVersion.fetchTagsAndUpdate(); String status; if (machineFlag) { final Map<String, Object> jsonOut = globals.flutterVersion.toJson(); if (jsonOut != null) { - jsonOut['flutterRoot'] = Cache.flutterRoot!; + jsonOut['flutterRoot'] = Cache.flutterRoot; } status = const JsonEncoder.withIndent(' ').convert(jsonOut); } else { @@ -285,7 +292,7 @@ class FlutterCommandRunner extends CommandRunner<void> { /// Get the root directories of the repo - the directories containing Dart packages. List<String> getRepoRoots() { - final String root = globals.fs.path.absolute(Cache.flutterRoot!); + final String root = globals.fs.path.absolute(Cache.flutterRoot); // not bin, and not the root return <String>['dev', 'examples', 'packages'].map<String>((String item) { return globals.fs.path.join(root, item); diff --git a/packages/flutter_tools/lib/src/sksl_writer.dart b/packages/flutter_tools/lib/src/sksl_writer.dart index 6ac6e3ddd20f8..dac647ea3a1f3 100644 --- a/packages/flutter_tools/lib/src/sksl_writer.dart +++ b/packages/flutter_tools/lib/src/sksl_writer.dart @@ -11,7 +11,7 @@ import 'base/logger.dart'; import 'build_info.dart'; import 'convert.dart'; import 'device.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; Future<String?> sharedSkSlWriter(Device device, Map<String, Object> data, { File? outputFile, diff --git a/packages/flutter_tools/lib/src/template.dart b/packages/flutter_tools/lib/src/template.dart index da0fe4a54b0e2..851de59c1703e 100644 --- a/packages/flutter_tools/lib/src/template.dart +++ b/packages/flutter_tools/lib/src/template.dart @@ -38,7 +38,7 @@ const List<String> kReservedKotlinKeywords = <String>['when', 'in']; /// Files in the destination will contain none of the '.tmpl', '.copy.tmpl', /// 'img.tmpl', or '-<language>.tmpl' extensions. class Template { - factory Template(Directory templateSource, Directory? imageSourceDir, { + factory Template(Directory templateSource, Directory imageSourceDir, { required FileSystem fileSystem, required Logger logger, required TemplateRenderer templateRenderer, @@ -46,7 +46,7 @@ class Template { }) { return Template._( <Directory>[templateSource], - imageSourceDir != null ? <Directory>[imageSourceDir] : <Directory>[], + <Directory>[imageSourceDir], fileSystem: fileSystem, logger: logger, templateRenderer: templateRenderer, diff --git a/packages/flutter_tools/lib/src/test/coverage_collector.dart b/packages/flutter_tools/lib/src/test/coverage_collector.dart index aaa4f035f007d..05b00c4be15c2 100644 --- a/packages/flutter_tools/lib/src/test/coverage_collector.dart +++ b/packages/flutter_tools/lib/src/test/coverage_collector.dart @@ -11,7 +11,7 @@ import 'package:vm_service/vm_service.dart' as vm_service; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/process.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../vmservice.dart'; import 'test_device.dart'; diff --git a/packages/flutter_tools/lib/src/test/flutter_platform.dart b/packages/flutter_tools/lib/src/test/flutter_platform.dart index 4809da1d953b9..267d088f8c580 100644 --- a/packages/flutter_tools/lib/src/test/flutter_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_platform.dart @@ -19,7 +19,7 @@ import '../compile.dart'; import '../convert.dart'; import '../dart/language_version.dart'; import '../device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../test/test_wrapper.dart'; @@ -345,6 +345,7 @@ class FlutterPlatform extends PlatformPlugin { return controller.suite; } + @override StreamChannel<dynamic> loadChannel(String path, SuitePlatform platform) { if (_testCount > 0) { // Fail if there will be a port conflict. diff --git a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart index e99ddedc0cced..53c4b7a364095 100644 --- a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart @@ -484,6 +484,10 @@ class FlutterWebPlatform extends PlatformPlugin { return suite; } + @override + StreamChannel<dynamic> loadChannel(String path, SuitePlatform platform) => + throw UnimplementedError(); + /// Returns the [BrowserManager] for [runtime], which should be a browser. /// /// If no browser manager is running yet, starts one. diff --git a/packages/flutter_tools/lib/src/test/font_config_manager.dart b/packages/flutter_tools/lib/src/test/font_config_manager.dart index 92d641503590f..77158d7e49f70 100644 --- a/packages/flutter_tools/lib/src/test/font_config_manager.dart +++ b/packages/flutter_tools/lib/src/test/font_config_manager.dart @@ -5,7 +5,7 @@ import 'dart:async'; import '../base/file_system.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; /// Manages a Font configuration that can be shared across multiple tests. class FontConfigManager { diff --git a/packages/flutter_tools/lib/src/test/integration_test_device.dart b/packages/flutter_tools/lib/src/test/integration_test_device.dart index 278275250c0b0..5d7eec304509d 100644 --- a/packages/flutter_tools/lib/src/test/integration_test_device.dart +++ b/packages/flutter_tools/lib/src/test/integration_test_device.dart @@ -2,8 +2,11 @@ // 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:meta/meta.dart'; import 'package:stream_channel/stream_channel.dart'; import 'package:vm_service/vm_service.dart' as vm_service; @@ -11,7 +14,7 @@ import '../application_package.dart'; import '../base/common.dart'; import '../build_info.dart'; import '../device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../vmservice.dart'; import 'test_device.dart'; @@ -21,10 +24,10 @@ const String kIntegrationTestMethod = 'ext.flutter.integrationTest'; class IntegrationTestTestDevice implements TestDevice { IntegrationTestTestDevice({ - required this.id, - required this.device, - required this.debuggingOptions, - required this.userIdentifier, + @required this.id, + @required this.device, + @required this.debuggingOptions, + @required this.userIdentifier, }); final int id; @@ -32,7 +35,7 @@ class IntegrationTestTestDevice implements TestDevice { final DebuggingOptions debuggingOptions; final String userIdentifier; - ApplicationPackage? _applicationPackage; + ApplicationPackage _applicationPackage; final Completer<void> _finished = Completer<void>(); final Completer<Uri> _gotProcessObservatoryUri = Completer<Uri>(); @@ -42,16 +45,13 @@ class IntegrationTestTestDevice implements TestDevice { @override Future<StreamChannel<String>> start(String entrypointPath) async { final TargetPlatform targetPlatform = await device.targetPlatform; - _applicationPackage = await ApplicationPackageFactory.instance?.getPackageForPlatform( + _applicationPackage = await ApplicationPackageFactory.instance.getPackageForPlatform( targetPlatform, buildInfo: debuggingOptions.buildInfo, ); - if (_applicationPackage == null) { - throw TestDeviceException('No application found for $targetPlatform.', StackTrace.current); - } final LaunchResult launchResult = await device.startApp( - _applicationPackage!, + _applicationPackage, mainPath: entrypointPath, platformArgs: <String, dynamic>{}, debuggingOptions: debuggingOptions, @@ -60,18 +60,17 @@ class IntegrationTestTestDevice implements TestDevice { if (!launchResult.started) { throw TestDeviceException('Unable to start the app on the device.', StackTrace.current); } - final Uri? observatoryUri = launchResult.observatoryUri; - if (observatoryUri == null) { + if (launchResult.observatoryUri == null) { throw TestDeviceException('Observatory is not available on the test device.', StackTrace.current); } // No need to set up the log reader because the logs are captured and // streamed to the package:test_core runner. - _gotProcessObservatoryUri.complete(observatoryUri); + _gotProcessObservatoryUri.complete(launchResult.observatoryUri); globals.printTrace('test $id: Connecting to vm service'); - final FlutterVmService vmService = await connectToVmService(observatoryUri, logger: globals.logger).timeout( + final FlutterVmService vmService = await connectToVmService(launchResult.observatoryUri, logger: globals.logger).timeout( const Duration(seconds: 5), onTimeout: () => throw TimeoutException('Connecting to the VM Service timed out.'), ); @@ -84,7 +83,7 @@ class IntegrationTestTestDevice implements TestDevice { await vmService.service.streamListen(vm_service.EventStreams.kExtension); final Stream<String> remoteMessages = vmService.service.onExtensionEvent .where((vm_service.Event e) => e.extensionKind == kIntegrationTestExtension) - .map((vm_service.Event e) => e.extensionData!.data[kIntegrationTestData] as String); + .map((vm_service.Event e) => e.extensionData.data[kIntegrationTestData] as String); final StreamChannelController<String> controller = StreamChannelController<String>(); @@ -114,14 +113,11 @@ class IntegrationTestTestDevice implements TestDevice { @override Future<void> kill() async { - final ApplicationPackage? applicationPackage = _applicationPackage; - if (applicationPackage != null) { - if (!await device.stopApp(applicationPackage, userIdentifier: userIdentifier)) { - globals.printTrace('Could not stop the Integration Test app.'); - } - if (!await device.uninstallApp(applicationPackage, userIdentifier: userIdentifier)) { - globals.printTrace('Could not uninstall the Integration Test app.'); - } + if (!await device.stopApp(_applicationPackage, userIdentifier: userIdentifier)) { + globals.printTrace('Could not stop the Integration Test app.'); + } + if (!await device.uninstallApp(_applicationPackage, userIdentifier: userIdentifier)) { + globals.printTrace('Could not uninstall the Integration Test app.'); } await device.dispose(); diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index 39ce06c131eab..532d41ff979b6 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart @@ -11,7 +11,7 @@ import '../base/common.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../device.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; import '../web/chrome.dart'; import '../web/memory_fs.dart'; diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 66b60b4b16ee5..13a2404d8ad28 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -14,7 +14,7 @@ import '../build_info.dart'; import '../bundle.dart'; import '../compile.dart'; import '../flutter_plugins.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../project.dart'; /// A request to the [TestCompiler] for recompilation. diff --git a/packages/flutter_tools/lib/src/tester/flutter_tester.dart b/packages/flutter_tools/lib/src/tester/flutter_tester.dart index 57ceb5d75f654..a2e76d6105808 100644 --- a/packages/flutter_tools/lib/src/tester/flutter_tester.dart +++ b/packages/flutter_tools/lib/src/tester/flutter_tester.dart @@ -36,6 +36,9 @@ class FlutterTesterApp extends ApplicationPackage { @override String get name => _directory.basename; + + @override + File get packagesFile => _directory.childFile('.packages'); } /// The device interface for running on the flutter_tester shell. diff --git a/packages/flutter_tools/lib/src/tracing.dart b/packages/flutter_tools/lib/src/tracing.dart index 8b35765058273..0cc8e36800c21 100644 --- a/packages/flutter_tools/lib/src/tracing.dart +++ b/packages/flutter_tools/lib/src/tracing.dart @@ -2,8 +2,11 @@ // 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:meta/meta.dart'; import 'package:vm_service/vm_service.dart' as vm_service; import 'base/common.dart'; @@ -21,8 +24,8 @@ const String kFirstFrameRasterizedEventName = 'Rasterized first useful frame'; class Tracing { Tracing({ - required this.vmService, - required Logger logger, + @required this.vmService, + @required Logger logger, }) : _logger = logger; static const String firstUsefulFrameEventName = kFirstFrameRasterizedEventName; @@ -36,7 +39,7 @@ class Tracing { } /// Stops tracing; optionally wait for first frame. - Future<Map<String, Object?>> stopTracingAndDownloadTimeline({ + Future<Map<String, dynamic>> stopTracingAndDownloadTimeline({ bool awaitFirstFrame = false, }) async { if (awaitFirstFrame) { @@ -59,10 +62,9 @@ class Tracing { bool done = false; final List<FlutterView> views = await vmService.getFlutterViews(); for (final FlutterView view in views) { - final String? uiIsolateId = view.uiIsolate?.id; - if (uiIsolateId != null && await vmService + if (await vmService .flutterAlreadyPaintedFirstUsefulFrame( - isolateId: uiIsolateId, + isolateId: view.uiIsolate.id, )) { done = true; break; @@ -78,15 +80,14 @@ class Tracing { } status.stop(); } - final vm_service.Response? timeline = await vmService.getTimeline(); + final vm_service.Response timeline = await vmService.getTimeline(); await vmService.setTimelineFlags(<String>[]); - final Map<String, Object?>? timelineJson = timeline?.json; - if (timelineJson == null) { + if (timeline == null) { throwToolExit( 'The device disconnected before the timeline could be retrieved.', ); } - return timelineJson; + return timeline.json; } } @@ -94,8 +95,8 @@ class Tracing { /// store it to `$output/start_up_info.json`. Future<void> downloadStartupTrace(FlutterVmService vmService, { bool awaitFirstFrame = true, - required Logger logger, - required Directory output, + @required Logger logger, + @required Directory output, }) async { final File traceInfoFile = output.childFile('start_up_info.json'); @@ -109,39 +110,33 @@ Future<void> downloadStartupTrace(FlutterVmService vmService, { final Tracing tracing = Tracing(vmService: vmService, logger: logger); - final Map<String, Object?> timeline = await tracing.stopTracingAndDownloadTimeline( + final Map<String, dynamic> timeline = await tracing.stopTracingAndDownloadTimeline( awaitFirstFrame: awaitFirstFrame, ); final File traceTimelineFile = output.childFile('start_up_timeline.json'); traceTimelineFile.writeAsStringSync(toPrettyJson(timeline)); - int? extractInstantEventTimestamp(String eventName) { - final List<Object?>? traceEvents = timeline['traceEvents'] as List<Object?>?; - if (traceEvents == null) { - return null; - } - final List<Map<String, Object?>> events = List<Map<String, Object?>>.from(traceEvents); - Map<String, Object?>? matchedEvent; - for (final Map<String, Object?> event in events) { - if (event['name'] == eventName) { - matchedEvent = event; - } - } - return matchedEvent == null ? null : (matchedEvent['ts'] as int?); + int extractInstantEventTimestamp(String eventName) { + final List<Map<String, dynamic>> events = + List<Map<String, dynamic>>.from(timeline['traceEvents'] as List<dynamic>); + final Map<String, dynamic> event = events.firstWhere( + (Map<String, dynamic> event) => event['name'] == eventName, orElse: () => null, + ); + return event == null ? null : (event['ts'] as int); } String message = 'No useful metrics were gathered.'; - final int? engineEnterTimestampMicros = extractInstantEventTimestamp(kFlutterEngineMainEnterEventName); - final int? frameworkInitTimestampMicros = extractInstantEventTimestamp(kFrameworkInitEventName); + final int engineEnterTimestampMicros = extractInstantEventTimestamp(kFlutterEngineMainEnterEventName); + final int frameworkInitTimestampMicros = extractInstantEventTimestamp(kFrameworkInitEventName); if (engineEnterTimestampMicros == null) { logger.printTrace('Engine start event is missing in the timeline: $timeline'); throwToolExit('Engine start event is missing in the timeline. Cannot compute startup time.'); } - final Map<String, Object?> traceInfo = <String, Object?>{ + final Map<String, dynamic> traceInfo = <String, dynamic>{ 'engineEnterTimestampMicros': engineEnterTimestampMicros, }; @@ -152,8 +147,8 @@ Future<void> downloadStartupTrace(FlutterVmService vmService, { } if (awaitFirstFrame) { - final int? firstFrameBuiltTimestampMicros = extractInstantEventTimestamp(kFirstFrameBuiltEventName); - final int? firstFrameRasterizedTimestampMicros = extractInstantEventTimestamp(kFirstFrameRasterizedEventName); + final int firstFrameBuiltTimestampMicros = extractInstantEventTimestamp(kFirstFrameBuiltEventName); + final int firstFrameRasterizedTimestampMicros = extractInstantEventTimestamp(kFirstFrameRasterizedEventName); if (firstFrameBuiltTimestampMicros == null || firstFrameRasterizedTimestampMicros == null) { logger.printTrace('First frame events are missing in the timeline: $timeline'); throwToolExit('First frame events are missing in the timeline. Cannot compute startup time.'); diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index ec86fc41e1953..abfbfc923935e 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart @@ -12,13 +12,12 @@ import 'base/process.dart'; import 'base/time.dart'; import 'cache.dart'; import 'convert.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; const String _unknownFrameworkVersion = '0.0.0-unknown'; /// The names of each channel/branch in order of increasing stability. enum Channel { - // TODO(fujino): update to main https://github.com/flutter/flutter/issues/95041 master, dev, beta, @@ -27,7 +26,7 @@ enum Channel { // Beware: Keep order in accordance with stability const Set<String> kOfficialChannels = <String>{ - globals.kDefaultFrameworkChannel, + 'master', 'dev', 'beta', 'stable', @@ -145,8 +144,6 @@ class FlutterVersion { late String _frameworkVersion; String get frameworkVersion => _frameworkVersion; - String get devToolsVersion => globals.cache.devToolsVersion; - String get dartSdkVersion => globals.cache.dartSdkVersion; String get engineRevision => globals.cache.engineRevision; @@ -162,10 +159,10 @@ class FlutterVersion { final String flutterText = 'Flutter$versionText • channel $channel • ${repositoryUrl ?? 'unknown source'}'; final String frameworkText = 'Framework • revision $frameworkRevisionShort ($frameworkAge) • $frameworkCommitDate'; final String engineText = 'Engine • revision $engineRevisionShort'; - final String toolsText = 'Tools • Dart $dartSdkVersion • DevTools $devToolsVersion'; + final String toolsText = 'Tools • Dart $dartSdkVersion'; // Flutter 1.10.2-pre.69 • channel master • https://github.com/flutter/flutter.git - // Framework • revision 340c158f32 (85 minutes ago) • 2018-10-26 11:27:22 -0400 + // Framework • revision 340c158f32 (84 minutes ago) • 2018-10-26 11:27:22 -0400 // Engine • revision 9c46333e14 // Tools • Dart 2.1.0 (build 2.1.0-dev.8.0 bf26f760b1) @@ -180,7 +177,6 @@ class FlutterVersion { 'frameworkCommitDate': frameworkCommitDate, 'engineRevision': engineRevision, 'dartSdkVersion': dartSdkVersion, - 'devToolsVersion': devToolsVersion, }; String get frameworkDate => frameworkCommitDate; @@ -242,15 +238,15 @@ class FlutterVersion { } final DateTime? latestFlutterCommitDate = await _getLatestAvailableFlutterDate(); - return VersionFreshnessValidator( - version: this, + await checkVersionFreshness( + this, clock: _clock, localFrameworkCommitDate: localFrameworkCommitDate, latestFlutterCommitDate: latestFlutterCommitDate, logger: globals.logger, cache: globals.cache, - pauseTime: VersionFreshnessValidator.timeToPauseToLetUserReadTheMessage, - ).run(); + pauseTime: timeToPauseToLetUserReadTheMessage, + ); } /// The name of the temporary git remote used to check for the latest @@ -281,10 +277,10 @@ class FlutterVersion { ); } on VersionCheckError catch (error) { if (globals.platform.environment.containsKey('FLUTTER_GIT_URL')) { - globals.printWarning('Warning: the Flutter git upstream was overridden ' + globals.logger.printError('Warning: the Flutter git upstream was overridden ' 'by the environment variable FLUTTER_GIT_URL = ${globals.flutterGit}'); } - globals.printError(error.toString()); + globals.logger.printError(error.toString()); rethrow; } finally { await _removeVersionCheckRemoteIfExists(); @@ -362,14 +358,13 @@ class FlutterVersion { globals.cache.checkLockAcquired(); final VersionCheckStamp versionCheckStamp = await VersionCheckStamp.load(globals.cache, globals.logger); - final DateTime now = _clock.now(); if (versionCheckStamp.lastTimeVersionWasChecked != null) { - final Duration timeSinceLastCheck = now.difference( + final Duration timeSinceLastCheck = _clock.now().difference( versionCheckStamp.lastTimeVersionWasChecked!, ); // Don't ping the server too often. Return cached value if it's fresh. - if (timeSinceLastCheck < VersionFreshnessValidator.checkAgeConsideredUpToDate) { + if (timeSinceLastCheck < checkAgeConsideredUpToDate) { return versionCheckStamp.lastKnownRemoteVersion; } } @@ -380,7 +375,7 @@ class FlutterVersion { await FlutterVersion.fetchRemoteFrameworkCommitDate(channel), ); await versionCheckStamp.store( - newTimeVersionWasChecked: now, + newTimeVersionWasChecked: _clock.now(), newKnownRemoteVersion: remoteFrameworkCommitDate, ); return remoteFrameworkCommitDate; @@ -392,7 +387,7 @@ class FlutterVersion { // Still update the timestamp to avoid us hitting the server on every single // command if for some reason we cannot connect (eg. we may be offline). await versionCheckStamp.store( - newTimeVersionWasChecked: now, + newTimeVersionWasChecked: _clock.now(), ); return null; } @@ -745,152 +740,53 @@ enum VersionCheckResult { newVersionAvailable, } -/// Determine whether or not the provided [version] is "fresh" and notify the user if appropriate. -/// -/// To initiate the validation check, call [run]. -/// -/// We do not want to check with the upstream git remote for newer commits on -/// every tool invocation, as this would significantly slow down running tool -/// commands. Thus, the tool writes to the [VersionCheckStamp] every time that -/// it actually has fetched commits from upstream, and this validator only -/// checks again if it has been more than [checkAgeConsideredUpToDate] since the -/// last fetch. -/// -/// We do not want to notify users with "reasonably" fresh versions about new -/// releases. The method [versionAgeConsideredUpToDate] defines a different -/// duration of freshness for each channel. If [localFrameworkCommitDate] is -/// newer than this duration, then we do not show the warning. -/// -/// We do not want to annoy users who intentionally disregard the warning and -/// choose not to upgrade. Thus, we only show the message if it has been more -/// than [maxTimeSinceLastWarning] since the last time the user saw the warning. -class VersionFreshnessValidator { - VersionFreshnessValidator({ - required this.version, - required this.localFrameworkCommitDate, - required this.clock, - required this.cache, - required this.logger, - this.latestFlutterCommitDate, - this.pauseTime = Duration.zero, - }); - - final FlutterVersion version; - final DateTime localFrameworkCommitDate; - final SystemClock clock; - final Cache cache; - final Logger logger; - final Duration pauseTime; - final DateTime? latestFlutterCommitDate; - - late final DateTime now = clock.now(); - late final Duration frameworkAge = now.difference(localFrameworkCommitDate); - - /// The amount of time we wait before pinging the server to check for the - /// availability of a newer version of Flutter. - @visibleForTesting - static const Duration checkAgeConsideredUpToDate = Duration(days: 3); - - /// The amount of time we wait between issuing a warning. - /// - /// This is to avoid annoying users who are unable to upgrade right away. - @visibleForTesting - static const Duration maxTimeSinceLastWarning = Duration(days: 1); - - /// The amount of time we pause for to let the user read the message about - /// outdated Flutter installation. - /// - /// This can be customized in tests to speed them up. - @visibleForTesting - static Duration timeToPauseToLetUserReadTheMessage = const Duration(seconds: 2); - - // We show a warning if either we know there is a new remote version, or we - // couldn't tell but the local version is outdated. - @visibleForTesting - bool canShowWarning(VersionCheckResult remoteVersionStatus) { - final bool installationSeemsOutdated = frameworkAge > versionAgeConsideredUpToDate(version.channel); - if (remoteVersionStatus == VersionCheckResult.newVersionAvailable) { - return true; - } - if (!installationSeemsOutdated) { - return false; - } - return remoteVersionStatus == VersionCheckResult.unknown; - } - - /// We warn the user if the age of their Flutter installation is greater than - /// this duration. The durations are slightly longer than the expected release - /// cadence for each channel, to give the user a grace period before they get - /// notified. - /// - /// For example, for the beta channel, this is set to eight weeks because - /// beta releases happen approximately every month. - @visibleForTesting - static Duration versionAgeConsideredUpToDate(String channel) { - switch (channel) { - case 'stable': - return const Duration(days: 365 ~/ 2); // Six months - case 'beta': - return const Duration(days: 7 * 8); // Eight weeks - case 'dev': - return const Duration(days: 7 * 4); // Four weeks - default: - return const Duration(days: 7 * 3); // Three weeks - } - } - - /// Execute validations and print warning to [logger] if necessary. - Future<void> run() async { - // Don't perform update checks if we're not on an official channel. - if (!kOfficialChannels.contains(version.channel)) { - return; - } - - // Get whether there's a newer version on the remote. This only goes - // to the server if we haven't checked recently so won't happen on every - // command. - final VersionCheckResult remoteVersionStatus; - - if (latestFlutterCommitDate == null) { - remoteVersionStatus = VersionCheckResult.unknown; - } else { - if (latestFlutterCommitDate!.isAfter(localFrameworkCommitDate)) { - remoteVersionStatus = VersionCheckResult.newVersionAvailable; - } else { - remoteVersionStatus = VersionCheckResult.versionIsCurrent; - } - } - - // Do not load the stamp before the above server check as it may modify the stamp file. - final VersionCheckStamp stamp = await VersionCheckStamp.load(cache, logger); - final DateTime lastTimeWarningWasPrinted = stamp.lastTimeWarningWasPrinted ?? clock.ago(maxTimeSinceLastWarning * 2); - final bool beenAWhileSinceWarningWasPrinted = now.difference(lastTimeWarningWasPrinted) > maxTimeSinceLastWarning; - if (!beenAWhileSinceWarningWasPrinted) { - return; - } - - final bool canShowWarningResult = canShowWarning(remoteVersionStatus); - - if (!canShowWarningResult) { - return; - } - - // By this point, we should show the update message - final String updateMessage; - switch (remoteVersionStatus) { - case VersionCheckResult.newVersionAvailable: - updateMessage = newVersionAvailableMessage(); - break; - case VersionCheckResult.versionIsCurrent: - case VersionCheckResult.unknown: - updateMessage = versionOutOfDateMessage(frameworkAge); - break; - } - +@visibleForTesting +Future<void> checkVersionFreshness(FlutterVersion version, { + required DateTime localFrameworkCommitDate, + required DateTime? latestFlutterCommitDate, + required SystemClock clock, + required Cache cache, + required Logger logger, + Duration pauseTime = Duration.zero, +}) async { + // Don't perform update checks if we're not on an official channel. + if (!kOfficialChannels.contains(version.channel)) { + return; + } + + final Duration frameworkAge = clock.now().difference(localFrameworkCommitDate); + final bool installationSeemsOutdated = frameworkAge > versionAgeConsideredUpToDate(version.channel); + + // Get whether there's a newer version on the remote. This only goes + // to the server if we haven't checked recently so won't happen on every + // command. + final VersionCheckResult remoteVersionStatus = latestFlutterCommitDate == null + ? VersionCheckResult.unknown + : latestFlutterCommitDate.isAfter(localFrameworkCommitDate) + ? VersionCheckResult.newVersionAvailable + : VersionCheckResult.versionIsCurrent; + + // Do not load the stamp before the above server check as it may modify the stamp file. + final VersionCheckStamp stamp = await VersionCheckStamp.load(cache, logger); + final DateTime lastTimeWarningWasPrinted = stamp.lastTimeWarningWasPrinted ?? clock.ago(maxTimeSinceLastWarning * 2); + final bool beenAWhileSinceWarningWasPrinted = clock.now().difference(lastTimeWarningWasPrinted) > maxTimeSinceLastWarning; + + // We show a warning if either we know there is a new remote version, or we couldn't tell but the local + // version is outdated. + final bool canShowWarning = + remoteVersionStatus == VersionCheckResult.newVersionAvailable || + (remoteVersionStatus == VersionCheckResult.unknown && + installationSeemsOutdated); + + if (beenAWhileSinceWarningWasPrinted && canShowWarning) { + final String updateMessage = + remoteVersionStatus == VersionCheckResult.newVersionAvailable + ? newVersionAvailableMessage() + : versionOutOfDateMessage(frameworkAge); logger.printStatus(updateMessage, emphasis: true); await Future.wait<void>(<Future<void>>[ stamp.store( - newTimeWarningWasPrinted: now, + newTimeWarningWasPrinted: clock.now(), cache: cache, ), Future<void>.delayed(pauseTime), @@ -898,6 +794,45 @@ class VersionFreshnessValidator { } } +/// The amount of time we wait before pinging the server to check for the +/// availability of a newer version of Flutter. +@visibleForTesting +const Duration checkAgeConsideredUpToDate = Duration(days: 3); + +/// We warn the user if the age of their Flutter installation is greater than +/// this duration. The durations are slightly longer than the expected release +/// cadence for each channel, to give the user a grace period before they get +/// notified. +/// +/// For example, for the beta channel, this is set to five weeks because +/// beta releases happen approximately every month. +@visibleForTesting +Duration versionAgeConsideredUpToDate(String channel) { + switch (channel) { + case 'stable': + return const Duration(days: 365 ~/ 2); // Six months + case 'beta': + return const Duration(days: 7 * 8); // Eight weeks + case 'dev': + return const Duration(days: 7 * 4); // Four weeks + default: + return const Duration(days: 7 * 3); // Three weeks + } +} + +/// The amount of time we wait between issuing a warning. +/// +/// This is to avoid annoying users who are unable to upgrade right away. +@visibleForTesting +const Duration maxTimeSinceLastWarning = Duration(days: 1); + +/// The amount of time we pause for to let the user read the message about +/// outdated Flutter installation. +/// +/// This can be customized in tests to speed them up. +@visibleForTesting +Duration timeToPauseToLetUserReadTheMessage = const Duration(seconds: 2); + @visibleForTesting String versionOutOfDateMessage(Duration frameworkAge) { String warning = 'WARNING: your installation of Flutter is ${frameworkAge.inDays} days old.'; diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index 127dd197d26f3..678a4f9b4eba6 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart @@ -402,7 +402,7 @@ class FlutterView { required this.uiIsolate, }); - factory FlutterView.parse(Map<String, Object?> json) { + factory FlutterView.parse(Map<String, Object> json) { final Map<String, Object?>? rawIsolate = json['isolate'] as Map<String, Object?>?; vm_service.IsolateRef? isolate; if (rawIsolate != null) { @@ -822,11 +822,11 @@ class FlutterVmService { // with cleaning up. return <FlutterView>[]; } - final List<Object?>? rawViews = response.json?['views'] as List<Object?>?; + final List<Object>? rawViews = response.json?['views'] as List<Object>?; final List<FlutterView> views = <FlutterView>[ if (rawViews != null) - for (final Map<String, Object?> rawView in rawViews.whereType<Map<String, Object?>>()) - FlutterView.parse(rawView) + for (final Object rawView in rawViews) + FlutterView.parse(rawView as Map<String, Object>) ]; if (views.isNotEmpty || returnEarly) { return views; diff --git a/packages/flutter_tools/lib/src/web/chrome.dart b/packages/flutter_tools/lib/src/web/chrome.dart index aab55dd8fc823..41b2445985b58 100644 --- a/packages/flutter_tools/lib/src/web/chrome.dart +++ b/packages/flutter_tools/lib/src/web/chrome.dart @@ -266,13 +266,11 @@ class ChromiumLauncher { // only required for flutter_test --platform=chrome and not flutter run. bool hitGlibcBug = false; bool shouldRetry = false; - final List<String> errors = <String>[]; await process.stderr .transform(utf8.decoder) .transform(const LineSplitter()) .map((String line) { - _logger.printTrace('[CHROME]: $line'); - errors.add('[CHROME]:$line'); + _logger.printTrace('[CHROME]:$line'); if (line.contains(_kGlibcError)) { hitGlibcBug = true; shouldRetry = true; @@ -289,8 +287,7 @@ class ChromiumLauncher { return ''; } if (retry >= kMaxRetries) { - errors.forEach(_logger.printError); - _logger.printError('Failed to launch browser after $kMaxRetries tries. Command used to launch it: ${args.join(' ')}'); + _logger.printTrace('Failed to launch browser after $kMaxRetries tries. Command used to launch it: ${args.join(' ')}'); throw ToolExit( 'Failed to launch browser. Make sure you are using an up-to-date ' 'Chrome or Edge. Otherwise, consider using -d web-server instead ' @@ -398,8 +395,7 @@ class ChromiumLauncher { // connection is valid. if (!skipCheck) { try { - await chrome.chromeConnection.getTab( - (ChromeTab tab) => true, retryFor: const Duration(seconds: 2)); + await chrome.chromeConnection.getTabs(); } on Exception catch (error, stackTrace) { _logger.printError('$error', stackTrace: stackTrace); await chrome.close(); diff --git a/packages/flutter_tools/lib/src/web/compile.dart b/packages/flutter_tools/lib/src/web/compile.dart index e9fa471a96a37..aad0161b5062e 100644 --- a/packages/flutter_tools/lib/src/web/compile.dart +++ b/packages/flutter_tools/lib/src/web/compile.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../artifacts.dart'; import '../base/common.dart'; import '../base/file_system.dart'; @@ -11,7 +13,7 @@ import '../build_system/build_system.dart'; import '../build_system/targets/web.dart'; import '../cache.dart'; import '../flutter_plugins.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../platform_plugins.dart'; import '../plugins.dart'; import '../project.dart'; @@ -24,7 +26,7 @@ Future<void> buildWeb( String serviceWorkerStrategy, bool sourceMaps, bool nativeNullAssertions, - String? baseHref, + String baseHref, ) async { final bool hasWebPlugins = (await findPlugins(flutterProject)) .any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey)); @@ -35,7 +37,7 @@ Future<void> buildWeb( final Status status = globals.logger.startProgress('Compiling $target for the Web...'); final Stopwatch sw = Stopwatch()..start(); try { - final BuildResult result = await globals.buildSystem.build(WebServiceWorker(globals.fs, globals.cache), Environment( + final BuildResult result = await globals.buildSystem.build(WebServiceWorker(globals.fs), Environment( projectDir: globals.fs.currentDirectory, outputDir: outputDirectory, buildDir: flutterProject.directory @@ -45,21 +47,20 @@ Future<void> buildWeb( kTargetFile: target, kHasWebPlugins: hasWebPlugins.toString(), kCspMode: csp.toString(), - if (baseHref != null) - kBaseHref : baseHref, + kBaseHref : baseHref, kSourceMapsEnabled: sourceMaps.toString(), kNativeNullAssertions: nativeNullAssertions.toString(), if (serviceWorkerStrategy != null) kServiceWorkerStrategy: serviceWorkerStrategy, ...buildInfo.toBuildSystemEnvironment(), }, - artifacts: globals.artifacts!, + artifacts: globals.artifacts, fileSystem: globals.fs, logger: globals.logger, processManager: globals.processManager, platform: globals.platform, cacheDir: globals.cache.getRoot(), - engineVersion: globals.artifacts!.isLocalEngine + engineVersion: globals.artifacts.isLocalEngine ? null : globals.flutterVersion.engineRevision, flutterRootDir: globals.fs.directory(Cache.flutterRoot), diff --git a/packages/flutter_tools/lib/src/windows/application_package.dart b/packages/flutter_tools/lib/src/windows/application_package.dart index 2b1e1939e2529..a1f74ad99e172 100644 --- a/packages/flutter_tools/lib/src/windows/application_package.dart +++ b/packages/flutter_tools/lib/src/windows/application_package.dart @@ -8,7 +8,7 @@ import '../base/utils.dart'; import '../build_info.dart'; import '../cmake.dart'; import '../cmake_project.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; abstract class WindowsApp extends ApplicationPackage { WindowsApp({required String projectBundleId}) : super(id: projectBundleId); diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index 6422d39d726b7..fefa23fada74b 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import '../artifacts.dart'; import '../base/analyze_size.dart'; import '../base/common.dart'; @@ -15,24 +17,29 @@ import '../cmake.dart'; import '../cmake_project.dart'; import '../convert.dart'; import '../flutter_plugins.dart'; -import '../globals.dart' as globals; +import '../globals_null_migrated.dart' as globals; import '../migrations/cmake_custom_command_migration.dart'; import 'install_manifest.dart'; import 'visual_studio.dart'; +// From https://cmake.org/cmake/help/v3.14/manual/cmake-generators.7.html#visual-studio-generators +// This may need to become a getter on VisualStudio in the future to support +// future major versions of Visual Studio. +const String _cmakeVisualStudioGeneratorIdentifier = 'Visual Studio 16 2019'; + /// Update the string when non-backwards compatible changes are made to the UWP template. const int kCurrentUwpTemplateVersion = 0; /// Builds the Windows project using msbuild. Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { - String? target, - VisualStudio? visualStudioOverride, - SizeAnalyzer? sizeAnalyzer, + String target, + VisualStudio visualStudioOverride, + SizeAnalyzer sizeAnalyzer, }) async { if (!windowsProject.cmakeFile.existsSync()) { throwToolExit( 'No Windows desktop project configured. See ' - 'https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' + 'https://flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' 'to learn about adding Windows support to a project.'); } @@ -55,25 +62,19 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { logger: globals.logger, processManager: globals.processManager, ); - final String? cmakePath = visualStudio.cmakePath; - final String? cmakeGenerator = visualStudio.cmakeGenerator; - if (cmakePath == null || cmakeGenerator == null) { + final String cmakePath = visualStudio.cmakePath; + if (cmakePath == null) { throwToolExit('Unable to find suitable Visual Studio toolchain. ' 'Please run `flutter doctor` for more details.'); } - final String buildModeName = getNameForBuildMode(buildInfo.mode); + final String buildModeName = getNameForBuildMode(buildInfo.mode ?? BuildMode.release); final Directory buildDirectory = globals.fs.directory(getWindowsBuildDirectory()); final Status status = globals.logger.startProgress( 'Building Windows application...', ); try { - await _runCmakeGeneration( - cmakePath: cmakePath, - generator: cmakeGenerator, - buildDir: buildDirectory, - sourceDir: windowsProject.cmakeFile.parent, - ); + await _runCmakeGeneration(cmakePath, buildDirectory, windowsProject.cmakeFile.parent); await _runBuild(cmakePath, buildDirectory, buildModeName); } finally { status.cancel(); @@ -84,7 +85,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { .childFile('snapshot.$arch.json'); final File precompilerTrace = globals.fs.directory(buildInfo.codeSizeDirectory) .childFile('trace.$arch.json'); - final Map<String, Object?> output = await sizeAnalyzer.analyzeAotSnapshot( + final Map<String, Object> output = await sizeAnalyzer.analyzeAotSnapshot( aotSnapshot: codeSizeFile, // This analysis is only supported for release builds. outputDirectory: globals.fs.directory( @@ -117,14 +118,14 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { /// /// Note that this feature is currently unfinished. Future<void> buildWindowsUwp(WindowsUwpProject windowsProject, BuildInfo buildInfo, { - String? target, - VisualStudio? visualStudioOverride, + String target, + VisualStudio visualStudioOverride, }) async { final Directory buildDirectory = globals.fs.directory(getWindowsBuildUwpDirectory()); if (!windowsProject.existsSync()) { throwToolExit( 'No Windows UWP desktop project configured. See ' - 'https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' + 'https://flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' 'to learn about adding Windows support to a project.', ); } @@ -152,14 +153,13 @@ Future<void> buildWindowsUwp(WindowsUwpProject windowsProject, BuildInfo buildIn logger: globals.logger, processManager: globals.processManager, ); - final String? cmakePath = visualStudio.cmakePath; - final String? cmakeGenerator = visualStudio.cmakeGenerator; - if (cmakePath == null || cmakeGenerator == null) { + final String cmakePath = visualStudio.cmakePath; + if (cmakePath == null) { throwToolExit('Unable to find suitable Visual Studio toolchain. ' 'Please run `flutter doctor` for more details.'); } - final String buildModeName = getNameForBuildMode(buildInfo.mode); + final String buildModeName = getNameForBuildMode(buildInfo.mode ?? BuildMode.release); final Status status = globals.logger.startProgress( 'Building Windows UWP application...', ); @@ -167,12 +167,7 @@ Future<void> buildWindowsUwp(WindowsUwpProject windowsProject, BuildInfo buildIn // The Cmake re-entrant build does not work for UWP, so the flutter build is // run in advance. await _runFlutterBuild(buildDirectory, buildInfo, target); - await _runCmakeGeneration( - cmakePath: cmakePath, - generator: cmakeGenerator, - buildDir: buildDirectory, - sourceDir: windowsProject.cmakeFile.parent, - ); + await _runCmakeGeneration(cmakePath, buildDirectory, windowsProject.cmakeFile.parent); await _runBuild(cmakePath, buildDirectory, buildModeName, install: false); } finally { status.cancel(); @@ -185,22 +180,21 @@ const Map<BuildMode, String> _targets = <BuildMode, String>{ BuildMode.release: 'release_bundle_windows_assets_uwp', }; -Future<void> _runFlutterBuild(Directory buildDirectory, BuildInfo buildInfo, String? targetFile) async { +Future<void> _runFlutterBuild(Directory buildDirectory, BuildInfo buildInfo, String targetFile) async { await buildDirectory.create(recursive: true); int result; - String? flutterEngine; - String? localEngine; - final Artifacts artifacts = globals.artifacts!; - if (artifacts is LocalEngineArtifacts) { - final String engineOutPath = artifacts.engineOutPath; + String flutterEngine; + String localEngine; + if (globals.artifacts is LocalEngineArtifacts) { + final LocalEngineArtifacts localEngineArtifacts = globals.artifacts as LocalEngineArtifacts; + final String engineOutPath = localEngineArtifacts.engineOutPath; flutterEngine = globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath)); localEngine = globals.fs.path.basename(engineOutPath); } try { - final String? buildMode = _targets[buildInfo.mode]; result = await globals.processUtils.stream( <String>[ - globals.fs.path.join(Cache.flutterRoot!, 'bin', 'flutter'), + globals.fs.path.join(Cache.flutterRoot, 'bin', 'flutter'), if (globals.logger.isVerbose) '--verbose', if (flutterEngine != null) '--local-engine-src-path=$flutterEngine', @@ -226,8 +220,7 @@ Future<void> _runFlutterBuild(Directory buildDirectory, BuildInfo buildInfo, Str '--ExtraGenSnapshotOptions=${buildInfo.extraGenSnapshotOptions}', if (buildInfo.extraFrontEndOptions != null && buildInfo.extraFrontEndOptions.isNotEmpty) '--ExtraFrontEndOptions=${buildInfo.extraFrontEndOptions}', - if (buildMode != null) - buildMode, + _targets[buildInfo.mode], ], trace: true, ); @@ -239,12 +232,7 @@ Future<void> _runFlutterBuild(Directory buildDirectory, BuildInfo buildInfo, Str } } -Future<void> _runCmakeGeneration({ - required String cmakePath, - required String generator, - required Directory buildDir, - required Directory sourceDir, -}) async { +Future<void> _runCmakeGeneration(String cmakePath, Directory buildDir, Directory sourceDir) async { final Stopwatch sw = Stopwatch()..start(); await buildDir.create(recursive: true); @@ -258,7 +246,7 @@ Future<void> _runCmakeGeneration({ '-B', buildDir.path, '-G', - generator, + _cmakeVisualStudioGeneratorIdentifier, ], trace: true, ); @@ -317,21 +305,21 @@ Future<void> _runBuild( void _writeGeneratedFlutterConfig( WindowsProject windowsProject, BuildInfo buildInfo, - String? target, + String target, ) { final Map<String, String> environment = <String, String>{ - 'FLUTTER_ROOT': Cache.flutterRoot!, + 'FLUTTER_ROOT': Cache.flutterRoot, 'FLUTTER_EPHEMERAL_DIR': windowsProject.ephemeralDirectory.path, 'PROJECT_DIR': windowsProject.parent.directory.path, if (target != null) 'FLUTTER_TARGET': target, ...buildInfo.toEnvironmentConfig(), }; - final Artifacts artifacts = globals.artifacts!; - if (artifacts is LocalEngineArtifacts) { - final String engineOutPath = artifacts.engineOutPath; + if (globals.artifacts is LocalEngineArtifacts) { + final LocalEngineArtifacts localEngineArtifacts = globals.artifacts as LocalEngineArtifacts; + final String engineOutPath = localEngineArtifacts.engineOutPath; environment['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath)); environment['LOCAL_ENGINE'] = globals.fs.path.basename(engineOutPath); } - writeGeneratedCmakeConfig(Cache.flutterRoot!, windowsProject, environment); + writeGeneratedCmakeConfig(Cache.flutterRoot, windowsProject, environment); } diff --git a/packages/flutter_tools/lib/src/windows/visual_studio.dart b/packages/flutter_tools/lib/src/windows/visual_studio.dart index 5c0c928786b36..5fcf11e4c91ef 100644 --- a/packages/flutter_tools/lib/src/windows/visual_studio.dart +++ b/packages/flutter_tools/lib/src/windows/visual_studio.dart @@ -167,19 +167,6 @@ class VisualStudio { ]); } - /// The generator string to pass to CMake to select this Visual Studio - /// version. - String? get cmakeGenerator { - // From https://cmake.org/cmake/help/v3.22/manual/cmake-generators.7.html#visual-studio-generators - switch (_majorVersion) { - case 17: - return 'Visual Studio 17 2022'; - case 16: - default: - return 'Visual Studio 16 2019'; - } - } - /// The major version of the Visual Studio install, as an integer. int? get _majorVersion => fullVersion != null ? int.tryParse(fullVersion!.split('.')[0]) : null; diff --git a/packages/flutter_tools/lib/src/windows/windows_device.dart b/packages/flutter_tools/lib/src/windows/windows_device.dart index 08f9f406d1f04..1b50490336fb6 100644 --- a/packages/flutter_tools/lib/src/windows/windows_device.dart +++ b/packages/flutter_tools/lib/src/windows/windows_device.dart @@ -2,8 +2,11 @@ // 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:meta/meta.dart'; import 'package:process/process.dart'; import '../application_package.dart'; @@ -25,10 +28,10 @@ import 'windows_workflow.dart'; /// A device that represents a desktop Windows target. class WindowsDevice extends DesktopDevice { WindowsDevice({ - required ProcessManager processManager, - required Logger logger, - required FileSystem fileSystem, - required OperatingSystemUtils operatingSystemUtils, + @required ProcessManager processManager, + @required Logger logger, + @required FileSystem fileSystem, + @required OperatingSystemUtils operatingSystemUtils, }) : super( 'windows', platformType: PlatformType.windows, @@ -56,8 +59,8 @@ class WindowsDevice extends DesktopDevice { @override Future<void> buildForDevice( covariant WindowsApp package, { - String? mainPath, - required BuildInfo buildInfo, + String mainPath, + BuildInfo buildInfo, }) async { await buildWindows( FlutterProject.current().windows, @@ -75,11 +78,11 @@ class WindowsDevice extends DesktopDevice { // A device that represents a desktop Windows UWP target. class WindowsUWPDevice extends Device { WindowsUWPDevice({ - required ProcessManager processManager, - required Logger logger, - required FileSystem fileSystem, - required OperatingSystemUtils operatingSystemUtils, - required UwpTool uwptool, + @required ProcessManager processManager, + @required Logger logger, + @required FileSystem fileSystem, + @required OperatingSystemUtils operatingSystemUtils, + @required UwpTool uwptool, }) : _logger = logger, _processManager = processManager, _operatingSystemUtils = operatingSystemUtils, @@ -97,9 +100,9 @@ class WindowsUWPDevice extends Device { final FileSystem _fileSystem; final OperatingSystemUtils _operatingSystemUtils; final UwpTool _uwptool; - BuildMode? _buildMode; + BuildMode _buildMode; - int? _processId; + int _processId; @override bool isSupported() => true; @@ -122,10 +125,10 @@ class WindowsUWPDevice extends Device { Future<void> dispose() async { } @override - Future<String?> get emulatorId async => null; + Future<String> get emulatorId async => null; @override - FutureOr<DeviceLogReader> getLogReader({covariant BuildableUwpApp? app, bool includePastLogs = false}) { + FutureOr<DeviceLogReader> getLogReader({covariant BuildableUwpApp app, bool includePastLogs = false}) { return NoOpDeviceLogReader('winuwp'); } @@ -159,7 +162,7 @@ class WindowsUWPDevice extends Device { } // Walks the build directory for any dependent packages for the specified architecture. - String? _getAppPackagePath(String buildDirectory) { + String/*?*/ _getAppPackagePath(String buildDirectory) { final List<String> packagePaths = _getPackagePaths(buildDirectory); return packagePaths.isNotEmpty ? packagePaths.first : null; } @@ -170,7 +173,7 @@ class WindowsUWPDevice extends Device { return _getPackagePaths(depsDirectory); } - String _getPackageName(String binaryName, String version, String config, {String? architecture}) { + String _getPackageName(String binaryName, String version, String config, {String/*?*/ architecture}) { final List<String> components = <String>[ binaryName, version, @@ -181,12 +184,12 @@ class WindowsUWPDevice extends Device { } @override - Future<bool> installApp(covariant BuildableUwpApp app, {String? userIdentifier}) async { + Future<bool> installApp(covariant BuildableUwpApp app, {String userIdentifier}) async { /// The cmake build generates an install powershell script. /// build\winuwp\runner_uwp\AppPackages\<app-name>\<app-name>_<app-version>_<cmake-config>\Add-AppDevPackage.ps1 - final String? binaryName = app.name; - final String? packageVersion = app.projectVersion; - if (binaryName == null || packageVersion == null) { + final String binaryName = app.name; + final String packageVersion = app.projectVersion; + if (packageVersion == null) { return false; } final String binaryDir = _fileSystem.path.absolute( @@ -201,9 +204,9 @@ class WindowsUWPDevice extends Device { // Single-archtitecture package. _getPackageName(binaryName, packageVersion, config, architecture: 'x64'), ]; - String? packageName; - String? buildDirectory; - String? packagePath; + String packageName; + String buildDirectory; + String packagePath; for (final String name in packageNames) { packageName = name; buildDirectory = _fileSystem.path.join(binaryDir, '${packageName}_Test'); @@ -222,7 +225,7 @@ class WindowsUWPDevice extends Device { // Verify package signature. if (!await _uwptool.isSignatureValid(packagePath)) { // If signature is invalid, install the developer certificate. - final String certificatePath = _fileSystem.path.join(buildDirectory!, '$packageName.cer'); + final String certificatePath = _fileSystem.path.join(buildDirectory, '$packageName.cer'); if (_logger.terminal.stdinHasTerminal) { final String response = await _logger.terminal.promptForCharInput( <String>['Y', 'y', 'N', 'n'], @@ -250,14 +253,14 @@ class WindowsUWPDevice extends Device { // Install the application and dependencies. final String packageUri = Uri.file(packagePath).toString(); - final List<String> dependencyUris = _getDependencyPaths(buildDirectory!, 'x64') + final List<String> dependencyUris = _getDependencyPaths(buildDirectory, 'x64') .map((String path) => Uri.file(path).toString()) .toList(); return _uwptool.installApp(packageUri, dependencyUris); } @override - Future<bool> isAppInstalled(covariant ApplicationPackage app, {String? userIdentifier}) async { + Future<bool> isAppInstalled(covariant ApplicationPackage app, {String userIdentifier}) async { final String packageName = app.id; return await _uwptool.getPackageFamilyName(packageName) != null; } @@ -276,13 +279,13 @@ class WindowsUWPDevice extends Device { @override Future<LaunchResult> startApp(covariant BuildableUwpApp package, { - String? mainPath, - String? route, - required DebuggingOptions debuggingOptions, - Map<String, Object?> platformArgs = const <String, Object>{}, + String mainPath, + String route, + DebuggingOptions debuggingOptions, + Map<String, dynamic> platformArgs, bool prebuiltApplication = false, bool ipv6 = false, - String? userIdentifier, + String userIdentifier, }) async { _buildMode = debuggingOptions.buildInfo.mode; if (!prebuiltApplication) { @@ -307,11 +310,7 @@ class WindowsUWPDevice extends Device { return LaunchResult.failed(); } - final String? packageFamily = await _uwptool.getPackageFamilyName(packageName); - if (packageFamily == null) { - _logger.printError('Could not find package family name from $packageName'); - return LaunchResult.failed(); - } + final String packageFamily = await _uwptool.getPackageFamilyName(packageName); if (debuggingOptions.buildInfo.mode.isRelease) { _processId = await _uwptool.launchApp(packageFamily, <String>[]); @@ -362,7 +361,7 @@ class WindowsUWPDevice extends Device { if (debuggingOptions.verboseSystemLogs) '--verbose-logging', if (debuggingOptions.cacheSkSL) '--cache-sksl', if (debuggingOptions.purgePersistentCache) '--purge-persistent-cache', - if (platformArgs['trace-startup'] as bool? ?? false) '--trace-startup', + if (platformArgs['trace-startup'] as bool ?? false) '--trace-startup', ]; _processId = await _uwptool.launchApp(packageFamily, args); if (_processId == null) { @@ -372,21 +371,21 @@ class WindowsUWPDevice extends Device { } @override - Future<bool> stopApp(covariant BuildableUwpApp app, {String? userIdentifier}) async { + Future<bool> stopApp(covariant BuildableUwpApp app, {String userIdentifier}) async { if (_processId != null) { - return _processManager.killPid(_processId!); + return _processManager.killPid(_processId); } return false; } @override - Future<bool> uninstallApp(covariant BuildableUwpApp app, {String? userIdentifier}) async { + Future<bool> uninstallApp(covariant BuildableUwpApp app, {String userIdentifier}) async { final String packageName = app.id; if (packageName == null) { _logger.printError('Could not find PACKAGE_GUID in ${app.project.runnerCmakeFile.path}'); return false; } - final String? packageFamily = await _uwptool.getPackageFamilyName(packageName); + final String packageFamily = await _uwptool.getPackageFamilyName(packageName); if (packageFamily == null) { // App is not installed. return true; @@ -400,13 +399,13 @@ class WindowsUWPDevice extends Device { class WindowsDevices extends PollingDeviceDiscovery { WindowsDevices({ - required ProcessManager processManager, - required Logger logger, - required FileSystem fileSystem, - required OperatingSystemUtils operatingSystemUtils, - required WindowsWorkflow windowsWorkflow, - required FeatureFlags featureFlags, - required UwpTool uwptool, + @required ProcessManager processManager, + @required Logger logger, + @required FileSystem fileSystem, + @required OperatingSystemUtils operatingSystemUtils, + @required WindowsWorkflow windowsWorkflow, + @required FeatureFlags featureFlags, + @required UwpTool uwptool, }) : _fileSystem = fileSystem, _logger = logger, _processManager = processManager, @@ -431,7 +430,7 @@ class WindowsDevices extends PollingDeviceDiscovery { bool get canListAnything => _windowsWorkflow.canListDevices; @override - Future<List<Device>> pollingGetDevices({ Duration? timeout }) async { + Future<List<Device>> pollingGetDevices({ Duration timeout }) async { if (!canListAnything) { return const <Device>[]; } diff --git a/packages/flutter_tools/lib/src/xcode_project.dart b/packages/flutter_tools/lib/src/xcode_project.dart index 300773c6984be..1657a7260abd0 100644 --- a/packages/flutter_tools/lib/src/xcode_project.dart +++ b/packages/flutter_tools/lib/src/xcode_project.dart @@ -9,7 +9,7 @@ import 'base/utils.dart'; import 'build_info.dart'; import 'bundle.dart' as bundle; import 'flutter_plugins.dart'; -import 'globals.dart' as globals; +import 'globals_null_migrated.dart' as globals; import 'ios/code_signing.dart'; import 'ios/plist_parser.dart'; import 'ios/xcode_build_settings.dart' as xcode; @@ -180,7 +180,7 @@ class IosProject extends XcodeBasedProject { // Try parsing the default, first. if (defaultInfoPlist.existsSync()) { try { - fromPlist = globals.plistParser.getStringValueFromFile( + fromPlist = globals.plistParser.getValueFromFile( defaultHostInfoPlist.path, PlistParser.kCFBundleIdentifierKey, ); @@ -216,7 +216,7 @@ class IosProject extends XcodeBasedProject { } /// The bundle name of the host app, `My App.app`. - Future<String?> hostAppBundleName(BuildInfo? buildInfo) async { + Future<String?> hostAppBundleName(BuildInfo buildInfo) async { if (!existsSync()) { return null; } @@ -224,7 +224,7 @@ class IosProject extends XcodeBasedProject { } String? _hostAppBundleName; - Future<String> _parseHostAppBundleName(BuildInfo? buildInfo) async { + Future<String> _parseHostAppBundleName(BuildInfo buildInfo) async { // The product name and bundle name are derived from the display name, which the user // is instructed to change in Xcode as part of deploying to the App Store. // https://flutter.dev/docs/deployment/ios#review-xcode-project-settings @@ -332,7 +332,7 @@ class IosProject extends XcodeBasedProject { // The Info.plist file of a target contains the key WKCompanionAppBundleIdentifier, // if it is a watchOS companion app. if (infoFile.existsSync()) { - final String? fromPlist = globals.plistParser.getStringValueFromFile(infoFile.path, 'WKCompanionAppBundleIdentifier'); + final String? fromPlist = globals.plistParser.getValueFromFile(infoFile.path, 'WKCompanionAppBundleIdentifier'); if (bundleIdentifier == fromPlist) { return true; } diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 3b21e58b19024..03c903ca42ef7 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -7,11 +7,11 @@ environment: dependencies: # To update these, use "flutter update-packages --force-upgrade". - archive: 3.1.8 + archive: 3.1.6 args: 2.3.0 browser_launcher: 1.0.0 - dds: 2.1.6+3 - dwds: 11.5.1 + dds: 2.1.4 + dwds: 11.4.0 completion: 1.0.0 coverage: 1.0.3 crypto: 3.0.1 @@ -32,7 +32,7 @@ dependencies: webkit_inspection_protocol: 1.0.0 xml: 5.3.1 yaml: 3.1.0 - native_stack_traces: 0.4.5 + native_stack_traces: 0.4.3 shelf: 1.1.4 vm_snapshot_analysis: 0.7.0 uuid: 3.0.5 @@ -42,7 +42,7 @@ dependencies: shelf_static: 1.1.0 pub_semver: 2.1.0 pool: 1.5.0 - path: 1.8.1 + path: 1.8.0 mime: 1.0.1 logging: 1.0.2 http_multi_server: 3.0.1 @@ -52,13 +52,13 @@ dependencies: # We depend on very specific internal implementation details of the # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. - test_api: 0.4.9 - test_core: 0.4.11 + test_api: 0.4.3 + test_core: 0.4.2 - vm_service: 7.5.0 + vm_service: 7.3.0 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_collection: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_value: 8.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,7 +66,7 @@ dependencies: cli_util: 0.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" csslib: 0.17.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - devtools_shared: 2.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + devtools_shared: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,7 +76,7 @@ dependencies: matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" petitparser: 4.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_proxy: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -92,16 +92,16 @@ dependencies: dev_dependencies: collection: 1.15.0 file_testing: 3.0.0 - pubspec_parse: 1.2.0 + pubspec_parse: 1.1.0 checked_yaml: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - json_annotation: 4.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + json_annotation: 4.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.20.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.17.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 5691 +# PUBSPEC CHECKSUM: 6a29 diff --git a/packages/flutter_tools/templates/app_shared/android-java.tmpl/app/build.gradle.tmpl b/packages/flutter_tools/templates/app_shared/android-java.tmpl/app/build.gradle.tmpl index 23c06f0c1de96..46d900573b455 100644 --- a/packages/flutter_tools/templates/app_shared/android-java.tmpl/app/build.gradle.tmpl +++ b/packages/flutter_tools/templates/app_shared/android-java.tmpl/app/build.gradle.tmpl @@ -22,7 +22,6 @@ if (flutterVersionName == null) { } apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { diff --git a/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle.tmpl b/packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle similarity index 69% rename from packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle.tmpl rename to packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle index 44c7b9c17050d..0b4cf534e0aaf 100644 --- a/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle.tmpl +++ b/packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle @@ -1,13 +1,11 @@ buildscript { - ext.kotlin_version = '{{kotlinVersion}}' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:{{agpVersion}}' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.android.tools.build:gradle:4.1.0' } } diff --git a/packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle.tmpl b/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle similarity index 81% rename from packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle.tmpl rename to packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle index 44c7b9c17050d..24047dce5d43f 100644 --- a/packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle.tmpl +++ b/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '{{kotlinVersion}}' + ext.kotlin_version = '1.3.50' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:{{agpVersion}}' + classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/dev/tracing_tests/android/gradle/wrapper/gradle-wrapper.properties b/packages/flutter_tools/templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from dev/tracing_tests/android/gradle/wrapper/gradle-wrapper.properties rename to packages/flutter_tools/templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/flutter_tools/templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties.tmpl b/packages/flutter_tools/templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties.tmpl deleted file mode 100644 index 5b54d823f5500..0000000000000 --- a/packages/flutter_tools/templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-{{gradleVersion}}-all.zip diff --git a/packages/flutter_tools/templates/app_shared/ios.tmpl/Runner/Info.plist.tmpl b/packages/flutter_tools/templates/app_shared/ios.tmpl/Runner/Info.plist.tmpl index 4d224546dad11..e5332a5951d30 100644 --- a/packages/flutter_tools/templates/app_shared/ios.tmpl/Runner/Info.plist.tmpl +++ b/packages/flutter_tools/templates/app_shared/ios.tmpl/Runner/Info.plist.tmpl @@ -42,6 +42,6 @@ <string>UIInterfaceOrientationLandscapeRight</string> </array> <key>UIViewControllerBasedStatusBarAppearance</key> - <false/> + <true/> </dict> </plist> diff --git a/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl index ef572e52fcd39..23a19a4673e03 100644 --- a/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl @@ -1,19 +1,11 @@ -# Project-level configuration. cmake_minimum_required(VERSION 3.10) project(runner LANGUAGES CXX) -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. set(BINARY_NAME "{{projectName}}") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID set(APPLICATION_ID "{{linuxIdentifier}}") -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. cmake_policy(SET CMP0063 NEW) -# Load bundled libraries from the lib/ directory relative to the binary. set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") # Root filesystem for cross-building. @@ -26,7 +18,7 @@ if(FLUTTER_TARGET_PLATFORM_SYSROOT) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) endif() -# Define build configuration options. +# Configure build options. if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) @@ -35,10 +27,6 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) endif() # Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_14) target_compile_options(${TARGET} PRIVATE -Wall -Werror) @@ -46,8 +34,9 @@ function(APPLY_STANDARD_SETTINGS TARGET) target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>") endfunction() -# Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. add_subdirectory(${FLUTTER_MANAGED_DIR}) # System-level dependencies. @@ -56,27 +45,16 @@ pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. +# Application build add_executable(${BINARY_NAME} "main.cc" "my_application.cc" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" ) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -# Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) - # Only the install-generated bundle's copy of the executable will launch # correctly, since the resources must in the right relative locations. To avoid # people trying to run the unbundled copy, put it in a subdirectory instead of diff --git a/packages/flutter_tools/templates/app_shared/linux.tmpl/flutter/CMakeLists.txt b/packages/flutter_tools/templates/app_shared/linux.tmpl/flutter/CMakeLists.txt index d5bd01648a96d..33fd5801e7134 100644 --- a/packages/flutter_tools/templates/app_shared/linux.tmpl/flutter/CMakeLists.txt +++ b/packages/flutter_tools/templates/app_shared/linux.tmpl/flutter/CMakeLists.txt @@ -1,4 +1,3 @@ -# This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.10) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") diff --git a/packages/flutter_tools/templates/app_shared/macos.tmpl/Runner/Base.lproj/MainMenu.xib b/packages/flutter_tools/templates/app_shared/macos.tmpl/Runner/Base.lproj/MainMenu.xib index 80e867a4e06b4..537341abf994b 100644 --- a/packages/flutter_tools/templates/app_shared/macos.tmpl/Runner/Base.lproj/MainMenu.xib +++ b/packages/flutter_tools/templates/app_shared/macos.tmpl/Runner/Base.lproj/MainMenu.xib @@ -323,10 +323,6 @@ </items> </menu> </menuItem> - <menuItem title="Help" id="EPT-qC-fAb"> - <modifierMask key="keyEquivalentModifierMask"/> - <menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/> - </menuItem> </items> <point key="canvasLocation" x="142" y="-258"/> </menu> diff --git a/packages/flutter_tools/templates/app_shared/web/index.html.tmpl b/packages/flutter_tools/templates/app_shared/web/index.html.tmpl index 725f53d0db479..850aa31a504ad 100644 --- a/packages/flutter_tools/templates/app_shared/web/index.html.tmpl +++ b/packages/flutter_tools/templates/app_shared/web/index.html.tmpl @@ -85,7 +85,7 @@ }); // If service worker doesn't succeed in a reasonable amount of time, - // fallback to plain <script> tag. + // fallback to plaint <script> tag. setTimeout(() => { if (!scriptLoaded) { console.warn( diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/app_shared/windows.tmpl/CMakeLists.txt.tmpl index eeb90783e1690..d969f43ac7700 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/CMakeLists.txt.tmpl @@ -1,16 +1,13 @@ -# Project-level configuration. cmake_minimum_required(VERSION 3.14) project({{projectName}} LANGUAGES CXX) -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. set(BINARY_NAME "{{projectName}}") -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. cmake_policy(SET CMP0063 NEW) -# Define build configuration option. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" @@ -23,7 +20,7 @@ else() "Debug" "Profile" "Release") endif() endif() -# Define settings for the Profile build mode. + set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") @@ -33,10 +30,6 @@ set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") add_definitions(-DUNICODE -D_UNICODE) # Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") @@ -45,11 +38,12 @@ function(APPLY_STANDARD_SETTINGS TARGET) target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>") endfunction() -# Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. add_subdirectory(${FLUTTER_MANAGED_DIR}) -# Application build; see runner/CMakeLists.txt. +# Application build add_subdirectory("runner") # Generated plugin build rules, which manage building the plugins and adding diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/flutter/CMakeLists.txt b/packages/flutter_tools/templates/app_shared/windows.tmpl/flutter/CMakeLists.txt index 930d2071a324e..b2e4bd8d658b2 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/flutter/CMakeLists.txt +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/flutter/CMakeLists.txt @@ -1,4 +1,3 @@ -# This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/CMakeLists.txt b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/CMakeLists.txt index b9e550fba8e17..de2d8916b72ba 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/CMakeLists.txt +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/CMakeLists.txt @@ -1,11 +1,6 @@ cmake_minimum_required(VERSION 3.14) project(runner LANGUAGES CXX) -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" @@ -15,18 +10,8 @@ add_executable(${BINARY_NAME} WIN32 "Runner.rc" "runner.exe.manifest" ) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. apply_standard_settings(${BINARY_NAME}) - -# Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/Runner.rc.tmpl b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/Runner.rc.tmpl index 7e4b8b77dd792..52b434289b1dd 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/Runner.rc.tmpl +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/Runner.rc.tmpl @@ -90,7 +90,7 @@ BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "{{organization}}" "\0" - VALUE "FileDescription", "{{projectName}}" "\0" + VALUE "FileDescription", "{{description}}" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "{{projectName}}" "\0" VALUE "LegalCopyright", "Copyright (C) {{year}} {{organization}}. All rights reserved." "\0" diff --git a/packages/flutter_tools/templates/app_shared/winuwp.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/app_shared/winuwp.tmpl/CMakeLists.txt.tmpl index 9827cf9923178..fe718ef46bef9 100644 --- a/packages/flutter_tools/templates/app_shared/winuwp.tmpl/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/app_shared/winuwp.tmpl/CMakeLists.txt.tmpl @@ -1,20 +1,16 @@ -# Project-level configuration. cmake_minimum_required(VERSION 3.8) set(CMAKE_SYSTEM_NAME WindowsStore) set(CMAKE_SYSTEM_VERSION 10.0) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED YES) + project({{projectName}} LANGUAGES CXX) -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. cmake_policy(SET CMP0079 NEW) -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. set(BINARY_NAME "{{projectName}}") -# Define build configuration options. +# Configure build options. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" @@ -27,7 +23,7 @@ else() "Debug" "Profile" "Release") endif() endif() -# Define settings for the Profile build mode. + set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") @@ -37,10 +33,6 @@ set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") add_definitions(-DUNICODE -D_UNICODE) # Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100" /await) @@ -56,9 +48,10 @@ set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") # Flutter library and tool build rules. add_subdirectory(${FLUTTER_MANAGED_DIR}) -# Application build; see runner/CMakeLists.txt. +# Application build add_subdirectory("runner_uwp") + # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) diff --git a/packages/flutter_tools/templates/app_shared/winuwp.tmpl/flutter/CMakeLists.txt b/packages/flutter_tools/templates/app_shared/winuwp.tmpl/flutter/CMakeLists.txt index 9adbd9ddb310f..ddf45257f8753 100644 --- a/packages/flutter_tools/templates/app_shared/winuwp.tmpl/flutter/CMakeLists.txt +++ b/packages/flutter_tools/templates/app_shared/winuwp.tmpl/flutter/CMakeLists.txt @@ -1,4 +1,3 @@ -# This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.8) set(CMAKE_SYSTEM_NAME WindowsStore) set(CMAKE_SYSTEM_VERSION 10.0) diff --git a/packages/flutter_tools/templates/app_shared/winuwp.tmpl/runner_uwp/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/app_shared/winuwp.tmpl/runner_uwp/CMakeLists.txt.tmpl index 8dccdc465b189..4ac70c511e6f2 100644 --- a/packages/flutter_tools/templates/app_shared/winuwp.tmpl/runner_uwp/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/app_shared/winuwp.tmpl/runner_uwp/CMakeLists.txt.tmpl @@ -112,11 +112,6 @@ foreach(ITEM ${INSTALL_MANIFEST_CONTENT}) set_property(SOURCE ${ITEM} PROPERTY VS_DEPLOYMENT_LOCATION ${RELPATH}) endforeach() -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. add_executable (${BINARY_NAME} WIN32 main.cpp flutter_frameworkview.cpp @@ -124,18 +119,9 @@ add_executable (${BINARY_NAME} WIN32 ${RESOURCE_FILES} ${INSTALL_MANIFEST_CONTENT} ) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. apply_standard_settings(${BINARY_NAME}) - -# Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE WindowsApp flutter flutter_wrapper_app) target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") -# Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/packages/flutter_tools/templates/module/android/deferred_component/build.gradle.tmpl b/packages/flutter_tools/templates/module/android/deferred_component/build.gradle.tmpl index 23a729fc60322..bce6215435c3f 100644 --- a/packages/flutter_tools/templates/module/android/deferred_component/build.gradle.tmpl +++ b/packages/flutter_tools/templates/module/android/deferred_component/build.gradle.tmpl @@ -19,7 +19,7 @@ if (flutterVersionName == null) { apply plugin: "com.android.dynamic-feature" android { - compileSdkVersion 31 + compileSdkVersion 30 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -35,7 +35,7 @@ android { defaultConfig { minSdkVersion 16 - targetSdkVersion 31 + targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/packages/flutter_tools/templates/module/android/gradle/build.gradle.tmpl b/packages/flutter_tools/templates/module/android/gradle/build.gradle.copy.tmpl similarity index 81% rename from packages/flutter_tools/templates/module/android/gradle/build.gradle.tmpl rename to packages/flutter_tools/templates/module/android/gradle/build.gradle.copy.tmpl index dea6cdbaa11c2..3bf7cc72b5ef1 100644 --- a/packages/flutter_tools/templates/module/android/gradle/build.gradle.tmpl +++ b/packages/flutter_tools/templates/module/android/gradle/build.gradle.copy.tmpl @@ -7,7 +7,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:{{agpVersion}}' + classpath 'com.android.tools.build:gradle:4.1.0' } } diff --git a/packages/flutter_tools/templates/module/android/host_app_common/app.tmpl/build.gradle.tmpl b/packages/flutter_tools/templates/module/android/host_app_common/app.tmpl/build.gradle.tmpl index d887000ded05b..ab4214eda0c85 100644 --- a/packages/flutter_tools/templates/module/android/host_app_common/app.tmpl/build.gradle.tmpl +++ b/packages/flutter_tools/templates/module/android/host_app_common/app.tmpl/build.gradle.tmpl @@ -3,7 +3,7 @@ def flutterPluginVersion = 'managed' apply plugin: 'com.android.application' android { - compileSdkVersion 31 + compileSdkVersion 30 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -13,7 +13,7 @@ android { defaultConfig { applicationId "{{androidIdentifier}}.host" minSdkVersion 16 - targetSdkVersion 31 + targetSdkVersion 30 versionCode 1 versionName "1.0" } diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl index 23f020cccefe1..3202215f8a63d 100644 --- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl +++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl @@ -42,6 +42,6 @@ <string>UIInterfaceOrientationLandscapeRight</string> </array> <key>UIViewControllerBasedStatusBarAppearance</key> - <false/> + <true/> </dict> </plist> diff --git a/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl b/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl index 2dbaaaa94c5f0..2f3d6851d3bba 100644 --- a/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl +++ b/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl @@ -81,8 +81,7 @@ def install_flutter_plugin_pods(flutter_application_path) plugin_pods.each do |plugin_hash| plugin_name = plugin_hash['name'] plugin_path = plugin_hash['path'] - has_native_build = plugin_hash.fetch('native_build', true) - if (plugin_name && plugin_path && has_native_build) + if (plugin_name && plugin_path) symlink = File.join(symlinks_dir, plugin_name) FileUtils.rm_f(symlink) File.symlink(plugin_path, symlink) diff --git a/packages/flutter_tools/templates/plugin/android-java.tmpl/build.gradle.tmpl b/packages/flutter_tools/templates/plugin/android-java.tmpl/build.gradle.tmpl index 606cde8a83d84..a8dfc512b96de 100644 --- a/packages/flutter_tools/templates/plugin/android-java.tmpl/build.gradle.tmpl +++ b/packages/flutter_tools/templates/plugin/android-java.tmpl/build.gradle.tmpl @@ -22,7 +22,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { - compileSdkVersion 31 + compileSdkVersion 30 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/packages/flutter_tools/templates/plugin/android-kotlin.tmpl/build.gradle.tmpl b/packages/flutter_tools/templates/plugin/android-kotlin.tmpl/build.gradle.tmpl index eae1c5e7c6ae6..ac94be4c3d0d6 100644 --- a/packages/flutter_tools/templates/plugin/android-kotlin.tmpl/build.gradle.tmpl +++ b/packages/flutter_tools/templates/plugin/android-kotlin.tmpl/build.gradle.tmpl @@ -2,14 +2,14 @@ group '{{androidIdentifier}}' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '{{kotlinVersion}}' + ext.kotlin_version = '1.3.50' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:{{agpVersion}}' + classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -25,7 +25,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 31 + compileSdkVersion 30 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/packages/flutter_tools/templates/plugin/linux.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/plugin/linux.tmpl/CMakeLists.txt.tmpl index 40a885d92f208..8df454676a5c7 100644 --- a/packages/flutter_tools/templates/plugin/linux.tmpl/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/plugin/linux.tmpl/CMakeLists.txt.tmpl @@ -1,46 +1,24 @@ -# The Flutter tooling requires that developers have CMake 3.10 or later -# installed. You should not increase this version, as doing so will cause -# the plugin to fail to compile for some customers of the plugin. cmake_minimum_required(VERSION 3.10) - -# Project-level configuration. set(PROJECT_NAME "{{projectName}}") project(${PROJECT_NAME} LANGUAGES CXX) # This value is used when generating builds using this plugin, so it must -# not be changed. +# not be changed set(PLUGIN_NAME "{{projectName}}_plugin") -# Define the plugin library target. Its name must not be changed (see comment -# on PLUGIN_NAME above). -# -# Any new source files that you add to the plugin should be added here. add_library(${PLUGIN_NAME} SHARED "{{pluginClassSnakeCase}}.cc" ) - -# Apply a standard set of build settings that are configured in the -# application-level CMakeLists.txt. This can be removed for plugins that want -# full control over build settings. apply_standard_settings(${PLUGIN_NAME}) - -# Symbols are hidden by default to reduce the chance of accidental conflicts -# between plugins. This should not be removed; any symbols that should be -# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) - -# Source include directories and library dependencies. Add any plugin-specific -# dependencies here. target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) -# List of absolute paths to libraries that should be bundled with the plugin. -# This list could contain prebuilt libraries, or libraries created by an -# external build triggered from this build file. +# List of absolute paths to libraries that should be bundled with the plugin set({{projectName}}_bundled_libraries "" PARENT_SCOPE diff --git a/packages/flutter_tools/templates/plugin/windows.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/plugin/windows.tmpl/CMakeLists.txt.tmpl index 3b05d1f9d23b0..5d7b0ef20f5ae 100644 --- a/packages/flutter_tools/templates/plugin/windows.tmpl/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/plugin/windows.tmpl/CMakeLists.txt.tmpl @@ -1,10 +1,4 @@ -# The Flutter tooling requires that developers have a version of Visual Studio -# installed that includes CMake 3.14 or later. You should not increase this -# version, as doing so will cause the plugin to fail to compile for some -# customers of the plugin. cmake_minimum_required(VERSION 3.14) - -# Project-level configuration. set(PROJECT_NAME "{{projectName}}") project(${PROJECT_NAME} LANGUAGES CXX) @@ -12,35 +6,18 @@ project(${PROJECT_NAME} LANGUAGES CXX) # not be changed set(PLUGIN_NAME "{{projectName}}_plugin") -# Define the plugin library target. Its name must not be changed (see comment -# on PLUGIN_NAME above). -# -# Any new source files that you add to the plugin should be added here. add_library(${PLUGIN_NAME} SHARED "{{pluginClassSnakeCase}}.cpp" ) - -# Apply a standard set of build settings that are configured in the -# application-level CMakeLists.txt. This can be removed for plugins that want -# full control over build settings. apply_standard_settings(${PLUGIN_NAME}) - -# Symbols are hidden by default to reduce the chance of accidental conflicts -# between plugins. This should not be removed; any symbols that should be -# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) - -# Source include directories and library dependencies. Add any plugin-specific -# dependencies here. target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) -# List of absolute paths to libraries that should be bundled with the plugin. -# This list could contain prebuilt libraries, or libraries created by an -# external build triggered from this build file. +# List of absolute paths to libraries that should be bundled with the plugin set({{projectName}}_bundled_libraries "" PARENT_SCOPE diff --git a/packages/flutter_tools/templates/template_manifest.json b/packages/flutter_tools/templates/template_manifest.json index 56a022085da6a..92ef080c2dbee 100644 --- a/packages/flutter_tools/templates/template_manifest.json +++ b/packages/flutter_tools/templates/template_manifest.json @@ -18,11 +18,11 @@ "templates/app_shared/analysis_options.yaml.tmpl", "templates/app_shared/android-java.tmpl/app/build.gradle.tmpl", "templates/app_shared/android-java.tmpl/app/src/main/java/androidIdentifier/MainActivity.java.tmpl", - "templates/app_shared/android-java.tmpl/build.gradle.tmpl", + "templates/app_shared/android-java.tmpl/build.gradle", "templates/app_shared/android-java.tmpl/projectName_android.iml.tmpl", "templates/app_shared/android-kotlin.tmpl/app/build.gradle.tmpl", "templates/app_shared/android-kotlin.tmpl/app/src/main/kotlin/androidIdentifier/MainActivity.kt.tmpl", - "templates/app_shared/android-kotlin.tmpl/build.gradle.tmpl", + "templates/app_shared/android-kotlin.tmpl/build.gradle", "templates/app_shared/android-kotlin.tmpl/projectName_android.iml.tmpl", "templates/app_shared/android.tmpl/.gitignore", "templates/app_shared/android.tmpl/app/src/debug/AndroidManifest.xml.tmpl", @@ -38,7 +38,7 @@ "templates/app_shared/android.tmpl/app/src/main/res/values/styles.xml", "templates/app_shared/android.tmpl/app/src/profile/AndroidManifest.xml.tmpl", "templates/app_shared/android.tmpl/gradle.properties.tmpl", - "templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties.tmpl", + "templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties", "templates/app_shared/android.tmpl/settings.gradle", "templates/app_shared/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl", "templates/app_shared/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme", @@ -207,7 +207,7 @@ "templates/module/android/deferred_component/build.gradle.tmpl", "templates/module/android/deferred_component/src/main/AndroidManifest.xml.tmpl", - "templates/module/android/gradle/build.gradle.tmpl", + "templates/module/android/gradle/build.gradle.copy.tmpl", "templates/module/android/gradle/gradle.properties.tmpl", "templates/module/android/host_app_common/app.tmpl/build.gradle.tmpl", "templates/module/android/host_app_common/app.tmpl/src/main/AndroidManifest.xml.tmpl", 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 35f63cafcdabd..e77906a0fb62c 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 @@ -6,7 +6,6 @@ import 'dart:async'; -import 'package:fake_async/fake_async.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/common.dart'; @@ -19,7 +18,7 @@ import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/analyze.dart'; import 'package:flutter_tools/src/dart/analysis.dart'; import 'package:flutter_tools/src/dart/pub.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:process/process.dart'; import '../../src/common.dart'; @@ -175,6 +174,7 @@ void main() { }); testUsingContext('Can run AnalysisService with customized cache location', () async { + final Completer<void> completer = Completer<void>(); final StreamController<List<int>> stdin = StreamController<List<int>>(); final FakeProcessManager processManager = FakeProcessManager.list( <FakeCommand>[ @@ -188,6 +188,7 @@ void main() { '--sdk', 'HostArtifact.engineDartSdkPath', ], + completer: completer, stdin: IOSink(stdin.sink), ), ]); @@ -211,11 +212,6 @@ void main() { }); testUsingContext('Can run AnalysisService with customized cache location --watch', () async { - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - fileSystem.directory('directoryA').childFile('foo').createSync(recursive: true); - - final BufferLogger logger = BufferLogger.test(); - final Completer<void> completer = Completer<void>(); final StreamController<List<int>> stdin = StreamController<List<int>>(); final FakeProcessManager processManager = FakeProcessManager.list( @@ -230,12 +226,8 @@ void main() { '--sdk', 'HostArtifact.engineDartSdkPath', ], + completer: completer, stdin: IOSink(stdin.sink), - stdout: ''' -{"event":"server.status","params":{"analysis":{"isAnalyzing":true}}} -{"event":"analysis.errors","params":{"file":"/directoryA/foo","errors":[{"type":"TestError","message":"It's an error.","severity":"warning","code":"500","location":{"file":"/directoryA/foo","startLine": 100,"startColumn":5,"offset":0}}]}} -{"event":"server.status","params":{"analysis":{"isAnalyzing":false}}} -''' ), ]); @@ -243,78 +235,17 @@ void main() { final AnalyzeCommand command = AnalyzeCommand( terminal: Terminal.test(), artifacts: artifacts, - logger: logger, - platform: FakePlatform(), - fileSystem: fileSystem, - processManager: processManager, - ); - - await FakeAsync().run((FakeAsync time) async { - final TestFlutterCommandRunner commandRunner = TestFlutterCommandRunner(); - commandRunner.addCommand(command); - unawaited(commandRunner.run(<String>['analyze', '--watch'])); - - while (!logger.statusText.contains('analyzed 1 file')) { - time.flushMicrotasks(); - } - completer.complete(); - return completer.future; - }); - expect(logger.statusText, contains("warning • It's an error • directoryA/foo:100:5 • 500")); - expect(logger.statusText, contains('1 issue found. (1 new)')); - expect(logger.errorText, isEmpty); - expect(processManager, hasNoRemainingExpectations); - }); - - testUsingContext('AnalysisService --watch skips errors from non-files', () async { - final BufferLogger logger = BufferLogger.test(); - final Completer<void> completer = Completer<void>(); - final StreamController<List<int>> stdin = StreamController<List<int>>(); - final FakeProcessManager processManager = FakeProcessManager.list( - <FakeCommand>[ - FakeCommand( - command: const <String>[ - 'HostArtifact.engineDartSdkPath/bin/dart', - '--disable-dart-dev', - 'HostArtifact.engineDartSdkPath/bin/snapshots/analysis_server.dart.snapshot', - '--disable-server-feature-completion', - '--disable-server-feature-search', - '--sdk', - 'HostArtifact.engineDartSdkPath', - ], - stdin: IOSink(stdin.sink), - stdout: ''' -{"event":"server.status","params":{"analysis":{"isAnalyzing":true}}} -{"event":"analysis.errors","params":{"file":"/directoryA/bar","errors":[{"type":"TestError","message":"It's an error.","severity":"warning","code":"500","location":{"file":"/directoryA/bar","startLine":100,"startColumn":5,"offset":0}}]}} -{"event":"server.status","params":{"analysis":{"isAnalyzing":false}}} -''' - ), - ]); - - final Artifacts artifacts = Artifacts.test(); - final AnalyzeCommand command = AnalyzeCommand( - terminal: Terminal.test(), - artifacts: artifacts, - logger: logger, + logger: BufferLogger.test(), platform: FakePlatform(), fileSystem: MemoryFileSystem.test(), processManager: processManager, ); - await FakeAsync().run((FakeAsync time) async { - final TestFlutterCommandRunner commandRunner = TestFlutterCommandRunner(); - commandRunner.addCommand(command); - unawaited(commandRunner.run(<String>['analyze', '--watch'])); - - while (!logger.statusText.contains('analyzed 1 file')) { - time.flushMicrotasks(); - } - completer.complete(); - return completer.future; - }); + final TestFlutterCommandRunner commandRunner = TestFlutterCommandRunner(); + commandRunner.addCommand(command); + unawaited(commandRunner.run(<String>['analyze', '--watch'])); + await stdin.stream.first; - expect(logger.statusText, contains('No issues found!')); - expect(logger.errorText, isEmpty); expect(processManager, hasNoRemainingExpectations); }); } 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 c29e76b0d99a9..56caf3dbfb180 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart @@ -14,7 +14,7 @@ import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/assemble.dart'; import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/common.dart'; import '../../src/context.dart'; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart index 48f8742299269..14151cefc9862 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart @@ -21,7 +21,7 @@ import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/attach.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device_port_forwarder.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/application_package.dart'; import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/macos/macos_ipad_device.dart'; @@ -568,20 +568,6 @@ class StreamLogger extends Logger { int hangingIndent, bool wrap, }) { - hadErrorOutput = true; - _log('[stderr] $message'); - } - - @override - void printWarning( - String message, { - bool emphasis, - TerminalColor color, - int indent, - int hangingIndent, - bool wrap, - }) { - hadWarningOutput = true; _log('[stderr] $message'); } @@ -598,18 +584,6 @@ class StreamLogger extends Logger { _log('[stdout] $message'); } - @override - void printBox( - String message, { - String title, - }) { - if (title == null) { - _log('[stdout] $message'); - } else { - _log('[stdout] $title: $message'); - } - } - @override void printTrace(String message) { _log('[verbose] $message'); 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 922ade2041aec..dcdc96b2fef8f 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 @@ -14,7 +14,6 @@ import 'package:flutter_tools/src/commands/build_ios.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; -import '../../general.shard/ios/xcresult_test_data.dart'; import '../../src/common.dart'; import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; @@ -84,35 +83,17 @@ void main() { return FakeCommand( command: const <String>[ 'rsync', - '-8', '-av', '--delete', 'build/ios/Release-iphoneos/Runner.app', 'build/ios/iphoneos', ], - onRun: onRun, - ); - } - - FakeCommand _setUpXCResultCommand({String stdout = '', void Function() onRun}) { - return FakeCommand( - command: const <String>[ - 'xcrun', - 'xcresulttool', - 'get', - '--path', - _xcBundleFilePath, - '--format', - 'json', - ], - stdout: stdout, - onRun: onRun, - ); + onRun: onRun); } // Creates a FakeCommand for the xcodebuild call to build the app // in the given configuration. - FakeCommand _setUpFakeXcodeBuildHandler({ bool verbose = false, bool simulator = false, int exitCode = 0, void Function() onRun }) { + FakeCommand _setUpFakeXcodeBuildHandler({ bool verbose = false, bool simulator = false, void Function() onRun }) { return FakeCommand( command: <String>[ 'xcrun', @@ -139,8 +120,6 @@ void main() { '-destination', 'generic/platform=iOS', ], - '-resultBundlePath', _xcBundleFilePath, - '-resultBundleVersion', '3', 'FLUTTER_SUPPRESS_ANALYTICS=true', 'COMPILER_INDEX_STORE_ENABLE=NO', ], @@ -148,7 +127,6 @@ void main() { TARGET_BUILD_DIR=build/ios/Release-iphoneos WRAPPER_NAME=Runner.app ''', - exitCode: exitCode, onRun: onRun, ); } @@ -303,257 +281,4 @@ void main() { Usage: () => usage, XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), }); - group('xcresults device', () { - testUsingContext('Trace error if xcresult is empty.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.traceText, contains('xcresult parser: Unrecognized top level json format.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - _setUpXCResultCommand(), - _setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Display xcresult issues on console if parsed.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); - expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - _setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), - _setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Do not display xcresult issues that needs to be discarded.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); - expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); - expect(testLogger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code'))); - expect(testLogger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99."))); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - _setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded), - _setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Trace if xcresult bundle does not exist.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1), - _setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), - _setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Extra error message for provision profile issue in xcresulb bundle.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains('Some Provisioning profile issue.')); - expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.')); - expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode')); - expect(testLogger.errorText, contains('open ios/Runner.xcworkspace')); - expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem:")); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - _setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue), - _setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - }); - - group('xcresults simulator', () { - testUsingContext('Trace error if xcresult is empty.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.traceText, contains('xcresult parser: Unrecognized top level json format.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler( - simulator: true, - exitCode: 1, - onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }, - ), - _setUpXCResultCommand(), - _setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Display xcresult issues on console if parsed.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); - expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler( - simulator: true, - exitCode: 1, - onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }, - ), - _setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), - _setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Do not display xcresult issues that needs to be discarded.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); - expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); - expect(testLogger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code'))); - expect(testLogger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99."))); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler( - simulator: true, - exitCode: 1, - onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }, - ), - _setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded), - _setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Trace if xcresult bundle does not exist.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler( - simulator: true, - exitCode: 1, - ), - _setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), - _setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - }); } - -const String _xcBundleFilePath = '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle'; 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 27734fb90e9d6..8226fc1bbd9a2 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 @@ -15,7 +15,6 @@ import 'package:flutter_tools/src/commands/build_ios.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; -import '../../general.shard/ios/xcresult_test_data.dart'; import '../../src/common.dart'; import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; @@ -63,43 +62,27 @@ void main() { }); // Sets up the minimal mock project files necessary to look like a Flutter project. - void _createCoreMockProjectFiles() { + void createCoreMockProjectFiles() { fileSystem.file('pubspec.yaml').createSync(); fileSystem.file('.packages').createSync(); fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true); } // Sets up the minimal mock project files necessary for iOS builds to succeed. - void _createMinimalMockProjectFiles() { + void createMinimalMockProjectFiles() { fileSystem.directory(fileSystem.path.join('ios', 'Runner.xcodeproj')).createSync(recursive: true); fileSystem.directory(fileSystem.path.join('ios', 'Runner.xcworkspace')).createSync(recursive: true); fileSystem.file(fileSystem.path.join('ios', 'Runner.xcodeproj', 'project.pbxproj')).createSync(); - _createCoreMockProjectFiles(); + createCoreMockProjectFiles(); } const FakeCommand xattrCommand = FakeCommand(command: <String>[ 'xattr', '-r', '-d', 'com.apple.FinderInfo', '/' ]); - FakeCommand _setUpXCResultCommand({String stdout = '', void Function() onRun}) { - return FakeCommand( - command: const <String>[ - 'xcrun', - 'xcresulttool', - 'get', - '--path', - _xcBundleFilePath, - '--format', - 'json', - ], - stdout: stdout, - onRun: onRun, - ); - } - // 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, void Function() onRun }) { return FakeCommand( command: <String>[ 'xcrun', @@ -114,15 +97,12 @@ void main() { '-sdk', 'iphoneos', '-destination', 'generic/platform=iOS', - '-resultBundlePath', '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle', - '-resultBundleVersion', '3', 'FLUTTER_SUPPRESS_ANALYTICS=true', 'COMPILER_INDEX_STORE_ENABLE=NO', '-archivePath', '/build/ios/archive/Runner', 'archive', ], stdout: 'STDOUT STUFF', - exitCode: exitCode, onRun: onRun, ); } @@ -145,7 +125,7 @@ void main() { testUsingContext('ipa build fails when there is no ios project', () async { final BuildCommand command = BuildCommand(); - _createCoreMockProjectFiles(); + createCoreMockProjectFiles(); expect(createTestCommandRunner(command).run( const <String>['build', 'ipa', '--no-pub'] @@ -159,7 +139,7 @@ void main() { testUsingContext('ipa build fails in debug with code analysis', () async { final BuildCommand command = BuildCommand(); - _createCoreMockProjectFiles(); + createCoreMockProjectFiles(); expect(createTestCommandRunner(command).run( const <String>['build', 'ipa', '--no-pub', '--debug', '--analyze-size'] @@ -192,7 +172,7 @@ void main() { testUsingContext('ipa build fails when export plist does not exist', () async { final BuildCommand command = BuildCommand(); - _createMinimalMockProjectFiles(); + createMinimalMockProjectFiles(); await expectToolExitLater( createTestCommandRunner(command).run(<String>[ @@ -215,7 +195,7 @@ void main() { testUsingContext('ipa build fails when export plist is not a file', () async { final Directory bogus = fileSystem.directory('bogus')..createSync(); final BuildCommand command = BuildCommand(); - _createMinimalMockProjectFiles(); + createMinimalMockProjectFiles(); await expectToolExitLater( createTestCommandRunner(command).run(<String>[ @@ -237,7 +217,7 @@ void main() { testUsingContext('ipa build invokes xcode build', () async { final BuildCommand command = BuildCommand(); - _createMinimalMockProjectFiles(); + createMinimalMockProjectFiles(); await createTestCommandRunner(command).run( const <String>['build', 'ipa', '--no-pub'] @@ -247,7 +227,7 @@ void main() { FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ xattrCommand, - _setUpFakeXcodeBuildHandler(), + setUpFakeXcodeBuildHandler(), ]), Platform: () => macosPlatform, XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), @@ -255,7 +235,7 @@ void main() { testUsingContext('ipa build invokes xcode build with verbosity', () async { final BuildCommand command = BuildCommand(); - _createMinimalMockProjectFiles(); + createMinimalMockProjectFiles(); await createTestCommandRunner(command).run( const <String>['build', 'ipa', '--no-pub', '-v'] @@ -264,7 +244,7 @@ void main() { FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ xattrCommand, - _setUpFakeXcodeBuildHandler(verbose: true), + setUpFakeXcodeBuildHandler(verbose: true), ]), Platform: () => macosPlatform, XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), @@ -272,7 +252,7 @@ void main() { testUsingContext('code size analysis fails when app not found', () async { final BuildCommand command = BuildCommand(); - _createMinimalMockProjectFiles(); + createMinimalMockProjectFiles(); await expectToolExitLater( createTestCommandRunner(command).run( @@ -290,7 +270,7 @@ void main() { testUsingContext('Performs code size analysis and sends analytics', () async { final BuildCommand command = BuildCommand(); - _createMinimalMockProjectFiles(); + createMinimalMockProjectFiles(); fileSystem.file('build/ios/archive/Runner.xcarchive/Products/Applications/Runner.app/Frameworks/App.framework/App') ..createSync(recursive: true) @@ -309,7 +289,7 @@ void main() { FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ xattrCommand, - _setUpFakeXcodeBuildHandler(onRun: () { + setUpFakeXcodeBuildHandler(onRun: () { fileSystem.file('build/flutter_size_01/snapshot.arm64.json') ..createSync(recursive: true) ..writeAsStringSync(''' @@ -338,7 +318,7 @@ void main() { final File exportOptions = fileSystem.file('ExportOptions.plist') ..createSync(); final BuildCommand command = BuildCommand(); - _createMinimalMockProjectFiles(); + createMinimalMockProjectFiles(); await createTestCommandRunner(command).run( <String>[ @@ -355,7 +335,7 @@ void main() { FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ xattrCommand, - _setUpFakeXcodeBuildHandler(), + setUpFakeXcodeBuildHandler(), exportArchiveCommand, ]), Platform: () => macosPlatform, @@ -363,133 +343,4 @@ void main() { XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), }); - - testUsingContext('Trace error if xcresult is empty.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.traceText, contains('xcresult parser: Unrecognized top level json format.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - _setUpXCResultCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Display xcresult issues on console if parsed.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); - expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - _setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Do not display xcresult issues that needs to be discarded.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); - expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); - expect(testLogger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code'))); - expect(testLogger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99."))); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - _setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - testUsingContext('Trace if xcresult bundle does not exist.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1), - _setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - - - testUsingContext('Extra error message for provision profile issue in xcresulb bundle.', () async { - final BuildCommand command = BuildCommand(); - - _createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains('Some Provisioning profile issue.')); - expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.')); - expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode')); - expect(testLogger.errorText, contains('open ios/Runner.xcworkspace')); - expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem:")); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ - xattrCommand, - _setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - _setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); } - -const String _xcBundleFilePath = '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle'; 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 0d73157cd1c1d..52b93f57488ce 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 @@ -114,7 +114,7 @@ void main() { expect(createTestCommandRunner(command).run( const <String>['build', 'linux', '--no-pub'] ), throwsToolExit(message: 'No Linux desktop project configured. See ' - 'https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' + 'https://flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' 'to learn about adding Linux support to a project.')); }, overrides: <Type, Generator>{ Platform: () => linuxPlatform, @@ -227,8 +227,6 @@ void main() { const <String>['build', 'linux', '--debug', '--no-pub'] ); expect(testLogger.statusText, isNot(contains('STDOUT STUFF'))); - expect(testLogger.warningText, isNot(contains('STDOUT STUFF'))); - expect(testLogger.errorText, isNot(contains('STDOUT STUFF'))); expect(testLogger.traceText, contains('STDOUT STUFF')); }, overrides: <Type, Generator>{ FileSystem: () => fileSystem, @@ -310,8 +308,6 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ); expect(testLogger.statusText, contains('STDOUT STUFF')); expect(testLogger.traceText, isNot(contains('STDOUT STUFF'))); - expect(testLogger.warningText, isNot(contains('STDOUT STUFF'))); - expect(testLogger.errorText, isNot(contains('STDOUT STUFF'))); }, overrides: <Type, Generator>{ FileSystem: () => fileSystem, ProcessManager: () => processManager, 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 4e5cc455d37d0..febf95159d82a 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 @@ -131,7 +131,7 @@ void main() { expect(createTestCommandRunner(command).run( const <String>['build', 'macos', '--no-pub'] ), throwsToolExit(message: 'No macOS desktop project configured. See ' - 'https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' + 'https://flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' 'to learn about adding macOS support to a project.')); }, overrides: <Type, Generator>{ Platform: () => macosPlatform, 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..d168ab2ecd0b1 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart @@ -3,13 +3,9 @@ // 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'; @@ -17,133 +13,31 @@ import '../../src/test_flutter_command_runner.dart'; void main() { testUsingContext('obfuscate requires split-debug-info', () { - final FakeBuildInfoCommand command = FakeBuildInfoCommand(); + final FakeBuildCommand command = FakeBuildCommand(); final CommandRunner<void> commandRunner = createTestCommandRunner(command); expect(() => commandRunner.run(<String>[ - 'fake', + 'build', '--obfuscate', - ]), throwsToolExit(message: '"--${FlutterOptions.kDartObfuscationOption}" can only be used in ' - 'combination with "--${FlutterOptions.kSplitDebugInfoOption}"')); - }); - group('Fatal Logs', () { - FakeBuildCommand command; - MemoryFileSystem fs; - - setUp(() { - fs = MemoryFileSystem.test(); - fs.file('/package/pubspec.yaml').createSync(recursive: true); - fs.currentDirectory = '/package'; - Cache.disableLocking(); - }); - - testUsingContext("doesn't fail if --fatal-warnings specified and no warnings occur", () async { - command = FakeBuildCommand(); - try { - await createTestCommandRunner(command).run(<String>[ - 'build', - 'test', - '--${FlutterOptions.kFatalWarnings}', - ]); - } on Exception { - fail('Unexpected exception thrown'); - } - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - - testUsingContext("doesn't fail if --fatal-warnings not specified", () async { - command = FakeBuildCommand(); - testLogger.printWarning('Warning: Mild annoyance Will Robinson!'); - try { - await createTestCommandRunner(command).run(<String>[ - 'build', - 'test', - ]); - } on Exception { - fail('Unexpected exception thrown'); - } - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - - testUsingContext('fails if --fatal-warnings specified and warnings emitted', () async { - command = FakeBuildCommand(); - testLogger.printWarning('Warning: Mild annoyance Will Robinson!'); - await expectLater(createTestCommandRunner(command).run(<String>[ - 'build', - 'test', - '--${FlutterOptions.kFatalWarnings}', - ]), throwsToolExit(message: 'Logger received warning output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - - testUsingContext('fails if --fatal-warnings specified and errors emitted', () async { - command = FakeBuildCommand(); - testLogger.printError('Error: Danger Will Robinson!'); - await expectLater(createTestCommandRunner(command).run(<String>[ - 'build', - 'test', - '--${FlutterOptions.kFatalWarnings}', - ]), throwsToolExit(message: 'Logger received error output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); + ]), throwsToolExit()); }); } -class FakeBuildInfoCommand extends FlutterCommand { - FakeBuildInfoCommand() : super() { +class FakeBuildCommand extends FlutterCommand { + FakeBuildCommand() { addSplitDebugInfoOption(); addDartObfuscationOption(); } @override - String get description => ''; - - @override - String get name => 'fake'; - - @override - Future<FlutterCommandResult> runCommand() async { - await getBuildInfo(); - return FlutterCommandResult.success(); - } -} - -class FakeBuildCommand extends BuildCommand { - FakeBuildCommand({bool verboseHelp = false}) : super(verboseHelp: verboseHelp) { - addSubcommand(FakeBuildSubcommand(verboseHelp: verboseHelp)); - } - - @override - String get description => ''; + String get description => throw UnimplementedError(); @override String get name => 'build'; @override Future<FlutterCommandResult> runCommand() async { - return FlutterCommandResult.success(); - } -} - -class FakeBuildSubcommand extends BuildSubCommand { - FakeBuildSubcommand({@required bool verboseHelp}) : super(verboseHelp: verboseHelp); - - @override - String get description => ''; - - @override - String get name => 'test'; - - @override - Future<FlutterCommandResult> runCommand() async { + await getBuildInfo(); return FlutterCommandResult.success(); } } 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 dea76d9b886ec..e783ab8ef43b2 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 @@ -111,6 +111,7 @@ void main() { 'DartObfuscation': 'false', 'TrackWidgetCreation': 'false', 'TreeShakeIcons': 'false', + 'baseHref': null, }); }), }); 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 8e16c301c6efd..764069004784c 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 @@ -25,8 +25,7 @@ const String flutterRoot = r'C:\flutter'; const String buildFilePath = r'C:\windows\CMakeLists.txt'; const String buildUwpFilePath = r'C:\winuwp\CMakeLists.txt'; const String visualStudioPath = r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community'; -const String _cmakePath = visualStudioPath + r'\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe'; -const String _defaultGenerator = 'Visual Studio 16 2019'; +const String cmakePath = visualStudioPath + r'\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe'; final Platform windowsPlatform = FakePlatform( operatingSystem: 'windows', @@ -46,6 +45,7 @@ void main() { FileSystem fileSystem; ProcessManager processManager; + FakeVisualStudio fakeVisualStudio; TestUsage usage; setUpAll(() { @@ -56,6 +56,7 @@ void main() { setUp(() { fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); Cache.flutterRoot = flutterRoot; + fakeVisualStudio = FakeVisualStudio(); usage = TestUsage(); }); @@ -82,14 +83,10 @@ void main() { // Returns the command matching the build_windows call to generate CMake // files. - FakeCommand cmakeGenerationCommand({ - void Function() onRun, - bool winuwp = false, - String generator = _defaultGenerator, - }) { + FakeCommand cmakeGenerationCommand({void Function() onRun, bool winuwp = false}) { return FakeCommand( command: <String>[ - _cmakePath, + cmakePath, '-S', fileSystem.path.dirname(winuwp ? buildUwpFilePath : buildFilePath), '-B', @@ -98,7 +95,7 @@ void main() { else r'build\windows', '-G', - generator, + 'Visual Studio 16 2019', ], onRun: onRun, ); @@ -113,7 +110,7 @@ void main() { }) { return FakeCommand( command: <String>[ - _cmakePath, + cmakePath, '--build', if (winuwp) r'build\winuwp' @@ -135,9 +132,9 @@ void main() { ); } - testUsingContext('Windows build fails when there is no cmake path', () async { + testUsingContext('Windows build fails when there is no vcvars64.bat', () async { final BuildWindowsCommand command = BuildWindowsCommand() - ..visualStudioOverride = FakeVisualStudio(cmakePath: null); + ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); expect(createTestCommandRunner(command).run( @@ -151,7 +148,7 @@ void main() { }); testUsingContext('Windows build fails when there is no windows project', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsCommand command = BuildWindowsCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockCoreProjectFiles(); @@ -159,7 +156,7 @@ void main() { expect(createTestCommandRunner(command).run( const <String>['windows', '--no-pub'] ), throwsToolExit(message: 'No Windows desktop project configured. See ' - 'https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' + 'https://flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' 'to learn about adding Windows support to a project.')); }, overrides: <Type, Generator>{ Platform: () => windowsPlatform, @@ -169,7 +166,7 @@ void main() { }); testUsingContext('Windows build fails on non windows platform', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsCommand command = BuildWindowsCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -185,7 +182,7 @@ void main() { }); testUsingContext('Windows build fails when feature is disabled', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsCommand command = BuildWindowsCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -201,7 +198,7 @@ void main() { }); testUsingContext('Windows build does not spew stdout to status logger', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsCommand command = BuildWindowsCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -226,7 +223,7 @@ void main() { }); testUsingContext('Windows build extracts errors from stdout', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsCommand command = BuildWindowsCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -284,7 +281,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier }); testUsingContext('Windows verbose build sets VERBOSE_SCRIPT_LOGGING', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsCommand command = BuildWindowsCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -310,7 +307,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier }); testUsingContext('Windows build invokes build and writes generated files', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsCommand command = BuildWindowsCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -375,7 +372,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier }); testUsingContext('Windows profile build passes Profile configuration', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsCommand command = BuildWindowsCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -395,29 +392,6 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), }); - testUsingContext('Windows build passes correct generator', () async { - const String generator = 'A different generator'; - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio( - cmakeGenerator: generator); - final BuildWindowsCommand command = BuildWindowsCommand() - ..visualStudioOverride = fakeVisualStudio; - setUpMockProjectFilesForBuild(); - - processManager = FakeProcessManager.list(<FakeCommand>[ - cmakeGenerationCommand(generator: generator), - buildCommand('Release'), - ]); - - await createTestCommandRunner(command).run( - const <String>['windows', '--release', '--no-pub'] - ); - }, overrides: <Type, Generator>{ - FileSystem: () => fileSystem, - ProcessManager: () => processManager, - Platform: () => windowsPlatform, - FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), - }); - testUsingContext('hidden when not enabled on Windows host', () { expect(BuildWindowsCommand().hidden, true); }, overrides: <Type, Generator>{ @@ -433,7 +407,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier }); testUsingContext('Performs code size analysis and sends analytics', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsCommand command = BuildWindowsCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -480,8 +454,8 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier Usage: () => usage, }); - testUsingContext('Windows UWP build fails when there is no windows project', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + testUsingContext('Windows build fails when there is no windows project', () async { + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsUwpCommand command = BuildWindowsUwpCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockCoreProjectFiles(); @@ -489,7 +463,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier expect(createTestCommandRunner(command).run( const <String>['winuwp', '--no-pub'] ), throwsToolExit(message: 'No Windows UWP desktop project configured. See ' - 'https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' + 'https://flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app ' 'to learn about adding Windows support to a project.')); }, overrides: <Type, Generator>{ Platform: () => windowsPlatform, @@ -499,7 +473,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier }); testUsingContext('Windows build fails on non windows platform', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsUwpCommand command = BuildWindowsUwpCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockUwpFilesForBuild(0); @@ -514,8 +488,8 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier FeatureFlags: () => TestFeatureFlags(isWindowsUwpEnabled: true), }); - testUsingContext('Windows UWP build fails on non windows platform', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + testUsingContext('Windows UWP uild fails on non windows platform', () async { + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsUwpCommand command = BuildWindowsUwpCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -531,7 +505,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier }); testUsingContext('Windows UWP build fails when the project version is out of date', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsUwpCommand command = BuildWindowsUwpCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockUwpFilesForBuild(-1); @@ -548,7 +522,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier }); testUsingContext('Windows UWP build fails when feature is disabled', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsUwpCommand command = BuildWindowsUwpCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -566,7 +540,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier }); testUsingContext('Windows UWP build completes successfully', () async { - final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(cmakePath); final BuildWindowsUwpCommand command = BuildWindowsUwpCommand() ..visualStudioOverride = fakeVisualStudio; setUpMockUwpFilesForBuild(0); @@ -601,14 +575,8 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier } class FakeVisualStudio extends Fake implements VisualStudio { - FakeVisualStudio({ - this.cmakePath = _cmakePath, - this.cmakeGenerator = 'Visual Studio 16 2019', - }); + FakeVisualStudio([this.cmakePath]); @override final String cmakePath; - - @override - final String cmakeGenerator; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart index 25d9f044dc356..1796f468e38c1 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart @@ -13,7 +13,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/config.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/version.dart'; import 'package:test/fake.dart'; 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 6b45a6dd69762..40f8a91aac99c 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 @@ -11,7 +11,7 @@ import 'package:flutter_tools/src/commands/create.dart'; import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; 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 059185f5c4ffe..8499eb06fdadb 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart @@ -20,11 +20,10 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/utils.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/commands/daemon.dart'; -import 'package:flutter_tools/src/daemon.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/ios_workflow.dart'; import 'package:flutter_tools/src/resident_runner.dart'; import 'package:test/fake.dart'; @@ -49,92 +48,75 @@ Future<T> _runFakeAsync<T>(Future<T> Function(FakeAsync time) f) async { }); } -class FakeDaemonStreams extends DaemonStreams { - final StreamController<Map<String, dynamic>> inputs = StreamController<Map<String, dynamic>>(); - final StreamController<Map<String, dynamic>> outputs = StreamController<Map<String, dynamic>>(); - - @override - Stream<Map<String, dynamic>> get inputStream { - return inputs.stream; - } - - @override - void send(Map<String, dynamic> message) { - outputs.add(message); - } - - @override - Future<void> dispose() async { - await inputs.close(); - // In some tests, outputs have no listeners. We don't wait for outputs to close. - unawaited(outputs.close()); - } -} - void main() { Daemon daemon; NotifyingLogger notifyingLogger; BufferLogger bufferLogger; group('daemon', () { - FakeDaemonStreams daemonStreams; - DaemonConnection daemonConnection; setUp(() { bufferLogger = BufferLogger.test(); notifyingLogger = NotifyingLogger(verbose: false, parent: bufferLogger); - daemonStreams = FakeDaemonStreams(); - daemonConnection = DaemonConnection( - daemonStreams: daemonStreams, - logger: bufferLogger, - ); }); - tearDown(() async { + tearDown(() { if (daemon != null) { return daemon.shutdown(); } notifyingLogger.dispose(); - await daemonConnection.dispose(); }); testUsingContext('daemon.version command should succeed', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'daemon.version'}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + commands.add(<String, dynamic>{'id': 0, 'method': 'daemon.version'}); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); expect(response['result'], isNotEmpty); expect(response['result'], isA<String>()); + await responses.close(); + await commands.close(); }); testUsingContext('daemon.getSupportedPlatforms command should succeed', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); // 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(<String, dynamic>{'id': 0, 'method': 'daemon.getSupportedPlatforms', 'params': <String, Object>{'projectRoot': projectPath}}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + commands.add(<String, dynamic>{'id': 0, 'method': 'daemon.getSupportedPlatforms', 'params': <String, Object>{'projectRoot': projectPath}}); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); expect(response['result'], isNotEmpty); expect((response['result'] as Map<String, dynamic>)['platforms'], <String>{'macos'}); + await responses.close(); + await commands.close(); }, overrides: <Type, Generator>{ // 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), }); testUsingContext('printError should send daemon.logMessage event', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); globals.printError('daemon.logMessage test'); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere((Map<String, dynamic> map) { + final Map<String, dynamic> response = await responses.stream.firstWhere((Map<String, dynamic> map) { return map['event'] == 'daemon.logMessage' && (map['params'] as Map<String, dynamic>)['level'] == 'error'; }); expect(response['id'], isNull); @@ -142,32 +124,19 @@ void main() { final Map<String, String> logMessage = castStringKeyedMap(response['params']).cast<String, String>(); expect(logMessage['level'], 'error'); expect(logMessage['message'], 'daemon.logMessage test'); - }, overrides: <Type, Generator>{ - Logger: () => notifyingLogger, - }); - - testUsingContext('printWarning should send daemon.logMessage event', () async { - daemon = Daemon( - daemonConnection, - notifyingLogger: notifyingLogger, - ); - globals.printWarning('daemon.logMessage test'); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere((Map<String, dynamic> map) { - return map['event'] == 'daemon.logMessage' && (map['params'] as Map<String, dynamic>)['level'] == 'warning'; - }); - expect(response['id'], isNull); - expect(response['event'], 'daemon.logMessage'); - final Map<String, String> logMessage = castStringKeyedMap(response['params']).cast<String, String>(); - expect(logMessage['level'], 'warning'); - expect(logMessage['message'], 'daemon.logMessage test'); + await responses.close(); + await commands.close(); }, overrides: <Type, Generator>{ Logger: () => notifyingLogger, }); testUsingContext('printStatus should log to stdout when logToStdout is enabled', () async { final StringBuffer buffer = await capturedConsolePrint(() { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, logToStdout: true, ); @@ -180,106 +149,121 @@ void main() { Logger: () => notifyingLogger, }); - testUsingContext('printBox should log to stdout when logToStdout is enabled', () async { - final StringBuffer buffer = await capturedConsolePrint(() { - daemon = Daemon( - daemonConnection, - notifyingLogger: notifyingLogger, - logToStdout: true, - ); - globals.printBox('This is the box message', title: 'Sample title'); - return Future<void>.value(); - }); - - expect(buffer.toString().trim(), contains('Sample title: This is the box message')); - }, overrides: <Type, Generator>{ - Logger: () => notifyingLogger, - }); - testUsingContext('daemon.shutdown command should stop daemon', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'daemon.shutdown'}); + commands.add(<String, dynamic>{'id': 0, 'method': 'daemon.shutdown'}); return daemon.onExit.then<void>((int code) async { - await daemonStreams.inputs.close(); + await commands.close(); expect(code, 0); }); }); testUsingContext('app.restart without an appId should report an error', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'app.restart'}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + commands.add(<String, dynamic>{'id': 0, 'method': 'app.restart'}); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); expect(response['error'], contains('appId is required')); + await responses.close(); + await commands.close(); }); testUsingContext('ext.flutter.debugPaint via service extension without an appId should report an error', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{ + commands.add(<String, dynamic>{ 'id': 0, 'method': 'app.callServiceExtension', 'params': <String, String>{ 'methodName': 'ext.flutter.debugPaint', }, }); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); expect(response['error'], contains('appId is required')); + await responses.close(); + await commands.close(); }); testUsingContext('app.stop without appId should report an error', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'app.stop'}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + commands.add(<String, dynamic>{'id': 0, 'method': 'app.stop'}); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); expect(response['error'], contains('appId is required')); + await responses.close(); + await commands.close(); }); testUsingContext('device.getDevices should respond with list', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'device.getDevices'}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + commands.add(<String, dynamic>{'id': 0, 'method': 'device.getDevices'}); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); expect(response['result'], isList); + await responses.close(); + await commands.close(); }); testUsingContext('device.getDevices reports available devices', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); daemon.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(FakeAndroidDevice()); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'device.getDevices'}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + commands.add(<String, dynamic>{'id': 0, 'method': 'device.getDevices'}); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); final dynamic result = response['result']; expect(result, isList); expect(result, isNotEmpty); + await responses.close(); + await commands.close(); }); testUsingContext('should send device.added event when device is discovered', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); @@ -287,12 +271,15 @@ void main() { daemon.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(FakeAndroidDevice()); - return daemonStreams.outputs.stream.skipWhile(_isConnectedEvent).first.then<void>((Map<String, dynamic> response) async { + return responses.stream.skipWhile(_isConnectedEvent).first.then<void>((Map<String, dynamic> response) async { expect(response['event'], 'device.added'); expect(response['params'], isMap); final Map<String, dynamic> params = castStringKeyedMap(response['params']); expect(params['platform'], isNotEmpty); // the fake device has a platform of 'android-arm' + + await responses.close(); + await commands.close(); }); }, overrides: <Type, Generator>{ AndroidWorkflow: () => FakeAndroidWorkflow(), @@ -301,90 +288,121 @@ void main() { }); testUsingContext('emulator.launch without an emulatorId should report an error', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'emulator.launch'}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + commands.add(<String, dynamic>{'id': 0, 'method': 'emulator.launch'}); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); expect(response['error'], contains('emulatorId is required')); + await responses.close(); + await commands.close(); }); testUsingContext('emulator.launch coldboot parameter must be boolean', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); final Map<String, dynamic> params = <String, dynamic>{'emulatorId': 'device', 'coldBoot': 1}; - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'emulator.launch', 'params': params}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + commands.add(<String, dynamic>{'id': 0, 'method': 'emulator.launch', 'params': params}); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); expect(response['error'], contains('coldBoot is not a bool')); + await responses.close(); + await commands.close(); }); testUsingContext('emulator.getEmulators should respond with list', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'emulator.getEmulators'}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere(_notEvent); + commands.add(<String, dynamic>{'id': 0, 'method': 'emulator.getEmulators'}); + final Map<String, dynamic> response = await responses.stream.firstWhere(_notEvent); expect(response['id'], 0); expect(response['result'], isList); + await responses.close(); + await commands.close(); }); testUsingContext('daemon can send exposeUrl requests to the client', () async { const String originalUrl = 'http://localhost:1234/'; const String mappedUrl = 'https://publichost:4321/'; + final StreamController<Map<String, dynamic>> input = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> output = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + input.stream, + output.add, notifyingLogger: notifyingLogger, ); // Respond to any requests from the daemon to expose a URL. - unawaited(daemonStreams.outputs.stream + unawaited(output.stream .firstWhere((Map<String, dynamic> request) => request['method'] == 'app.exposeUrl') .then((Map<String, dynamic> request) { expect((request['params'] as Map<String, dynamic>)['url'], equals(originalUrl)); - daemonStreams.inputs.add(<String, dynamic>{'id': request['id'], 'result': <String, dynamic>{'url': mappedUrl}}); + input.add(<String, dynamic>{'id': request['id'], 'result': <String, dynamic>{'url': mappedUrl}}); }) ); final String exposedUrl = await daemon.daemonDomain.exposeUrl(originalUrl); expect(exposedUrl, equals(mappedUrl)); + + await output.close(); + await input.close(); }); testUsingContext('devtools.serve command should return host and port on success', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'devtools.serve'}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere((Map<String, dynamic> response) => response['id'] == 0); + commands.add(<String, dynamic>{'id': 0, 'method': 'devtools.serve'}); + final Map<String, dynamic> response = await responses.stream.firstWhere((Map<String, dynamic> response) => response['id'] == 0); final Map<String, dynamic> result = response['result'] as Map<String, dynamic>; expect(result, isNotEmpty); expect(result['host'], '127.0.0.1'); expect(result['port'], 1234); + await responses.close(); + await commands.close(); }, overrides: <Type, Generator>{ DevtoolsLauncher: () => FakeDevtoolsLauncher(DevToolsServerAddress('127.0.0.1', 1234)), }); testUsingContext('devtools.serve command should return null fields if null returned', () async { + final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>(); + final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>(); daemon = Daemon( - daemonConnection, + commands.stream, + responses.add, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(<String, dynamic>{'id': 0, 'method': 'devtools.serve'}); - final Map<String, dynamic> response = await daemonStreams.outputs.stream.firstWhere((Map<String, dynamic> response) => response['id'] == 0); + commands.add(<String, dynamic>{'id': 0, 'method': 'devtools.serve'}); + final Map<String, dynamic> response = await responses.stream.firstWhere((Map<String, dynamic> response) => response['id'] == 0); final Map<String, dynamic> result = response['result'] as Map<String, dynamic>; expect(result, isNotEmpty); expect(result['host'], null); expect(result['port'], null); + await responses.close(); + await commands.close(); }, overrides: <Type, Generator>{ DevtoolsLauncher: () => FakeDevtoolsLauncher(null), }); @@ -423,6 +441,19 @@ void main() { expect(message.message, 'hello'); }); + group('daemon serialization', () { + test('OperationResult', () { + expect( + jsonEncodeObject(OperationResult.ok), + '{"code":0,"message":""}', + ); + expect( + jsonEncodeObject(OperationResult(1, 'foo')), + '{"code":1,"message":"foo"}', + ); + }); + }); + group('daemon queue', () { DebounceOperationQueue<int, String> queue; const Duration debounceDuration = Duration(seconds: 1); 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 427f66cfadc74..4bb74d806bc53 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart @@ -11,7 +11,7 @@ import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/devices.dart'; import 'package:flutter_tools/src/device.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/common.dart'; import '../../src/context.dart'; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart index e99711df3ac17..936b97c241db3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart @@ -30,7 +30,7 @@ import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/version.dart'; import 'package:flutter_tools/src/vscode/vscode.dart'; @@ -88,7 +88,7 @@ void main() { testUsingContext('No IDE Validator includes expected installation messages', () async { final ValidationResult result = await NoIdeValidator().validate(); - expect(result.type, ValidationType.notAvailable); + expect(result.type, ValidationType.missing); expect( result.messages.map((ValidationMessage vm) => vm.message), @@ -313,14 +313,6 @@ void main() { }, overrides: <Type, Generator>{ Usage: () => testUsage, }); - - testUsingContext('sending events can be skipped', () async { - await FakePassingDoctor(logger).diagnose(verbose: false, sendEvent: false); - - expect(testUsage.events, isEmpty); - }, overrides: <Type, Generator>{ - Usage: () => testUsage, - }); }); group('doctor with fake validators', () { @@ -464,78 +456,6 @@ void main() { '! Doctor found issues in 4 categories.\n' )); }); - - testUsingContext('validate PII can be hidden', () async { - expect(await FakePiiDoctor(logger).diagnose(showPii: false), isTrue); - expect(logger.statusText, equals( - '[✓] PII Validator\n' - ' • Does not contain PII\n' - '\n' - '• No issues found!\n' - )); - logger.clear(); - // PII shown. - expect(await FakePiiDoctor(logger).diagnose(), isTrue); - expect(logger.statusText, equals( - '[✓] PII Validator\n' - ' • Contains PII path/to/username\n' - '\n' - '• No issues found!\n' - )); - }); - }); - - group('doctor diagnosis wrapper', () { - TestUsage testUsage; - BufferLogger logger; - - setUp(() { - testUsage = TestUsage(); - logger = BufferLogger.test(); - }); - - testUsingContext('PII separated, events only sent once', () async { - final Doctor fakeDoctor = FakePiiDoctor(logger); - final DoctorText doctorText = DoctorText(logger, doctor: fakeDoctor); - const String expectedPiiText = '[✓] PII Validator\n' - ' • Contains PII path/to/username\n' - '\n' - '• No issues found!\n'; - const String expectedPiiStrippedText = - '[✓] PII Validator\n' - ' • Does not contain PII\n' - '\n' - '• No issues found!\n'; - - // Run each multiple times to make sure the logger buffer is being cleared, - // and that events are only sent once. - expect(await doctorText.text, expectedPiiText); - expect(await doctorText.text, expectedPiiText); - - expect(await doctorText.piiStrippedText, expectedPiiStrippedText); - expect(await doctorText.piiStrippedText, expectedPiiStrippedText); - - // Only one event sent. - expect(testUsage.events, <TestUsageEvent>[ - const TestUsageEvent( - 'doctor-result', - 'PiiValidator', - label: 'installed', - ), - ]); - }, overrides: <Type, Generator>{ - Usage: () => testUsage, - }); - - testUsingContext('without PII has same text and PII-stripped text', () async { - final Doctor fakeDoctor = FakePassingDoctor(logger); - final DoctorText doctorText = DoctorText(logger, doctor: fakeDoctor); - final String piiText = await doctorText.text; - expect(piiText, isNotEmpty); - expect(piiText, await doctorText.piiStrippedText); - }, overrides: <Type, Generator>{ - Usage: () => testUsage, - }); }); testUsingContext('validate non-verbose output wrapping', () async { @@ -615,6 +535,7 @@ void main() { )); }); + group('doctor with grouped validators', () { testUsingContext('validate diagnose combines validator output', () async { expect(await FakeGroupedDoctor(logger).diagnose(), isTrue); @@ -745,9 +666,6 @@ class NoOpDoctor implements Doctor { bool verbose = true, bool showColor = true, AndroidLicenseValidator androidLicenseValidator, - bool showPii = true, - List<ValidatorTask> startedValidatorTasks, - bool sendEvent = true, }) async => true; @override @@ -776,18 +694,6 @@ class PassingValidator extends DoctorValidator { } } -class PiiValidator extends DoctorValidator { - PiiValidator() : super('PII Validator'); - - @override - Future<ValidationResult> validate() async { - const List<ValidationMessage> messages = <ValidationMessage>[ - ValidationMessage('Contains PII path/to/username', piiStrippedMessage: 'Does not contain PII'), - ]; - return const ValidationResult(ValidationType.installed, messages); - } -} - class MissingValidator extends DoctorValidator { MissingValidator() : super('Missing Validator'); @@ -934,19 +840,6 @@ class FakeQuietDoctor extends Doctor { } } -/// A doctor that passes and contains PII that can be hidden. -class FakePiiDoctor extends Doctor { - FakePiiDoctor(Logger logger) : super(logger: logger); - - List<DoctorValidator> _validators; - @override - List<DoctorValidator> get validators { - return _validators ??= <DoctorValidator>[ - PiiValidator(), - ]; - } -} - /// A doctor with a validator that throws an exception. class FakeCrashingDoctor extends Doctor { FakeCrashingDoctor(Logger logger) : super(logger: logger); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/http_host_validator_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/http_host_validator_test.dart deleted file mode 100644 index 97a20d627453e..0000000000000 --- a/packages/flutter_tools/test/commands.shard/hermetic/http_host_validator_test.dart +++ /dev/null @@ -1,266 +0,0 @@ -// 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:io'; - -import 'package:flutter_tools/src/base/platform.dart'; -import 'package:flutter_tools/src/doctor_validator.dart'; -import 'package:flutter_tools/src/http_host_validator.dart'; - -import '../../src/common.dart'; -import '../../src/fake_http_client.dart'; -import '../../src/fakes.dart'; - -// The environment variables used to override some URLs -const String kTestEnvPubHost = 'https://pub.flutter-io.cn'; -const String kTestEnvGCloudHost = 'https://storage.flutter-io.cn'; -const Map<String, String> kTestEnvironment = <String, String>{ - 'PUB_HOSTED_URL': kTestEnvPubHost, - 'FLUTTER_STORAGE_BASE_URL': kTestEnvGCloudHost, - 'FLUTTER_DOCTOR_HOST_TIMEOUT': '1', -}; - -void main() { - group('http host validator', () { - const List<String> osTested = <String>['windows', 'macos', 'linux']; - - group('no env variables', () { - testWithoutContext('all http hosts are available', () async { - final FakeHttpClient mockClient = FakeHttpClient.any(); - - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os), - featureFlags: TestFeatureFlags(), - httpClient: mockClient, - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.installed)); - } - }); - - testWithoutContext('all http hosts are not available', () async { - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os), - featureFlags: TestFeatureFlags(), - httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse(kgCloudHttpHost), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(androidRequiredHttpHosts[0]), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(kPubDevHttpHost), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(macOSRequiredHttpHosts[0]), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - ]), - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.notAvailable)); - } - }); - - testWithoutContext('one http hosts are not available', () async { - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os), - featureFlags: TestFeatureFlags(), - httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse(kgCloudHttpHost), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(androidRequiredHttpHosts[0]), method: HttpMethod.head), - FakeRequest(Uri.parse(kPubDevHttpHost), method: HttpMethod.head), - FakeRequest(Uri.parse(macOSRequiredHttpHosts[0]), method: HttpMethod.head), - ]), - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.partial)); - } - }); - - testWithoutContext('one http hosts are not available', () async { - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os), - featureFlags: TestFeatureFlags(), - httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse(kgCloudHttpHost), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(androidRequiredHttpHosts[0]), method: HttpMethod.head), - FakeRequest(Uri.parse(kPubDevHttpHost), method: HttpMethod.head), - FakeRequest(Uri.parse(macOSRequiredHttpHosts[0]), method: HttpMethod.head), - ]), - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.partial)); - } - }); - }); - - group('with env variables', () { - testWithoutContext('all http hosts are available', () async { - final FakeHttpClient mockClient = FakeHttpClient.any(); - - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os, environment: kTestEnvironment), - featureFlags: TestFeatureFlags(), - httpClient: mockClient, - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.installed)); - } - }); - - testWithoutContext('all http hosts are not available', () async { - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os, environment: kTestEnvironment), - featureFlags: TestFeatureFlags(), - httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse(kTestEnvGCloudHost), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(androidRequiredHttpHosts[0]), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(kTestEnvPubHost), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(macOSRequiredHttpHosts[0]), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - ]), - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.notAvailable)); - } - }); - - testWithoutContext('one http hosts are not available', () async { - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os, environment: kTestEnvironment), - featureFlags: TestFeatureFlags(), - httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse(kTestEnvGCloudHost), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(androidRequiredHttpHosts[0]), method: HttpMethod.head), - FakeRequest(Uri.parse(kTestEnvPubHost), method: HttpMethod.head), - FakeRequest(Uri.parse(macOSRequiredHttpHosts[0]), method: HttpMethod.head), - ]), - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.partial)); - } - }); - - testWithoutContext('one http hosts are not available', () async { - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os, environment: kTestEnvironment), - featureFlags: TestFeatureFlags(), - httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse(kTestEnvGCloudHost), method: HttpMethod.head, responseError: const OSError('Name or service not known', -2)), - FakeRequest(Uri.parse(androidRequiredHttpHosts[0]), method: HttpMethod.head), - FakeRequest(Uri.parse(kTestEnvPubHost), method: HttpMethod.head), - FakeRequest(Uri.parse(macOSRequiredHttpHosts[0]), method: HttpMethod.head), - ]), - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.partial)); - } - }); - }); - - group('specific os disabled', () { - testWithoutContext('all http hosts are available - android disabled', () async { - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os), - featureFlags: TestFeatureFlags(isAndroidEnabled: false), - httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse(kgCloudHttpHost), method: HttpMethod.head), - FakeRequest(Uri.parse(kPubDevHttpHost), method: HttpMethod.head), - FakeRequest(Uri.parse(macOSRequiredHttpHosts[0]), method: HttpMethod.head), - ]), - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.installed)); - } - }); - - testWithoutContext('all http hosts are available - iOS disabled', () async { - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os), - featureFlags: TestFeatureFlags(isIOSEnabled: false), - httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse(kgCloudHttpHost), method: HttpMethod.head), - FakeRequest(Uri.parse(kPubDevHttpHost), method: HttpMethod.head), - FakeRequest(Uri.parse(androidRequiredHttpHosts[0]), method: HttpMethod.head), - ]), - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.installed)); - } - }); - - testWithoutContext('all http hosts are available - android, iOS disabled', () async { - // Run the check for all operating systems one by one - for(final String os in osTested) { - final HttpHostValidator httpHostValidator = HttpHostValidator( - platform: FakePlatform(operatingSystem: os), - featureFlags: TestFeatureFlags(isAndroidEnabled: false, isIOSEnabled: false), - httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse(kgCloudHttpHost), method: HttpMethod.head), - FakeRequest(Uri.parse(kPubDevHttpHost), method: HttpMethod.head), - ]), - ); - - // Run the validation check and get the results - final ValidationResult result = await httpHostValidator.validate(); - - // Check for a ValidationType.installed result - expect(result.type, equals(ValidationType.installed)); - } - }); - }); - }); -} 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 cdee1e2a5fa69..ebdd22007f5cc 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 @@ -8,7 +8,7 @@ import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/ide_config.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/template.dart'; import '../../src/common.dart'; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/proxy_validator_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/proxy_validator_test.dart index be600cba5fa67..c3da3a174f7a4 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/proxy_validator_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/proxy_validator_test.dart @@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:io' as io; -import 'dart:typed_data'; - -import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; import 'package:flutter_tools/src/proxy_validator.dart'; @@ -13,30 +9,6 @@ import 'package:flutter_tools/src/proxy_validator.dart'; import '../../src/common.dart'; void main() { - setUp(() { - setNetworkInterfaceLister( - ({ - bool includeLoopback = true, - bool includeLinkLocal = true, - InternetAddressType type = InternetAddressType.any, - }) async { - final List<FakeNetworkInterface> interfaces = <FakeNetworkInterface>[ - FakeNetworkInterface(<FakeInternetAddress>[ - const FakeInternetAddress('127.0.0.1') - ]), - FakeNetworkInterface(<FakeInternetAddress>[ - const FakeInternetAddress('::1') - ]) - ]; - - return Future<List<NetworkInterface>>.value(interfaces); - }); - }); - - tearDown(() { - resetNetworkInterfaceLister(); - }); - testWithoutContext('ProxyValidator does not show if HTTP_PROXY is not set', () { final Platform platform = FakePlatform(environment: <String, String>{}); @@ -65,17 +37,16 @@ void main() { final Platform platform = FakePlatform( environment: <String, String>{ 'HTTP_PROXY': 'fakeproxy.local', - 'NO_PROXY': 'localhost,127.0.0.1,::1', + 'NO_PROXY': 'localhost,127.0.0.1', }, ); final ValidationResult results = await ProxyValidator(platform: platform).validate(); expect(results.messages, const <ValidationMessage>[ ValidationMessage('HTTP_PROXY is set'), - ValidationMessage('NO_PROXY is localhost,127.0.0.1,::1'), - ValidationMessage('NO_PROXY contains localhost'), + ValidationMessage('NO_PROXY is localhost,127.0.0.1'), ValidationMessage('NO_PROXY contains 127.0.0.1'), - ValidationMessage('NO_PROXY contains ::1'), + ValidationMessage('NO_PROXY contains localhost'), ]); }); @@ -83,17 +54,16 @@ void main() { final Platform platform = FakePlatform( environment: <String, String>{ 'http_proxy': 'fakeproxy.local', - 'no_proxy': 'localhost,127.0.0.1,::1', + 'no_proxy': 'localhost,127.0.0.1', }, ); final ValidationResult results = await ProxyValidator(platform: platform).validate(); expect(results.messages, const <ValidationMessage>[ ValidationMessage('HTTP_PROXY is set'), - ValidationMessage('NO_PROXY is localhost,127.0.0.1,::1'), - ValidationMessage('NO_PROXY contains localhost'), + ValidationMessage('NO_PROXY is localhost,127.0.0.1'), ValidationMessage('NO_PROXY contains 127.0.0.1'), - ValidationMessage('NO_PROXY contains ::1'), + ValidationMessage('NO_PROXY contains localhost'), ]); }); @@ -101,157 +71,31 @@ void main() { final Platform platform = FakePlatform( environment: <String, String>{ 'HTTP_PROXY': 'fakeproxy.local', - 'NO_PROXY': '127.0.0.1,::1', + 'NO_PROXY': '127.0.0.1', }, ); final ValidationResult results = await ProxyValidator(platform: platform).validate(); expect(results.messages, const <ValidationMessage>[ ValidationMessage('HTTP_PROXY is set'), - ValidationMessage('NO_PROXY is 127.0.0.1,::1'), - ValidationMessage.hint('NO_PROXY does not contain localhost'), + ValidationMessage('NO_PROXY is 127.0.0.1'), ValidationMessage('NO_PROXY contains 127.0.0.1'), - ValidationMessage('NO_PROXY contains ::1'), + ValidationMessage.hint('NO_PROXY does not contain localhost'), ]); }); testWithoutContext('ProxyValidator reports issues when NO_PROXY is missing 127.0.0.1', () async { final Platform platform = FakePlatform(environment: <String, String>{ 'HTTP_PROXY': 'fakeproxy.local', - 'NO_PROXY': 'localhost,::1', - }); - final ValidationResult results = await ProxyValidator(platform: platform).validate(); - - expect(results.messages, const <ValidationMessage>[ - ValidationMessage('HTTP_PROXY is set'), - ValidationMessage('NO_PROXY is localhost,::1'), - ValidationMessage('NO_PROXY contains localhost'), - ValidationMessage.hint('NO_PROXY does not contain 127.0.0.1'), - ValidationMessage('NO_PROXY contains ::1'), - ]); - }); - - testWithoutContext('ProxyValidator reports issues when NO_PROXY is missing ::1', () async { - final Platform platform = FakePlatform(environment: <String, String>{ - 'HTTP_PROXY': 'fakeproxy.local', - 'NO_PROXY': 'localhost,127.0.0.1', + 'NO_PROXY': 'localhost', }); final ValidationResult results = await ProxyValidator(platform: platform).validate(); - expect(results.messages, const <ValidationMessage>[ - ValidationMessage('HTTP_PROXY is set'), - ValidationMessage('NO_PROXY is localhost,127.0.0.1'), - ValidationMessage('NO_PROXY contains localhost'), - ValidationMessage('NO_PROXY contains 127.0.0.1'), - ValidationMessage.hint('NO_PROXY does not contain ::1'), - ]); - }); - - testWithoutContext('ProxyValidator reports issues when NO_PROXY is missing localhost, 127.0.0.1', () async { - final Platform platform = FakePlatform( - environment: <String, String>{ - 'HTTP_PROXY': 'fakeproxy.local', - 'NO_PROXY': '::1', - }, - ); - final ValidationResult results = await ProxyValidator(platform: platform).validate(); - - expect(results.messages, const <ValidationMessage>[ - ValidationMessage('HTTP_PROXY is set'), - ValidationMessage('NO_PROXY is ::1'), - ValidationMessage.hint('NO_PROXY does not contain localhost'), - ValidationMessage.hint('NO_PROXY does not contain 127.0.0.1'), - ValidationMessage('NO_PROXY contains ::1'), - ]); - }); - - testWithoutContext('ProxyValidator reports issues when NO_PROXY is missing localhost, ::1', () async { - final Platform platform = FakePlatform( - environment: <String, String>{ - 'HTTP_PROXY': 'fakeproxy.local', - 'NO_PROXY': '127.0.0.1', - }, - ); - final ValidationResult results = await ProxyValidator(platform: platform).validate(); - - expect(results.messages, const <ValidationMessage>[ - ValidationMessage('HTTP_PROXY is set'), - ValidationMessage('NO_PROXY is 127.0.0.1'), - ValidationMessage.hint('NO_PROXY does not contain localhost'), - ValidationMessage('NO_PROXY contains 127.0.0.1'), - ValidationMessage.hint('NO_PROXY does not contain ::1'), - ]); - }); - - testWithoutContext('ProxyValidator reports issues when NO_PROXY is missing 127.0.0.1, ::1', () async { - final Platform platform = FakePlatform( - environment: <String, String>{ - 'HTTP_PROXY': 'fakeproxy.local', - 'NO_PROXY': 'localhost', - }, - ); - final ValidationResult results = await ProxyValidator(platform: platform).validate(); - expect(results.messages, const <ValidationMessage>[ ValidationMessage('HTTP_PROXY is set'), ValidationMessage('NO_PROXY is localhost'), - ValidationMessage('NO_PROXY contains localhost'), ValidationMessage.hint('NO_PROXY does not contain 127.0.0.1'), - ValidationMessage.hint('NO_PROXY does not contain ::1'), + ValidationMessage('NO_PROXY contains localhost'), ]); }); } - -class FakeNetworkInterface extends NetworkInterface { - FakeNetworkInterface(List<FakeInternetAddress> addresses): - super(FakeNetworkInterfaceDelegate(addresses)); - - @override - String get name => 'FakeNetworkInterface$index'; -} - -class FakeNetworkInterfaceDelegate implements io.NetworkInterface { - FakeNetworkInterfaceDelegate(this._fakeAddresses); - - final List<FakeInternetAddress> _fakeAddresses; - - @override - List<io.InternetAddress> get addresses => _fakeAddresses; - - @override - int get index => addresses.length; - - @override - String get name => 'FakeNetworkInterfaceDelegate$index'; -} - -class FakeInternetAddress implements io.InternetAddress { - const FakeInternetAddress(this._fakeAddress); - - final String _fakeAddress; - - @override - String get address => _fakeAddress; - - @override - String get host => throw UnimplementedError(); - - @override - bool get isLinkLocal => throw UnimplementedError(); - - @override - bool get isLoopback => true; - - @override - bool get isMulticast => throw UnimplementedError(); - - @override - Uint8List get rawAddress => throw UnimplementedError(); - - @override - Future<io.InternetAddress> reverse() => - throw UnimplementedError(); - - @override - io.InternetAddressType get type => throw UnimplementedError(); -} 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 0511ac1b3d232..8a916865b311a 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart @@ -14,22 +14,19 @@ import 'dart:async'; import 'package:file/file.dart'; import 'package:file/memory.dart'; -import 'package:flutter_tools/src/android/android_device.dart'; -import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/run.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/resident_runner.dart'; @@ -220,88 +217,6 @@ void main() { Cache: () => Cache.test(processManager: FakeProcessManager.any()), }); - testUsingContext('fails when v1 FlutterApplication is detected', () async { - fs.file('pubspec.yaml').createSync(); - fs.file('android/AndroidManifest.xml') - ..createSync(recursive: true) - ..writeAsStringSync(''' - <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.v1"> - <application - android:name="io.flutter.app.FlutterApplication"> - </application> - </manifest> - ''', flush: true); - fs.file('.packages').writeAsStringSync('\n'); - fs.file('lib/main.dart').createSync(recursive: true); - final AndroidDevice device = AndroidDevice('1234', - modelID: 'TestModel', - logger: testLogger, - platform: FakePlatform(), - androidSdk: FakeAndroidSdk(), - fileSystem: fs, - processManager: FakeProcessManager.any(), - ); - - mockDeviceManager - ..devices = <Device>[device] - ..targetDevices = <Device>[device]; - - final RunCommand command = RunCommand(); - await expectLater(createTestCommandRunner(command).run(<String>[ - 'run', - '--pub', - ]), throwsToolExit(message: 'Build failed due to use of deprecated Android v1 embedding.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - DeviceManager: () => mockDeviceManager, - Stdio: () => FakeStdio(), - Cache: () => Cache.test(processManager: FakeProcessManager.any()), - }); - - testUsingContext('fails when v1 metadata is detected', () async { - fs.file('pubspec.yaml').createSync(); - fs.file('android/AndroidManifest.xml') - ..createSync(recursive: true) - ..writeAsStringSync(''' - <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.v1"> - <application > - <meta-data - android:name="flutterEmbedding" - android:value="1" /> - </application> - </manifest> - ''', flush: true); - fs.file('.packages').writeAsStringSync('\n'); - fs.file('lib/main.dart').createSync(recursive: true); - final AndroidDevice device = AndroidDevice('1234', - modelID: 'TestModel', - logger: testLogger, - platform: FakePlatform(), - androidSdk: FakeAndroidSdk(), - fileSystem: fs, - processManager: FakeProcessManager.any(), - ); - - mockDeviceManager - ..devices = <Device>[device] - ..targetDevices = <Device>[device]; - - final RunCommand command = RunCommand(); - await expectLater(createTestCommandRunner(command).run(<String>[ - 'run', - '--pub', - ]), throwsToolExit(message: 'Build failed due to use of deprecated Android v1 embedding.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - DeviceManager: () => mockDeviceManager, - Stdio: () => FakeStdio(), - Cache: () => Cache.test(processManager: FakeProcessManager.any()), - }); - testUsingContext('shows unsupported devices when no supported devices are found', () async { final RunCommand command = RunCommand(); final FakeDevice mockDevice = FakeDevice(targetPlatform: TargetPlatform.android_arm, isLocalEmulator: true, sdkNameAndVersion: 'api-14'); @@ -379,75 +294,6 @@ void main() { }); }); - group('Fatal Logs', () { - TestRunCommandWithFakeResidentRunner command; - MemoryFileSystem fs; - - setUp(() { - command = TestRunCommandWithFakeResidentRunner() - ..fakeResidentRunner = FakeResidentRunner(); - fs = MemoryFileSystem.test(); - }); - - testUsingContext("doesn't fail if --fatal-warnings specified and no warnings occur", () async { - try { - await createTestCommandRunner(command).run(<String>[ - 'run', - '--no-pub', - '--no-hot', - '--${FlutterOptions.kFatalWarnings}', - ]); - } on Exception { - fail('Unexpected exception thrown'); - } - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - - testUsingContext("doesn't fail if --fatal-warnings not specified", () async { - testLogger.printWarning('Warning: Mild annoyance Will Robinson!'); - try { - await createTestCommandRunner(command).run(<String>[ - 'run', - '--no-pub', - '--no-hot', - ]); - } on Exception { - fail('Unexpected exception thrown'); - } - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - - testUsingContext('fails if --fatal-warnings specified and warnings emitted', () async { - testLogger.printWarning('Warning: Mild annoyance Will Robinson!'); - await expectLater(createTestCommandRunner(command).run(<String>[ - 'run', - '--no-pub', - '--no-hot', - '--${FlutterOptions.kFatalWarnings}', - ]), throwsToolExit(message: 'Logger received warning output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - - testUsingContext('fails if --fatal-warnings specified and errors emitted', () async { - testLogger.printError('Error: Danger Will Robinson!'); - await expectLater(createTestCommandRunner(command).run(<String>[ - 'run', - '--no-pub', - '--no-hot', - '--${FlutterOptions.kFatalWarnings}', - ]), throwsToolExit(message: 'Logger received error output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - }); - testUsingContext('should only request artifacts corresponding to connected devices', () async { mockDeviceManager.devices = <Device>[FakeDevice(targetPlatform: TargetPlatform.android_arm)]; @@ -620,10 +466,6 @@ class FakeDeviceManager extends Fake implements DeviceManager { } } -class FakeAndroidSdk extends Fake implements AndroidSdk { - @override - String get adbPath => 'adb'; -} class TestRunCommand extends RunCommand { @override @@ -654,7 +496,7 @@ class FakeDevice extends Fake implements Device { @override String get id => 'fake_device'; - void _throwToolExit(int code) => throwToolExit('FakeDevice tool exit', exitCode: code); + void _throwToolExit(int code) => throwToolExit(null, exitCode: code); @override Future<bool> get isLocalEmulator => Future<bool>.value(_isLocalEmulator); @@ -662,9 +504,6 @@ class FakeDevice extends Fake implements Device { @override bool supportsRuntimeMode(BuildMode mode) => true; - @override - Future<bool> get supportsHardwareRendering async => true; - @override bool supportsHotReload = false; @@ -703,7 +542,7 @@ class FakeDevice extends Fake implements Device { @override final PlatformType platformType = PlatformType.ios; - bool startAppSuccess; + bool startAppSuccess = true; @override DevFSWriter createDevFSWriter( @@ -725,12 +564,9 @@ class FakeDevice extends Fake implements Device { bool ipv6 = false, String userIdentifier, }) async { - if (startAppSuccess == false) { + if (!startAppSuccess) { return LaunchResult.failed(); } - if (startAppSuccess == true) { - return LaunchResult.succeeded(); - } final String dartFlags = debuggingOptions.dartFlags; // In release mode, --dart-flags should be set to the empty string and // provided flags should be dropped. In debug and profile modes, @@ -750,6 +586,19 @@ class FakeDevice extends Fake implements Device { } } +class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFactory { + ApplicationPackage package; + + @override + Future<ApplicationPackage> getPackageForPlatform( + TargetPlatform platform, { + BuildInfo buildInfo, + File applicationBinary, + }) async { + return package; + } +} + class TestRunCommandWithFakeResidentRunner extends RunCommand { FakeResidentRunner fakeResidentRunner; 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..914e8b1da0aed 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 @@ -10,7 +10,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/shell_completion.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/context.dart'; import '../../src/fakes.dart'; 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 17762d3954e4d..f77b30da3baa6 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart @@ -16,7 +16,6 @@ import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/test.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/project.dart'; -import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/test/runner.dart'; import 'package:flutter_tools/src/test/test_wrapper.dart'; import 'package:flutter_tools/src/test/watcher.dart'; @@ -561,7 +560,7 @@ dev_dependencies: DeviceManager: () => _FakeDeviceManager(<Device>[]), }); - // TODO(jiahaog): Remove this when web is supported. https://github.com/flutter/flutter/issues/66264 + // TODO(jiahaog): Remove this when web is supported. https://github.com/flutter/flutter/pull/74236 testUsingContext('Integration tests when only web devices are connected', () async { final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0); @@ -605,32 +604,6 @@ dev_dependencies: ]), }); - testUsingContext('Integration tests given flavor', () async { - final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0); - - final TestCommand testCommand = TestCommand(testRunner: testRunner); - final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand); - - await commandRunner.run(const <String>[ - 'test', - '--no-pub', - '--flavor', - 'dev', - 'integration_test', - ]); - - expect( - testRunner.lastDebuggingOptionsValue.buildInfo.flavor, - contains('dev'), - ); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - DeviceManager: () => _FakeDeviceManager(<Device>[ - FakeDevice('ephemeral', 'ephemeral', type: PlatformType.android), - ]), - }); - testUsingContext('Builds the asset manifest by default', () async { final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0); @@ -671,60 +644,6 @@ dev_dependencies: ProcessManager: () => FakeProcessManager.any(), DeviceManager: () => _FakeDeviceManager(<Device>[]), }); - - group('Fatal Logs', () { - testUsingContext("doesn't fail when --fatal-warnings is set and no warning output", () async { - final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0); - - final TestCommand testCommand = TestCommand(testRunner: testRunner); - final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand); - - try { - await commandRunner.run(const <String>[ - 'test', - '--no-pub', - '--${FlutterOptions.kFatalWarnings}', - ]); - } on Exception { - fail('Unexpected exception thrown'); - } - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - testUsingContext('fails if --fatal-warnings specified and warnings emitted', () async { - final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0); - - final TestCommand testCommand = TestCommand(testRunner: testRunner); - final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand); - - testLogger.printWarning('Warning: Mild annoyance, Will Robinson!'); - expect(commandRunner.run(const <String>[ - 'test', - '--no-pub', - '--${FlutterOptions.kFatalWarnings}', - ]), throwsToolExit(message: 'Logger received warning output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - testUsingContext('fails when --fatal-warnings is set and only errors emitted', () async { - final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0); - - final TestCommand testCommand = TestCommand(testRunner: testRunner); - final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand); - - testLogger.printError('Error: Danger Will Robinson!'); - expect(commandRunner.run(const <String>[ - 'test', - '--no-pub', - '--${FlutterOptions.kFatalWarnings}', - ]), throwsToolExit(message: 'Logger received error output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.')); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - }); - }); } class FakeFlutterTestRunner implements FlutterTestRunner { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart index 78018b4b6dc12..c8f2bc3e0be8e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart @@ -4,75 +4,9 @@ // @dart = 2.8 -import 'package:file/file.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/update_packages.dart'; -import 'package:flutter_tools/src/dart/pub.dart'; -import 'package:meta/meta.dart'; -import 'package:test/fake.dart'; import '../../src/common.dart'; -import '../../src/context.dart'; -import '../../src/test_flutter_command_runner.dart'; - -// An example pubspec.yaml from flutter, not necessary for it to be up to date. -const String kFlutterPubspecYaml = r''' -name: flutter -description: A framework for writing Flutter applications -homepage: http://flutter.dev - -environment: - sdk: ">=2.2.2 <3.0.0" - -dependencies: - # To update these, use "flutter update-packages --force-upgrade". - collection: 1.14.11 - meta: 1.1.8 - typed_data: 1.1.6 - vector_math: 2.0.8 - - sky_engine: - sdk: flutter - - gallery: - git: - url: https://github.com/flutter/gallery.git - ref: d00362e6bdd0f9b30bba337c358b9e4a6e4ca950 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_goldens: - sdk: flutter - - archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - -# PUBSPEC CHECKSUM: 1234 -'''; - -// An example pubspec.yaml, not necessary for it to be up to date. -const String kExamplesPubspecYaml = r''' -name: examples -description: Examples for flutter -homepage: http://flutter.dev - -version: 1.0.0 - -environment: - sdk: ">=2.14.0-383.0.dev <3.0.0" - flutter: ">=2.5.0-6.0.pre.30 <3.0.0" - -dependencies: - cupertino_icons: 1.0.4 - flutter: - sdk: flutter - - archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - -# PUBSPEC CHECKSUM: 6543 -'''; void main() { testWithoutContext('kManuallyPinnedDependencies pins are actually pins', () { @@ -82,148 +16,4 @@ void main() { reason: 'Version pins in kManuallyPinnedDependencies must be specific pins, not ranges.', ); }); - - group('update-packages', () { - FileSystem fileSystem; - Directory flutterSdk; - Directory flutter; - FakePub pub; - - setUpAll(() { - Cache.disableLocking(); - }); - - setUp(() { - fileSystem = MemoryFileSystem.test(); - flutterSdk = fileSystem.directory('flutter')..createSync(); - flutterSdk.childFile('version').writeAsStringSync('1.2.3'); - flutter = flutterSdk.childDirectory('packages').childDirectory('flutter') - ..createSync(recursive: true); - flutterSdk.childDirectory('dev').createSync(recursive: true); - flutterSdk.childDirectory('examples').childFile('pubspec.yaml') - ..createSync(recursive: true) - ..writeAsStringSync(kExamplesPubspecYaml); - flutter.childFile('pubspec.yaml').writeAsStringSync(kFlutterPubspecYaml); - Cache.flutterRoot = flutterSdk.absolute.path; - pub = FakePub(fileSystem); - }); - - testUsingContext('updates packages', () async { - final UpdatePackagesCommand command = UpdatePackagesCommand(); - await createTestCommandRunner(command).run(<String>['update-packages']); - expect(pub.pubGetDirectories, equals(<String>[ - '/.tmp_rand0/flutter_update_packages.rand0', - '/flutter/examples', - '/flutter/packages/flutter', - ])); - expect(pub.pubBatchDirectories, isEmpty); - }, overrides: <Type, Generator>{ - Pub: () => pub, - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - Cache: () => Cache.test( - processManager: FakeProcessManager.any(), - ), - }); - - testUsingContext('force updates packages', () async { - final UpdatePackagesCommand command = UpdatePackagesCommand(); - await createTestCommandRunner(command).run(<String>[ - 'update-packages', - '--force-upgrade', - ]); - expect(pub.pubGetDirectories, equals(<String>[ - '/.tmp_rand0/flutter_update_packages.rand0', - '/flutter/examples', - '/flutter/packages/flutter', - ])); - expect(pub.pubBatchDirectories, equals(<String>[ - '/.tmp_rand0/flutter_update_packages.rand0', - ])); - }, overrides: <Type, Generator>{ - Pub: () => pub, - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - Cache: () => Cache.test( - processManager: FakeProcessManager.any(), - ), - }); - }); -} - -class FakePub extends Fake implements Pub { - FakePub(this.fileSystem); - - final FileSystem fileSystem; - final List<String> pubGetDirectories = <String>[]; - final List<String> pubBatchDirectories = <String>[]; - - @override - Future<void> get({ - @required PubContext context, - String directory, - bool skipIfAbsent = false, - bool upgrade = false, - bool offline = false, - bool generateSyntheticPackage = false, - String flutterRootOverride, - bool checkUpToDate = false, - bool shouldSkipThirdPartyGenerator = true, - bool printProgress = true, - }) async { - pubGetDirectories.add(directory); - fileSystem.directory(directory).childFile('pubspec.lock') - ..createSync(recursive: true) - ..writeAsStringSync(''' -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: "direct dev" - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" -sdks: - dart: ">=2.14.0 <3.0.0" -'''); - fileSystem.currentDirectory - .childDirectory('.dart_tool') - .childFile('package_config.json') - ..createSync(recursive: true) - ..writeAsStringSync('{"configVersion":2,"packages":[]}'); - } - - @override - Future<void> batch( - List<String> arguments, { - @required PubContext context, - String directory, - MessageFilter filter, - String failureMessage = 'pub failed', - @required bool retry, - bool showTraceForErrors, - }) async { - pubBatchDirectories.add(directory); - -''' -Dart SDK 2.16.0-144.0.dev -Flutter SDK 2.9.0-1.0.pre.263 -flutter_api_samples 1.0.0 - -dependencies: -- cupertino_icons 1.0.4 -- collection 1.15.0 -- meta 1.7.0 -- typed_data 1.3.0 [collection] -- vector_math 2.1.1 - -dev dependencies: - -transitive dependencies: -- platform 3.1.0 -- process 4.2.4 [file path platform] -'''.split('\n').forEach(filter); - } } 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 d2beafda51707..4685923f087c4 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 @@ -7,13 +7,11 @@ import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/android/android_sdk.dart'; -import 'package:flutter_tools/src/android/android_studio.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/build_aar.dart'; -import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:meta/meta.dart'; @@ -22,8 +20,6 @@ import 'package:test/fake.dart'; import '../../src/android_common.dart'; import '../../src/common.dart'; import '../../src/context.dart'; -import '../../src/fake_process_manager.dart'; -import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { @@ -194,18 +190,9 @@ void main() { group('Gradle', () { Directory tempDir; - AndroidSdk mockAndroidSdk; - String gradlew; - FakeProcessManager processManager; - String flutterRoot; setUp(() { tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); - mockAndroidSdk = FakeAndroidSdk(); - gradlew = globals.fs.path.join(tempDir.path, 'flutter_project', '.android', - globals.platform.isWindows ? 'gradlew.bat' : 'gradlew'); - processManager = FakeProcessManager.empty(); - flutterRoot = getFlutterRoot(); }); tearDown(() { @@ -232,46 +219,6 @@ void main() { ProcessManager: () => FakeProcessManager.any(), }); }); - - testUsingContext('support ExtraDartFlagOptions', () async { - final String projectPath = await createProject(tempDir, - arguments: <String>['--no-pub', '--template=module']); - - processManager.addCommand(FakeCommand( - command: <String>[ - gradlew, - '-I=${globals.fs.path.join(flutterRoot, 'packages', 'flutter_tools', 'gradle','aar_init_script.gradle')}', - '-Pflutter-root=$flutterRoot', - '-Poutput-dir=${globals.fs.path.join(tempDir.path, 'flutter_project', 'build', 'host')}', - '-Pis-plugin=false', - '-PbuildNumber=1.0', - '-q', - '-Ptarget=${globals.fs.path.join('lib', 'main.dart')}', - '-Pdart-obfuscation=false', - '-Pextra-front-end-options=foo,bar', - '-Ptrack-widget-creation=true', - '-Ptree-shake-icons=true', - '-Ptarget-platform=android-arm,android-arm64,android-x64', - 'assembleAarRelease', - ], - exitCode: 1, - )); - - await expectLater(() => runBuildAarCommand(projectPath, arguments: <String>[ - '--no-debug', - '--no-profile', - '--extra-front-end-options=foo', - '--extra-front-end-options=bar', - ]), throwsToolExit(message: 'Gradle task assembleAarRelease failed with exit code 1')); - expect(processManager, hasNoRemainingExpectations); - }, - overrides: <Type, Generator>{ - AndroidSdk: () => mockAndroidSdk, - FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), - ProcessManager: () => processManager, - FeatureFlags: () => TestFeatureFlags(isIOSEnabled: false), - AndroidStudio: () => FakeAndroidStudio(), - }); }); } @@ -312,11 +259,3 @@ class FakeAndroidBuilder extends Fake implements AndroidBuilder { this.buildNumber = buildNumber; } } - -class FakeAndroidSdk extends Fake implements AndroidSdk { -} - -class FakeAndroidStudio extends Fake implements AndroidStudio { - @override - String get javaPath => 'java'; -} 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..af937bf6da067 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 @@ -11,7 +11,7 @@ import 'package:flutter_tools/src/android/android_studio.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/build_apk.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:test/fake.dart'; 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..0abdec8839a8b 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 @@ -10,7 +10,7 @@ import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/build_appbundle.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:test/fake.dart'; 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 8bb4cc8503753..de3aea4996c6d 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 @@ -20,7 +20,7 @@ import 'package:flutter_tools/src/bundle_builder.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/build_bundle.dart'; import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:meta/meta.dart'; import 'package:test/fake.dart'; @@ -89,7 +89,8 @@ void main() { globals.fs.file('lib/main.dart').createSync(recursive: true); globals.fs.file('pubspec.yaml').createSync(recursive: true); globals.fs.file('.packages').createSync(recursive: true); - final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand(bundleBuilder: FakeBundleBuilder())); + final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand() + ..bundleBuilder = FakeBundleBuilder()); expect(() => runner.run(<String>[ 'bundle', @@ -106,7 +107,8 @@ void main() { globals.fs.file('lib/main.dart').createSync(recursive: true); globals.fs.file('pubspec.yaml').createSync(); globals.fs.file('.packages').createSync(); - final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand(bundleBuilder: FakeBundleBuilder())); + final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand() + ..bundleBuilder = FakeBundleBuilder()); expect(() => runner.run(<String>[ 'bundle', @@ -123,7 +125,8 @@ void main() { globals.fs.file('lib/main.dart').createSync(recursive: true); globals.fs.file('pubspec.yaml').createSync(); globals.fs.file('.packages').createSync(); - final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand(bundleBuilder: FakeBundleBuilder())); + final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand() + ..bundleBuilder = FakeBundleBuilder()); expect(() => runner.run(<String>[ 'bundle', @@ -140,7 +143,8 @@ void main() { globals.fs.file('lib/main.dart').createSync(recursive: true); globals.fs.file('pubspec.yaml').createSync(); globals.fs.file('.packages').createSync(); - final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand(bundleBuilder: FakeBundleBuilder())); + final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand() + ..bundleBuilder = FakeBundleBuilder()); expect(() => runner.run(<String>[ 'bundle', @@ -157,7 +161,8 @@ void main() { globals.fs.file('lib/main.dart').createSync(recursive: true); globals.fs.file('pubspec.yaml').createSync(); globals.fs.file('.packages').createSync(); - final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand(bundleBuilder: FakeBundleBuilder())); + final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand() + ..bundleBuilder = FakeBundleBuilder()); await runner.run(<String>[ 'bundle', @@ -174,7 +179,8 @@ void main() { globals.fs.file('lib/main.dart').createSync(recursive: true); globals.fs.file('pubspec.yaml').createSync(); globals.fs.file('.packages').createSync(); - final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand(bundleBuilder: FakeBundleBuilder())); + final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand() + ..bundleBuilder = FakeBundleBuilder()); await runner.run(<String>[ 'bundle', @@ -191,7 +197,8 @@ void main() { globals.fs.file('lib/main.dart').createSync(recursive: true); globals.fs.file('pubspec.yaml').createSync(); globals.fs.file('.packages').createSync(); - final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand(bundleBuilder: FakeBundleBuilder())); + final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand() + ..bundleBuilder = FakeBundleBuilder()); await runner.run(<String>[ 'bundle', 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 3a1e9fb3beeaa..3c31a0b38378a 100755 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -21,7 +21,7 @@ import 'package:flutter_tools/src/commands/create.dart'; import 'package:flutter_tools/src/commands/create_base.dart'; import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/version.dart'; import 'package:process/process.dart'; @@ -147,8 +147,6 @@ void main() { projectDir, <String>['-t', 'skeleton', '-i', 'objc', '-a', 'java', '--implementation-tests'], <String>[ - '.dart_tool/flutter_gen/pubspec.yaml', - '.dart_tool/flutter_gen/gen_l10n/app_localizations.dart', 'analysis_options.yaml', 'android/app/src/main/java/com/example/flutter_project/MainActivity.java', 'android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java', @@ -1022,7 +1020,6 @@ void main() { expect(resourceFile, exists); final String contents = resourceFile.readAsStringSync(); expect(contents, contains('"CompanyName", "com.foo.bar"')); - expect(contents, contains('"FileDescription", "flutter_project"')); expect(contents, contains('"ProductName", "flutter_project"')); }, overrides: <Type, Generator>{ FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), @@ -1366,6 +1363,84 @@ void main() { ProcessManager: () => fakeProcessManager, }); + testUsingContext('UIViewControllerBasedStatusBarAppearance is YES for objc iOS project.', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + await runner.run(<String>['create', '--template=app', '--no-pub', '--org', 'com.foo.bar','--ios-language=objc', '--project-name=my_project', projectDir.path]); + + final String plistPath = globals.fs.path.join('ios', 'Runner', 'Info.plist'); + final File plistFile = globals.fs.file(globals.fs.path.join(projectDir.path, plistPath)); + expect(plistFile, exists); + final bool viewControllerBasedStatusBarAppearance = _getBooleanValueFromPlist(plistFile: plistFile, key: 'UIViewControllerBasedStatusBarAppearance'); + expect(viewControllerBasedStatusBarAppearance, true); + }); + + testUsingContext('UIViewControllerBasedStatusBarAppearance is YES for objc swift project.', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + await runner.run(<String>['create', '--template=app', '--no-pub', '--org', 'com.foo.bar','--ios-language=swift', '--project-name=my_project', projectDir.path]); + + final String plistPath = globals.fs.path.join('ios', 'Runner', 'Info.plist'); + final File plistFile = globals.fs.file(globals.fs.path.join(projectDir.path, plistPath)); + expect(plistFile, exists); + final bool viewControllerBasedStatusBarAppearance = _getBooleanValueFromPlist(plistFile: plistFile, key: 'UIViewControllerBasedStatusBarAppearance'); + expect(viewControllerBasedStatusBarAppearance, true); + }); + + testUsingContext('UIViewControllerBasedStatusBarAppearance is YES for objc iOS module.', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + await runner.run(<String>['create', '--template=module', '--org', 'com.foo.bar','--ios-language=objc', '--project-name=my_project', projectDir.path]); + + final String plistPath = globals.fs.path.join('.ios', 'Runner', 'Info.plist'); + final File plistFile = globals.fs.file(globals.fs.path.join(projectDir.path, plistPath)); + expect(plistFile, exists); + final bool viewControllerBasedStatusBarAppearance = _getBooleanValueFromPlist(plistFile: plistFile, key: 'UIViewControllerBasedStatusBarAppearance'); + expect(viewControllerBasedStatusBarAppearance, true); + }, overrides: <Type, Generator>{ + Pub: () => Pub( + fileSystem: globals.fs, + logger: globals.logger, + processManager: globals.processManager, + usage: globals.flutterUsage, + botDetector: globals.botDetector, + platform: globals.platform, + ), + }); + + testUsingContext('UIViewControllerBasedStatusBarAppearance is YES for swift iOS module.', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + await runner.run(<String>['create', '--template=module', '--org', 'com.foo.bar','--ios-language=swift', '--project-name=my_project', projectDir.path]); + + final String plistPath = globals.fs.path.join('.ios', 'Runner', 'Info.plist'); + final File plistFile = globals.fs.file(globals.fs.path.join(projectDir.path, plistPath)); + expect(plistFile, exists); + final bool viewControllerBasedStatusBarAppearance = _getBooleanValueFromPlist(plistFile: plistFile, key: 'UIViewControllerBasedStatusBarAppearance'); + expect(viewControllerBasedStatusBarAppearance, true); + }, overrides: <Type, Generator>{ + Pub: () => Pub( + fileSystem: globals.fs, + logger: globals.logger, + processManager: globals.processManager, + usage: globals.flutterUsage, + botDetector: globals.botDetector, + platform: globals.platform, + ), + }); + testUsingContext('display name is Title Case for objc iOS project.', () async { Cache.flutterRoot = '../..'; @@ -2976,3 +3051,10 @@ String _getStringValueFromPlist({File plistFile, String key}) { assert(keyIndex > 0); return plist[keyIndex+1].replaceAll('<string>', '').replaceAll('</string>', ''); } + +bool _getBooleanValueFromPlist({File plistFile, String key}) { + final List<String> plist = plistFile.readAsLinesSync().map((String line) => line.trim()).toList(); + final int keyIndex = plist.indexOf('<key>$key</key>'); + assert(keyIndex > 0); + return plist[keyIndex+1].replaceAll('<', '').replaceAll('/>', '') == 'true'; +} 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..b8eb0910ef167 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/format_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/format_test.dart @@ -8,7 +8,7 @@ import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/format.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/common.dart'; import '../../src/context.dart'; 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 da89e132a2392..e0bafd7978a5e 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart @@ -23,7 +23,7 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/packages.dart'; import 'package:flutter_tools/src/dart/pub.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/common.dart'; import '../../src/context.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 4821d90710079..745dcd07fb4d7 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart @@ -10,7 +10,7 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/upgrade.dart'; import 'package:flutter_tools/src/convert.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/persistent_tool_state.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/version.dart'; diff --git a/packages/flutter_tools/test/general.shard/analytics_test.dart b/packages/flutter_tools/test/general.shard/analytics_test.dart index 75266cd66a82a..cfb551fdce0cc 100644 --- a/packages/flutter_tools/test/general.shard/analytics_test.dart +++ b/packages/flutter_tools/test/general.shard/analytics_test.dart @@ -17,9 +17,8 @@ import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/commands/config.dart'; import 'package:flutter_tools/src/commands/doctor.dart'; import 'package:flutter_tools/src/doctor.dart'; -import 'package:flutter_tools/src/doctor_validator.dart'; import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/version.dart'; @@ -369,9 +368,6 @@ class FakeDoctor extends Fake implements Doctor { bool verbose = true, bool showColor = true, AndroidLicenseValidator androidLicenseValidator, - bool showPii = true, - List<ValidatorTask> startedValidatorTasks, - bool sendEvent = true, }) async { return diagnoseSucceeds; } diff --git a/packages/flutter_tools/test/general.shard/android/android_device_start_test.dart b/packages/flutter_tools/test/general.shard/android/android_device_start_test.dart index 4402ee8369d7f..ddf6d382ed9f6 100644 --- a/packages/flutter_tools/test/general.shard/android/android_device_start_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_device_start_test.dart @@ -68,7 +68,7 @@ void main() { final File apkFile = fileSystem.file('app.apk')..createSync(); final AndroidApk apk = AndroidApk( id: 'FlutterApp', - applicationPackage: apkFile, + file: apkFile, launchActivity: 'FlutterActivity', versionCode: 1, ); @@ -103,6 +103,7 @@ void main() { 'android.intent.action.RUN', '-f', '0x20000000', + '--ez', 'enable-background-compilation', 'true', '--ez', 'enable-dart-profiling', 'true', 'FlutterActivity', ], @@ -133,7 +134,7 @@ void main() { final File apkFile = fileSystem.file('app.apk')..createSync(); final AndroidApk apk = AndroidApk( id: 'FlutterApp', - applicationPackage: apkFile, + file: apkFile, launchActivity: 'FlutterActivity', versionCode: 1, ); @@ -171,7 +172,7 @@ void main() { final File apkFile = fileSystem.file('app.apk')..createSync(); final AndroidApk apk = AndroidApk( id: 'FlutterApp', - applicationPackage: apkFile, + file: apkFile, launchActivity: 'FlutterActivity', versionCode: 1, ); @@ -230,6 +231,7 @@ void main() { '-f', '0x20000000', // The DebuggingOptions arguments go here. + '--ez', 'enable-background-compilation', 'true', '--ez', 'enable-dart-profiling', 'true', '--ez', 'enable-software-rendering', 'true', '--ez', 'skia-deterministic-rendering', 'true', diff --git a/packages/flutter_tools/test/general.shard/android/android_emulator_test.dart b/packages/flutter_tools/test/general.shard/android/android_emulator_test.dart index c85b6e2c0a366..a09b3e326a48f 100644 --- a/packages/flutter_tools/test/general.shard/android/android_emulator_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_emulator_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'dart:async'; import 'package:flutter_tools/src/android/android_emulator.dart'; @@ -123,7 +125,7 @@ void main() { }); group('Android emulator launch ', () { - late FakeAndroidSdk mockSdk; + FakeAndroidSdk mockSdk; setUp(() { mockSdk = FakeAndroidSdk(); @@ -196,30 +198,10 @@ void main() { expect(logger.errorText, isEmpty); }); - - testWithoutContext('throws if emulator not found', () async { - mockSdk.emulatorPath = null; - - final AndroidEmulator emulator = AndroidEmulator( - emulatorID, - processManager: FakeProcessManager.empty(), - androidSdk: mockSdk, - logger: BufferLogger.test(), - ); - - await expectLater( - () => emulator.launch(startupDuration: Duration.zero), - throwsA(isException.having( - (Exception exception) => exception.toString(), - 'description', - contains('Emulator is missing from the Android SDK'), - )), - ); - }); }); } class FakeAndroidSdk extends Fake implements AndroidSdk { @override - String? emulatorPath; + String emulatorPath; } diff --git a/packages/flutter_tools/test/general.shard/android/android_install_test.dart b/packages/flutter_tools/test/general.shard/android/android_install_test.dart index 8e889d852ddc0..1eeb63e90c7c6 100644 --- a/packages/flutter_tools/test/general.shard/android/android_install_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_install_test.dart @@ -73,7 +73,7 @@ void main() { ]); final File apk = fileSystem.file('app.apk')..createSync(); final AndroidApk androidApk = AndroidApk( - applicationPackage: apk, + file: apk, id: 'app', versionCode: 22, launchActivity: 'Main', @@ -89,7 +89,7 @@ void main() { testWithoutContext('Cannot install app if APK file is missing', () async { final File apk = fileSystem.file('app.apk'); final AndroidApk androidApk = AndroidApk( - applicationPackage: apk, + file: apk, id: 'app', versionCode: 22, launchActivity: 'Main', @@ -117,7 +117,7 @@ void main() { ]); final File apk = fileSystem.file('app.apk')..createSync(); final AndroidApk androidApk = AndroidApk( - applicationPackage: apk, + file: apk, id: 'app', versionCode: 22, launchActivity: 'Main', @@ -146,7 +146,7 @@ void main() { ]); final File apk = fileSystem.file('app.apk')..createSync(); final AndroidApk androidApk = AndroidApk( - applicationPackage: apk, + file: apk, id: 'app', versionCode: 22, launchActivity: 'Main', @@ -190,7 +190,7 @@ void main() { ]); final File apk = fileSystem.file('app.apk')..createSync(); final AndroidApk androidApk = AndroidApk( - applicationPackage: apk, + file: apk, id: 'app', versionCode: 22, launchActivity: 'Main', @@ -224,7 +224,7 @@ void main() { final File apk = fileSystem.file('app.apk')..createSync(); fileSystem.file('app.apk.sha1').writeAsStringSync('example_sha'); final AndroidApk androidApk = AndroidApk( - applicationPackage: apk, + file: apk, id: 'app', versionCode: 22, launchActivity: 'Main', @@ -265,7 +265,7 @@ void main() { final File apk = fileSystem.file('app.apk')..createSync(); fileSystem.file('app.apk.sha1').writeAsStringSync('example_sha'); final AndroidApk androidApk = AndroidApk( - applicationPackage: apk, + file: apk, id: 'app', versionCode: 22, launchActivity: 'Main', @@ -298,7 +298,7 @@ void main() { ]); final File apk = fileSystem.file('app.apk')..createSync(); final AndroidApk androidApk = AndroidApk( - applicationPackage: apk, + file: apk, id: 'app', versionCode: 22, launchActivity: 'Main', diff --git a/packages/flutter_tools/test/general.shard/android/android_sdk_test.dart b/packages/flutter_tools/test/general.shard/android/android_sdk_test.dart index 35bcda4a76ec3..f9e8da857bd5a 100644 --- a/packages/flutter_tools/test/general.shard/android/android_sdk_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_sdk_test.dart @@ -9,7 +9,7 @@ import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/base/config.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/platform.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:meta/meta.dart'; import '../../src/common.dart'; diff --git a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart index c81f0c8069d05..787f2ec52d9df 100644 --- a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart @@ -9,7 +9,7 @@ import 'package:flutter_tools/src/android/android_studio.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/version.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/plist_parser.dart'; import 'package:test/fake.dart'; diff --git a/packages/flutter_tools/test/general.shard/android/android_studio_validator_test.dart b/packages/flutter_tools/test/general.shard/android/android_studio_validator_test.dart index 975f439fb0461..e12eaac1df5b2 100644 --- a/packages/flutter_tools/test/general.shard/android/android_studio_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_studio_validator_test.dart @@ -12,7 +12,7 @@ import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/common.dart'; import '../../src/context.dart'; diff --git a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart index b251ffd61a9d4..8cb73cd1945f1 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart @@ -12,7 +12,7 @@ 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'; import 'package:flutter_tools/src/base/terminal.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import '../../src/common.dart'; @@ -34,7 +34,6 @@ void main() { lockFileDepMissing, multidexErrorHandler, incompatibleKotlinVersionHandler, - minCompileSdkVersionHandler, ]) ); }); @@ -557,12 +556,8 @@ Command: /home/android/gradlew assembleRelease expect( testLogger.statusText, contains( - '\n' - '┌─ Flutter Fix ───────────────────────────────────────────────────────────────────────────────────┐\n' - '│ [!] Gradle does not have execution permission. │\n' - '│ You should change the ownership of the project directory to your user, or move the project to a │\n' - '│ directory with execute permissions. │\n' - '└─────────────────────────────────────────────────────────────────────────────────────────────────┘\n' + 'You should change the ownership of the project directory to your user, ' + 'or move the project to a directory with execute permissions.' ) ); }); @@ -587,12 +582,8 @@ Command: /home/android/gradlew assembleRelease expect( testLogger.statusText, contains( - '\n' - '┌─ Flutter Fix ───────────────────────────────────────────────────────────────────────────────────┐\n' - '│ [!] Gradle does not have execution permission. │\n' - '│ You should change the ownership of the project directory to your user, or move the project to a │\n' - '│ directory with execute permissions. │\n' - '└─────────────────────────────────────────────────────────────────────────────────────────────────┘\n' + 'You should change the ownership of the project directory to your user, ' + 'or move the project to a directory with execute permissions.' ) ); }); @@ -617,14 +608,11 @@ Command: /home/android/gradlew assembleRelease expect( testLogger.statusText, contains( - '\n' - '┌─ Flutter Fix ─────────────────────────────────────────────────────────────────────────────────┐\n' - '│ [!] Unable to download needed Android SDK components, as the following licenses have not been │\n' - '│ accepted: foo, bar │\n' - '│ │\n' - '│ To resolve this, please run the following command in a Terminal: │\n' - '│ flutter doctor --android-licenses │\n' - '└───────────────────────────────────────────────────────────────────────────────────────────────┘\n' + 'Unable to download needed Android SDK components, as the ' + 'following licenses have not been accepted:\n' + 'foo, bar\n\n' + 'To resolve this, please run the following command in a Terminal:\n' + 'flutter doctor --android-licenses' ) ); }); @@ -699,13 +687,9 @@ assembleFooTest expect( testLogger.statusText, contains( - '\n' - '┌─ Flutter Fix ───────────────────────────────────────────────────────────────────────────────────┐\n' - '│ [!] Gradle project does not define a task suitable for the requested build. │\n' - '│ │\n' - '│ The /android/app/build.gradle file defines product flavors: flavor1, flavor_2. You must specify │\n' - '│ a --flavor option to select one of them. │\n' - '└─────────────────────────────────────────────────────────────────────────────────────────────────┘\n' + 'The android/app/build.gradle file defines product ' + 'flavors: flavor1, flavor_2 ' + 'You must specify a --flavor option to select one of them.' ) ); expect(fakeProcessManager.hasRemainingExpectations, isFalse); @@ -738,13 +722,15 @@ assembleProfile expect( testLogger.statusText, contains( - '\n' - '┌─ Flutter Fix ─────────────────────────────────────────────────────────────────────────────────┐\n' - '│ [!] Gradle project does not define a task suitable for the requested build. │\n' - '│ │\n' - '│ The /android/app/build.gradle file does not define any custom product flavors. You cannot use │\n' - '│ the --flavor option. │\n' - '└───────────────────────────────────────────────────────────────────────────────────────────────┘\n' + 'Gradle project does not define a task suitable ' + 'for the requested build.' + ) + ); + expect( + testLogger.statusText, + contains( + 'The android/app/build.gradle file does not define any custom product flavors. ' + 'You cannot use the --flavor option.' ) ); expect(fakeProcessManager.hasRemainingExpectations, isFalse); @@ -776,19 +762,16 @@ assembleProfile testLogger.statusText, contains( '\n' - '┌─ Flutter Fix ─────────────────────────────────────────────────────────────────────────────────┐\n' - '│ The plugin webview_flutter requires a higher Android SDK version. │\n' - '│ Fix this issue by adding the following to the file /android/app/build.gradle: │\n' - '│ android { │\n' - '│ defaultConfig { │\n' - '│ minSdkVersion 19 │\n' - '│ } │\n' - '│ } │\n' - '│ │\n' - "│ Note that your app won't be available to users running Android SDKs below 19. │\n" - '│ Alternatively, try to find a version of this plugin that supports these lower versions of the │\n' - '│ Android SDK. │\n' - '└───────────────────────────────────────────────────────────────────────────────────────────────┘\n' + 'The plugin webview_flutter requires a higher Android SDK version.\n' + 'Fix this issue by adding the following to the file /android/app/build.gradle:\n' + 'android {\n' + ' defaultConfig {\n' + ' minSdkVersion 19\n' + ' }\n' + '}\n' + '\n' + "Note that your app won't be available to users running Android SDKs below 19.\n" + 'Alternatively, try to find a version of this plugin that supports these lower versions of the Android SDK.\n' ) ); }, overrides: <Type, Generator>{ @@ -819,15 +802,13 @@ assembleProfile testLogger.statusText, contains( '\n' - '┌─ Flutter Fix ─────────────────────────────────────────────────────────────────┐\n' - '│ This issue appears to be https://github.com/flutter/flutter/issues/58247. │\n' - '│ Fix this issue by adding the following to the file /android/app/build.gradle: │\n' - '│ android { │\n' - '│ lintOptions { │\n' - '│ checkReleaseBuilds false │\n' - '│ } │\n' - '│ } │\n' - '└───────────────────────────────────────────────────────────────────────────────┘\n' + 'This issue appears to be https://github.com/flutter/flutter/issues/58247.\n' + 'Fix this issue by adding the following to the file /android/app/build.gradle:\n' + 'android {\n' + ' lintOptions {\n' + ' checkReleaseBuilds false\n' + ' }\n' + '}\n' ) ); }, overrides: <Type, Generator>{ @@ -861,11 +842,10 @@ Execution failed for task ':app:generateDebugFeatureTransitiveDeps'. testLogger.statusText, contains( '\n' - '┌─ Flutter Fix ────────────────────────────────────────────────────────────────────────────┐\n' - '│ You need to update the lockfile, or disable Gradle dependency locking. │\n' - '│ To regenerate the lockfiles run: `./gradlew :generateLockfiles` in /android/build.gradle │\n' - '│ To remove dependency locking, remove the `dependencyLocking` from /android/build.gradle │\n' - '└──────────────────────────────────────────────────────────────────────────────────────────┘\n' + 'You need to update the lockfile, or disable Gradle dependency locking.\n' + 'To regenerate the lockfiles run: `./gradlew :generateLockfiles` in /android/build.gradle\n' + 'To remove dependency locking, remove the `dependencyLocking` from /android/build.gradle\n' + '\n' ) ); }, overrides: <Type, Generator>{ @@ -892,66 +872,9 @@ Execution failed for task ':app:generateDebugFeatureTransitiveDeps'. expect( testLogger.statusText, contains( - '\n' - '┌─ Flutter Fix ────────────────────────────────────────────────────────────────────────────────┐\n' - '│ [!] Your project requires a newer version of the Kotlin Gradle plugin. │\n' - '│ Find the latest version on https://kotlinlang.org/docs/gradle.html#plugin-and-versions, then │\n' - '│ update /android/build.gradle: │\n' - "│ ext.kotlin_version = '<latest-version>' │\n" - '└──────────────────────────────────────────────────────────────────────────────────────────────┘\n' - ) - ); - }, overrides: <Type, Generator>{ - GradleUtils: () => FakeGradleUtils(), - Platform: () => fakePlatform('android'), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), - }); - }); - - group('Required compileSdkVersion', () { - const String errorMessage = ''' -Execution failed for task ':app:checkDebugAarMetadata'. -> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction - > One or more issues found when checking AAR metadata values: - - The minCompileSdk (31) specified in a - dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties) - is greater than this module's compileSdkVersion (android-30). - Dependency: androidx.window:window-java:1.0.0-beta04. - AAR metadata file: ~/.gradle/caches/transforms-3/2adc32c5b3f24bed763d33fbfb203338/transformed/jetified-window-java-1.0.0-beta04/META-INF/com/android/build/gradle/aar-metadata.properties. - - The minCompileSdk (31) specified in a - dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties) - is greater than this module's compileSdkVersion (android-30). - Dependency: androidx.window:window:1.0.0-beta04. - AAR metadata file: ~/.gradle/caches/transforms-3/88f7e476ef68cecca729426edff955b5/transformed/jetified-window-1.0.0-beta04/META-INF/com/android/build/gradle/aar-metadata.properties. -'''; - - testWithoutContext('pattern', () { - expect( - minCompileSdkVersionHandler.test(errorMessage), - isTrue, - ); - }); - - testUsingContext('suggestion', () async { - await minCompileSdkVersionHandler.handler( - line: errorMessage, - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), - ); - - expect( - testLogger.statusText, - contains( - '\n' - '┌─ Flutter Fix ─────────────────────────────────────────────────────────────────┐\n' - '│ [!] Your project requires a higher compileSdkVersion. │\n' - '│ Fix this issue by bumping the compileSdkVersion in /android/app/build.gradle: │\n' - '│ android { │\n' - '│ compileSdkVersion 31 │\n' - '│ } │\n' - '└───────────────────────────────────────────────────────────────────────────────┘\n' + '[!] Your project requires a newer version of the Kotlin Gradle plugin.\n' + ' Find the latest version on https://kotlinlang.org/docs/gradle.html#plugin-and-versions, then update /android/build.gradle:\n' + " ext.kotlin_version = '<latest-version>'\n" ) ); }, overrides: <Type, Generator>{ diff --git a/packages/flutter_tools/test/general.shard/android/gradle_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_test.dart index d98c34d2069ab..7bd9322309a5f 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_test.dart @@ -15,7 +15,7 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:test/fake.dart'; diff --git a/packages/flutter_tools/test/general.shard/android/multidex_test.dart b/packages/flutter_tools/test/general.shard/android/multidex_test.dart index 07627f1ef1996..a4cc8e871c6da 100644 --- a/packages/flutter_tools/test/general.shard/android/multidex_test.dart +++ b/packages/flutter_tools/test/general.shard/android/multidex_test.dart @@ -8,7 +8,7 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/android/multidex.dart'; import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/common.dart'; import '../../src/context.dart'; diff --git a/packages/flutter_tools/test/general.shard/application_package_test.dart b/packages/flutter_tools/test/general.shard/application_package_test.dart index c5c41035d17d8..d0e0106a84c30 100644 --- a/packages/flutter_tools/test/general.shard/application_package_test.dart +++ b/packages/flutter_tools/test/general.shard/application_package_test.dart @@ -17,7 +17,7 @@ import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/fuchsia/application_package.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/application_package.dart'; import 'package:flutter_tools/src/ios/plist_parser.dart'; import 'package:flutter_tools/src/project.dart'; @@ -84,8 +84,6 @@ void main() { applicationBinary: apkFile, ); expect(applicationPackage.name, 'app.apk'); - expect(applicationPackage, isA<PrebuiltApplicationPackage>()); - expect((applicationPackage as PrebuiltApplicationPackage).applicationPackage.path, apkFile.path); expect(fakeProcessManager.hasRemainingExpectations, isFalse); }, overrides: overrides); @@ -300,10 +298,9 @@ void main() { testPlistParser.setProperty('CFBundleIdentifier', 'fooBundleId'); final PrebuiltIOSApp iosApp = IOSApp.fromPrebuiltApp(globals.fs.file('bundle.app')) as PrebuiltIOSApp; expect(testLogger.errorText, isEmpty); - expect(iosApp.uncompressedBundle.path, 'bundle.app'); + expect(iosApp.bundleDir.path, 'bundle.app'); expect(iosApp.id, 'fooBundleId'); expect(iosApp.bundleName, 'bundle.app'); - expect(iosApp.applicationPackage.path, globals.fs.directory('bundle.app').path); }, overrides: overrides); testUsingContext('Bad ipa zip-file, no payload dir', () { @@ -351,10 +348,9 @@ void main() { }; final PrebuiltIOSApp iosApp = IOSApp.fromPrebuiltApp(globals.fs.file('app.ipa')) as PrebuiltIOSApp; expect(testLogger.errorText, isEmpty); - expect(iosApp.uncompressedBundle.path, endsWith('bundle.app')); + expect(iosApp.bundleDir.path, endsWith('bundle.app')); expect(iosApp.id, 'fooBundleId'); expect(iosApp.bundleName, 'bundle.app'); - expect(iosApp.applicationPackage.path, globals.fs.file('app.ipa').path); }, overrides: overrides); testUsingContext('returns null when there is no ios or .ios directory', () async { @@ -431,7 +427,6 @@ void main() { final PrebuiltFuchsiaApp fuchsiaApp = FuchsiaApp.fromPrebuiltApp(globals.fs.file('bundle.far')) as PrebuiltFuchsiaApp; expect(testLogger.errorText, isEmpty); expect(fuchsiaApp.id, 'bundle.far'); - expect(fuchsiaApp.applicationPackage.path, globals.fs.file('bundle.far').path); }, overrides: overrides); testUsingContext('returns null when there is no fuchsia', () async { diff --git a/packages/flutter_tools/test/general.shard/artifact_updater_test.dart b/packages/flutter_tools/test/general.shard/artifact_updater_test.dart index 12bfef989b393..9946e803279b9 100644 --- a/packages/flutter_tools/test/general.shard/artifact_updater_test.dart +++ b/packages/flutter_tools/test/general.shard/artifact_updater_test.dart @@ -32,7 +32,6 @@ void main() { httpClient: FakeHttpClient.any(), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); await artifactUpdater.downloadZipArchive( @@ -56,7 +55,6 @@ void main() { httpClient: FakeHttpClient.any(), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); // Unrelated file from another cache. fileSystem.file('out/bar').createSync(recursive: true); @@ -94,7 +92,6 @@ void main() { ]), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); await artifactUpdater.downloadZipArchive( @@ -130,7 +127,6 @@ void main() { ]), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); await artifactUpdater.downloadZipArchive( @@ -174,7 +170,6 @@ void main() { ]), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); await expectLater(() async => artifactUpdater.downloadZipArchive( @@ -203,7 +198,6 @@ void main() { ]), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); await artifactUpdater.downloadZipArchive( @@ -231,7 +225,6 @@ void main() { ]), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); await expectLater(() async => artifactUpdater.downloadZipArchive( @@ -258,16 +251,15 @@ void main() { }, ), httpClient: FakeHttpClient.list(<FakeRequest>[ - FakeRequest(Uri.parse('http://foo-bar/test.zip'), responseError: ArgumentError()) + FakeRequest(Uri.parse('http:///foo-bar/test.zip'), responseError: ArgumentError()) ]), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://foo-bar/test.zip'], ); await expectLater(() async => artifactUpdater.downloadZipArchive( 'test message', - Uri.parse('http://foo-bar/test.zip'), + Uri.parse('http:///foo-bar/test.zip'), fileSystem.currentDirectory.childDirectory('out'), ), throwsToolExit()); @@ -289,7 +281,6 @@ void main() { ]), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); await expectLater(() async => artifactUpdater.downloadZipArchive( @@ -314,7 +305,6 @@ void main() { httpClient: FakeHttpClient.any(), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); operatingSystemUtils.failures = 1; @@ -339,7 +329,6 @@ void main() { httpClient: FakeHttpClient.any(), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); operatingSystemUtils.failures = 1; @@ -364,7 +353,6 @@ void main() { httpClient: FakeHttpClient.any(), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); operatingSystemUtils.failures = 2; @@ -389,7 +377,6 @@ void main() { httpClient: FakeHttpClient.any(), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); operatingSystemUtils.failures = 2; @@ -414,7 +401,6 @@ void main() { httpClient: FakeHttpClient.any(), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); await artifactUpdater.downloadZippedTarball( @@ -437,7 +423,6 @@ void main() { httpClient: FakeHttpClient.any(), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); artifactUpdater.downloadedFiles.addAll(<File>[ @@ -465,7 +450,6 @@ void main() { httpClient: FakeHttpClient.any(), tempStorage: fileSystem.currentDirectory.childDirectory('temp') ..createSync(), - allowedBaseUrls: <String>['http://test.zip'], ); final Directory errorDirectory = fileSystem.currentDirectory diff --git a/packages/flutter_tools/test/general.shard/asset_bundle_package_fonts_test.dart b/packages/flutter_tools/test/general.shard/asset_bundle_package_fonts_test.dart index a312ea919713a..ac49c9529d5d9 100644 --- a/packages/flutter_tools/test/general.shard/asset_bundle_package_fonts_test.dart +++ b/packages/flutter_tools/test/general.shard/asset_bundle_package_fonts_test.dart @@ -12,7 +12,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../src/common.dart'; import '../src/context.dart'; diff --git a/packages/flutter_tools/test/general.shard/asset_bundle_package_test.dart b/packages/flutter_tools/test/general.shard/asset_bundle_package_test.dart index a733bd2f51750..eec7eff438e78 100644 --- a/packages/flutter_tools/test/general.shard/asset_bundle_package_test.dart +++ b/packages/flutter_tools/test/general.shard/asset_bundle_package_test.dart @@ -12,7 +12,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../src/common.dart'; import '../src/context.dart'; diff --git a/packages/flutter_tools/test/general.shard/asset_bundle_test.dart b/packages/flutter_tools/test/general.shard/asset_bundle_test.dart index 5400ddddade71..45d965372ca9a 100644 --- a/packages/flutter_tools/test/general.shard/asset_bundle_test.dart +++ b/packages/flutter_tools/test/general.shard/asset_bundle_test.dart @@ -13,7 +13,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/bundle_builder.dart'; import 'package:flutter_tools/src/devfs.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../src/common.dart'; import '../src/context.dart'; @@ -311,7 +311,7 @@ flutter: await writeBundle(directory, <String, DevFSContent>{}, loggerOverride: testLogger); - expect(testLogger.warningText, contains('Expected Error Text')); + expect(testLogger.errorText, contains('Expected Error Text')); }); testUsingContext('does not unnecessarily recreate asset manifest, font manifest, license', () async { diff --git a/packages/flutter_tools/test/general.shard/asset_bundle_variant_test.dart b/packages/flutter_tools/test/general.shard/asset_bundle_variant_test.dart index 7ae9dd1f42568..a321d7d0839c0 100644 --- a/packages/flutter_tools/test/general.shard/asset_bundle_variant_test.dart +++ b/packages/flutter_tools/test/general.shard/asset_bundle_variant_test.dart @@ -12,7 +12,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../src/common.dart'; import '../src/context.dart'; diff --git a/packages/flutter_tools/test/general.shard/asset_test.dart b/packages/flutter_tools/test/general.shard/asset_test.dart index 0b134558ed755..2b387458756a3 100644 --- a/packages/flutter_tools/test/general.shard/asset_test.dart +++ b/packages/flutter_tools/test/general.shard/asset_test.dart @@ -7,7 +7,7 @@ import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../src/common.dart'; import '../src/context.dart'; diff --git a/packages/flutter_tools/test/general.shard/base/logger_test.dart b/packages/flutter_tools/test/general.shard/base/logger_test.dart index 3fd56f8914224..3fc06cb5b8b55 100644 --- a/packages/flutter_tools/test/general.shard/base/logger_test.dart +++ b/packages/flutter_tools/test/general.shard/base/logger_test.dart @@ -282,31 +282,6 @@ void main() { mockLogger.errorText, matches('^$red' r'\[ (?: {0,2}\+[0-9]{1,4} ms| )\] ' '${bold}Helpless!$resetBold$resetColor' r'\n$')); }); - - testWithoutContext('printBox', () { - final BufferLogger mockLogger = BufferLogger( - terminal: AnsiTerminal( - stdio: FakeStdio(), - platform: FakePlatform(stdoutSupportsAnsi: true), - ), - outputPreferences: OutputPreferences.test(showColor: true), - ); - final VerboseLogger verboseLogger = VerboseLogger( - mockLogger, stopwatchFactory: FakeStopwatchFactory(stopwatch: fakeStopWatch), - ); - - verboseLogger.printBox('This is the box message', title: 'Sample title'); - - expect( - mockLogger.statusText, - contains('[ ] \x1B[1m\x1B[22m\n' - '\x1B[1m ┌─ Sample title ──────────┐\x1B[22m\n' - '\x1B[1m │ This is the box message │\x1B[22m\n' - '\x1B[1m └─────────────────────────┘\x1B[22m\n' - '\x1B[1m \x1B[22m\n' - ), - ); - }); }); testWithoutContext('Logger does not throw when stdio write throws synchronously', () async { @@ -953,184 +928,6 @@ void main() { expect(lines[0], equals('')); }); - testWithoutContext('Stdout printBox puts content inside a box', () { - final Logger logger = StdoutLogger( - terminal: AnsiTerminal( - stdio: fakeStdio, - platform: FakePlatform(), - ), - stdio: fakeStdio, - outputPreferences: OutputPreferences.test(showColor: true), - ); - logger.printBox('Hello world', title: 'Test title'); - final String stdout = fakeStdio.writtenToStdout.join(''); - expect(stdout, - contains( - '\n' - '┌─ Test title ┐\n' - '│ Hello world │\n' - '└─────────────┘\n' - ), - ); - }); - - testWithoutContext('Stdout printBox does not require title', () { - final Logger logger = StdoutLogger( - terminal: AnsiTerminal( - stdio: fakeStdio, - platform: FakePlatform(), - ), - stdio: fakeStdio, - outputPreferences: OutputPreferences.test(showColor: true), - ); - logger.printBox('Hello world'); - final String stdout = fakeStdio.writtenToStdout.join(''); - expect(stdout, - contains( - '\n' - '┌─────────────┐\n' - '│ Hello world │\n' - '└─────────────┘\n' - ), - ); - }); - - testWithoutContext('Stdout printBox handles new lines', () { - final Logger logger = StdoutLogger( - terminal: AnsiTerminal( - stdio: fakeStdio, - platform: FakePlatform(), - ), - stdio: fakeStdio, - outputPreferences: OutputPreferences.test(showColor: true), - ); - logger.printBox('Hello world\nThis is a new line', title: 'Test title'); - final String stdout = fakeStdio.writtenToStdout.join(''); - expect(stdout, - contains( - '\n' - '┌─ Test title ───────┐\n' - '│ Hello world │\n' - '│ This is a new line │\n' - '└────────────────────┘\n' - ), - ); - }); - - testWithoutContext('Stdout printBox handles content with ANSI escape characters', () { - final Logger logger = StdoutLogger( - terminal: AnsiTerminal( - stdio: fakeStdio, - platform: FakePlatform(), - ), - stdio: fakeStdio, - outputPreferences: OutputPreferences.test(showColor: true), - ); - const String bold = '\u001B[1m'; - const String clear = '\u001B[2J\u001B[H'; - logger.printBox('${bold}Hello world$clear', title: 'Test title'); - final String stdout = fakeStdio.writtenToStdout.join(''); - expect(stdout, - contains( - '\n' - '┌─ Test title ┐\n' - '│ ${bold}Hello world$clear │\n' - '└─────────────┘\n' - ), - ); - }); - - testWithoutContext('Stdout printBox handles column limit', () { - const int columnLimit = 14; - final Logger logger = StdoutLogger( - terminal: AnsiTerminal( - stdio: fakeStdio, - platform: FakePlatform(), - ), - stdio: fakeStdio, - outputPreferences: OutputPreferences.test(showColor: true, wrapColumn: columnLimit), - ); - logger.printBox('This line is longer than $columnLimit characters', title: 'Test'); - final String stdout = fakeStdio.writtenToStdout.join(''); - final List<String> stdoutLines = stdout.split('\n'); - - expect(stdoutLines.length, greaterThan(1)); - expect(stdoutLines[1].length, equals(columnLimit)); - expect(stdout, - contains( - '\n' - '┌─ Test ─────┐\n' - '│ This line │\n' - '│ is longer │\n' - '│ than 14 │\n' - '│ characters │\n' - '└────────────┘\n' - ), - ); - }); - - testWithoutContext('Stdout printBox handles column limit and respects new lines', () { - const int columnLimit = 14; - final Logger logger = StdoutLogger( - terminal: AnsiTerminal( - stdio: fakeStdio, - platform: FakePlatform(), - ), - stdio: fakeStdio, - outputPreferences: OutputPreferences.test(showColor: true, wrapColumn: columnLimit), - ); - logger.printBox('This\nline is longer than\n\n$columnLimit characters', title: 'Test'); - final String stdout = fakeStdio.writtenToStdout.join(''); - final List<String> stdoutLines = stdout.split('\n'); - - expect(stdoutLines.length, greaterThan(1)); - expect(stdoutLines[1].length, equals(columnLimit)); - expect(stdout, - contains( - '\n' - '┌─ Test ─────┐\n' - '│ This │\n' - '│ line is │\n' - '│ longer │\n' - '│ than │\n' - '│ │\n' - '│ 14 │\n' - '│ characters │\n' - '└────────────┘\n' - ), - ); - }); - - testWithoutContext('Stdout printBox breaks long words that exceed the column limit', () { - const int columnLimit = 14; - final Logger logger = StdoutLogger( - terminal: AnsiTerminal( - stdio: fakeStdio, - platform: FakePlatform(), - ), - stdio: fakeStdio, - outputPreferences: OutputPreferences.test(showColor: true, wrapColumn: columnLimit), - ); - logger.printBox('Thiswordislongerthan${columnLimit}characters', title: 'Test'); - final String stdout = fakeStdio.writtenToStdout.join(''); - final List<String> stdoutLines = stdout.split('\n'); - - expect(stdoutLines.length, greaterThan(1)); - expect(stdoutLines[1].length, equals(columnLimit)); - expect(stdout, - contains( - '\n' - '┌─ Test ─────┐\n' - '│ Thiswordis │\n' - '│ longerthan │\n' - '│ 14characte │\n' - '│ rs │\n' - '└────────────┘\n' - ), - ); - }); - - testWithoutContext('Stdout startProgress on non-color terminal', () async { final FakeStopwatch fakeStopwatch = FakeStopwatch(); final Logger logger = StdoutLogger( diff --git a/packages/flutter_tools/test/general.shard/base/os_test.dart b/packages/flutter_tools/test/general.shard/base/os_test.dart index 637fd65fc69bc..3621c619c5d50 100644 --- a/packages/flutter_tools/test/general.shard/base/os_test.dart +++ b/packages/flutter_tools/test/general.shard/base/os_test.dart @@ -586,7 +586,6 @@ void main() { ), FakeCommand(command: <String>[ 'rsync', - '-8', '-av', '--delete', tempDirectory.childDirectory('dirA').path, @@ -594,7 +593,6 @@ void main() { ]), FakeCommand(command: <String>[ 'rsync', - '-8', '-av', '--delete', tempDirectory.childDirectory('dirB').path, diff --git a/packages/flutter_tools/test/general.shard/build_system/exceptions_test.dart b/packages/flutter_tools/test/general.shard/build_system/exceptions_test.dart index 0a935870e655f..52267e995a4f3 100644 --- a/packages/flutter_tools/test/general.shard/build_system/exceptions_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/exceptions_test.dart @@ -5,7 +5,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/exceptions.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/common.dart'; diff --git a/packages/flutter_tools/test/general.shard/build_system/source_test.dart b/packages/flutter_tools/test/general.shard/build_system/source_test.dart index 182a35b4f6694..fe3d0ae034d69 100644 --- a/packages/flutter_tools/test/general.shard/build_system/source_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/source_test.dart @@ -10,7 +10,7 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/exceptions.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../src/common.dart'; import '../../src/fake_process_manager.dart'; diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart index 6045862b3ff81..fe30517ece975 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart @@ -72,8 +72,7 @@ void main() { testUsingContext('DebugUniversalFramework creates simulator binary', () async { environment.defines[kIosArchs] = 'x86_64'; environment.defines[kSdkRoot] = 'path/to/iPhoneSimulator.sdk'; - final String appFrameworkPath = environment.buildDir.childDirectory('App.framework').childFile('App').path; - processManager.addCommands(<FakeCommand>[ + processManager.addCommand( FakeCommand(command: <String>[ 'xcrun', 'clang', @@ -99,17 +98,12 @@ void main() { '-isysroot', 'path/to/iPhoneSimulator.sdk', '-o', - appFrameworkPath, - ]), - FakeCommand(command: <String>[ - 'codesign', - '--force', - '--sign', - '-', - '--timestamp=none', - appFrameworkPath, + environment.buildDir + .childDirectory('App.framework') + .childFile('App') + .path, ]), - ]); + ); await const DebugUniversalFramework().build(environment); expect(processManager.hasRemainingExpectations, isFalse); @@ -122,8 +116,7 @@ void main() { testUsingContext('DebugUniversalFramework creates expected binary with arm64 only arch', () async { environment.defines[kIosArchs] = 'arm64'; environment.defines[kSdkRoot] = 'path/to/iPhoneOS.sdk'; - final String appFrameworkPath = environment.buildDir.childDirectory('App.framework').childFile('App').path; - processManager.addCommands(<FakeCommand>[ + processManager.addCommand( FakeCommand(command: <String>[ 'xcrun', 'clang', @@ -136,17 +129,12 @@ void main() { '.tmp_rand0', 'flutter_tools_stub_source.rand0', 'debug_app.cc')), ..._kSharedConfig, '-o', - appFrameworkPath, + environment.buildDir + .childDirectory('App.framework') + .childFile('App') + .path, ]), - FakeCommand(command: <String>[ - 'codesign', - '--force', - '--sign', - '-', - '--timestamp=none', - appFrameworkPath, - ]), - ]); + ); await const DebugUniversalFramework().build(environment); expect(processManager.hasRemainingExpectations, isFalse); @@ -329,7 +317,6 @@ void main() { FakeCommand lipoCommandNonFatResult; FakeCommand lipoVerifyArm64Command; FakeCommand bitcodeStripCommand; - FakeCommand adHocCodesignCommand; setUp(() { final FileSystem fileSystem = MemoryFileSystem.test(); @@ -366,15 +353,6 @@ void main() { '-o', binary.path, ]); - - adHocCodesignCommand = FakeCommand(command: <String>[ - 'codesign', - '--force', - '--sign', - '-', - '--timestamp=none', - binary.path, - ]); }); testWithoutContext('iphonesimulator', () async { @@ -411,7 +389,6 @@ void main() { '-verify_arch', 'x86_64', ]), - adHocCodesignCommand, ]); await const DebugUnpackIOS().build(environment); @@ -561,7 +538,6 @@ void main() { copyPhysicalFrameworkCommand, lipoCommandNonFatResult, lipoVerifyArm64Command, - adHocCodesignCommand, ]); await const DebugUnpackIOS().build(environment); @@ -611,7 +587,6 @@ void main() { 'armv7', binary.path, ]), - adHocCodesignCommand, ]); await const DebugUnpackIOS().build(environment); @@ -683,7 +658,6 @@ void main() { lipoCommandNonFatResult, lipoVerifyArm64Command, bitcodeStripCommand, - adHocCodesignCommand, ]); await const DebugUnpackIOS().build(environment); diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart index 0be396a79c1aa..2f9c5da8bcf8d 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart @@ -12,7 +12,7 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/depfile.dart'; import 'package:flutter_tools/src/build_system/targets/web.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../../../src/common.dart'; import '../../../src/fake_process_manager.dart'; @@ -637,7 +637,7 @@ void main() { environment.outputDir.childDirectory('a').childFile('a.txt') ..createSync(recursive: true) ..writeAsStringSync('A'); - await WebServiceWorker(globals.fs, globals.cache).build(environment); + await WebServiceWorker(globals.fs).build(environment); expect(environment.outputDir.childFile('flutter_service_worker.js'), exists); // Contains file hash. @@ -656,7 +656,7 @@ void main() { environment.outputDir .childFile('index.html') .createSync(recursive: true); - await WebServiceWorker(globals.fs, globals.cache).build(environment); + await WebServiceWorker(globals.fs).build(environment); expect(environment.outputDir.childFile('flutter_service_worker.js'), exists); // Contains file hash for both `/` and index.html. @@ -674,7 +674,7 @@ void main() { environment.outputDir .childFile('main.dart.js.map') .createSync(recursive: true); - await WebServiceWorker(globals.fs, globals.cache).build(environment); + await WebServiceWorker(globals.fs).build(environment); // No caching of source maps. expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(), diff --git a/packages/flutter_tools/test/general.shard/bundle_builder_test.dart b/packages/flutter_tools/test/general.shard/bundle_builder_test.dart index 8c5f949b7e15c..56ae76055bcc1 100644 --- a/packages/flutter_tools/test/general.shard/bundle_builder_test.dart +++ b/packages/flutter_tools/test/general.shard/bundle_builder_test.dart @@ -11,7 +11,7 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/bundle.dart'; import 'package:flutter_tools/src/bundle_builder.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import '../src/common.dart'; diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index 849d939865888..22ed53b9a33ab 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -16,7 +16,7 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/flutter_cache.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:meta/meta.dart'; import 'package:test/fake.dart'; @@ -137,7 +137,7 @@ void main() { final FakeSimpleArtifact artifact = FakeSimpleArtifact(cache); await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils()); - expect(logger.warningText, contains('stamp write failed')); + expect(logger.errorText, contains('stamp write failed')); }); testWithoutContext('Continues on missing version file', () async { @@ -153,7 +153,7 @@ void main() { final FakeSimpleArtifact artifact = FakeSimpleArtifact(cache); await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils()); - expect(logger.warningText, contains('No known version for the artifact name "fake"')); + expect(logger.errorText, contains('No known version for the artifact name "fake"')); }); testWithoutContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () { @@ -725,7 +725,7 @@ void main() { cache.clearStampFiles(); - expect(logger.warningText, contains('Failed to delete some stamp files')); + expect(logger.errorText, contains('Failed to delete some stamp files')); }); testWithoutContext('FlutterWebSdk fetches web artifacts and deletes previous directory contents', () async { @@ -943,12 +943,6 @@ void main() { expect(pub.calledGet, 1); }); - testUsingContext('Check current DevTools version', () async { - final String currentDevToolsVersion = globals.cache.devToolsVersion; - final RegExp devToolsVersionFormat = RegExp(r'\d+\.\d+\.\d+(?:-\S+)?'); - expect(devToolsVersionFormat.allMatches(currentDevToolsVersion).length, 1,); - }); - // Check that the build number matches the format documented here: // https://dart.dev/get-dart#release-channels testUsingContext('Check current Dart SDK build number', () async { @@ -978,23 +972,18 @@ void main() { }); testUsingContext('AndroidMavenArtifacts can invoke Gradle resolve dependencies if Android SDK is present', () async { - final String oldRoot = Cache.flutterRoot; Cache.flutterRoot = ''; - try { - final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(cache, platform: FakePlatform()); - expect(await mavenArtifacts.isUpToDate(memoryFileSystem), isFalse); + final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(cache, platform: FakePlatform()); + expect(await mavenArtifacts.isUpToDate(memoryFileSystem), isFalse); - final Directory gradleWrapperDir = cache.getArtifactDirectory('gradle_wrapper')..createSync(recursive: true); - gradleWrapperDir.childFile('gradlew').writeAsStringSync('irrelevant'); - gradleWrapperDir.childFile('gradlew.bat').writeAsStringSync('irrelevant'); + final Directory gradleWrapperDir = cache.getArtifactDirectory('gradle_wrapper')..createSync(recursive: true); + gradleWrapperDir.childFile('gradlew').writeAsStringSync('irrelevant'); + gradleWrapperDir.childFile('gradlew.bat').writeAsStringSync('irrelevant'); - await mavenArtifacts.update(FakeArtifactUpdater(), BufferLogger.test(), memoryFileSystem, FakeOperatingSystemUtils()); + await mavenArtifacts.update(FakeArtifactUpdater(), BufferLogger.test(), memoryFileSystem, FakeOperatingSystemUtils()); - expect(await mavenArtifacts.isUpToDate(memoryFileSystem), isFalse); - expect(fakeAndroidSdk.reinitialized, true); - } finally { - Cache.flutterRoot = oldRoot; - } + expect(await mavenArtifacts.isUpToDate(memoryFileSystem), isFalse); + expect(fakeAndroidSdk.reinitialized, true); }, overrides: <Type, Generator>{ Cache: () => cache, FileSystem: () => memoryFileSystem, @@ -1120,7 +1109,7 @@ class FakeSecondaryCache extends Fake implements Cache { Directory getArtifactDirectory(String name) => artifactDirectory; @override - Directory getCacheDir(String name, { bool shouldCreate = true }) { + Directory getCacheDir(String name) { return artifactDirectory.childDirectory(name); } diff --git a/packages/flutter_tools/test/general.shard/channel_test.dart b/packages/flutter_tools/test/general.shard/channel_test.dart index 33d05521e4fe5..d5cdbedd2532e 100644 --- a/packages/flutter_tools/test/general.shard/channel_test.dart +++ b/packages/flutter_tools/test/general.shard/channel_test.dart @@ -15,7 +15,7 @@ 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/channel.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/version.dart'; import '../src/common.dart'; diff --git a/packages/flutter_tools/test/general.shard/commands/analyze_base_test.dart b/packages/flutter_tools/test/general.shard/commands/analyze_base_test.dart index 36cf3c94698e1..6a7d5a4707258 100644 --- a/packages/flutter_tools/test/general.shard/commands/analyze_base_test.dart +++ b/packages/flutter_tools/test/general.shard/commands/analyze_base_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:flutter_tools/src/commands/analyze_base.dart'; import '../../src/common.dart'; 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 b912556068986..17e661aafe4d6 100644 --- a/packages/flutter_tools/test/general.shard/commands/build_test.dart +++ b/packages/flutter_tools/test/general.shard/commands/build_test.dart @@ -19,7 +19,7 @@ import 'package:flutter_tools/src/commands/build_linux.dart'; import 'package:flutter_tools/src/commands/build_macos.dart'; import 'package:flutter_tools/src/commands/build_web.dart'; import 'package:flutter_tools/src/commands/build_windows.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/runner/flutter_command.dart'; import '../../src/common.dart'; @@ -83,8 +83,6 @@ void main() { } class FakeBuildSubCommand extends BuildSubCommand { - FakeBuildSubCommand() : super(verboseHelp: false); - @override String get description => throw UnimplementedError(); diff --git a/packages/flutter_tools/test/general.shard/compile_test.dart b/packages/flutter_tools/test/general.shard/compile_test.dart index 72cd902baa000..cd2dbef44f615 100644 --- a/packages/flutter_tools/test/general.shard/compile_test.dart +++ b/packages/flutter_tools/test/general.shard/compile_test.dart @@ -88,17 +88,4 @@ void main() { '--enable-asserts', ]); }); - - testWithoutContext('buildModeOptions removes matching profile define', () { - expect(buildModeOptions(BuildMode.debug, <String>['dart.vm.profile=true']), <String>[ - '-Ddart.vm.product=false', - '--enable-asserts', - ]); - }); - - testWithoutContext('buildModeOptions removes both matching profile and release define', () { - expect(buildModeOptions(BuildMode.debug, <String>['dart.vm.profile=true', 'dart.vm.product=true']), <String>[ - '--enable-asserts', - ]); - }); } diff --git a/packages/flutter_tools/test/general.shard/crash_reporting_test.dart b/packages/flutter_tools/test/general.shard/crash_reporting_test.dart index 93f596fa12d64..d0c893be219be 100644 --- a/packages/flutter_tools/test/general.shard/crash_reporting_test.dart +++ b/packages/flutter_tools/test/general.shard/crash_reporting_test.dart @@ -10,13 +10,11 @@ import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/platform.dart'; -import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/crash_reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:http/http.dart'; import 'package:http/testing.dart'; -import 'package:test/fake.dart'; import '../src/common.dart'; import '../src/fake_http_client.dart'; @@ -78,7 +76,7 @@ void main() { expect(logger.traceText, contains('Crash report sent (report ID: test-report-id)')); } - testWithoutContext('CrashReporter.informUser provides basic instructions without PII', () async { + testWithoutContext('CrashReporter.informUser provides basic instructions', () async { final CrashReporter crashReporter = CrashReporter( fileSystem: fs, logger: logger, @@ -93,16 +91,12 @@ void main() { command: 'arg1 arg2 arg3', error: Exception('Dummy exception'), stackTrace: StackTrace.current, - // Spaces are URL query encoded in the output, make it one word to make this test simpler. - doctorText: FakeDoctorText('Ignored', 'NoPIIFakeDoctorText'), - ), + doctorText: 'Fake doctor text'), file, ); - expect(logger.statusText, contains('NoPIIFakeDoctorText')); - expect(logger.statusText, isNot(contains('Ignored'))); - expect(logger.statusText, contains('https://github.com/flutter/flutter/issues/new')); expect(logger.errorText, contains('A crash report has been written to ${file.path}.')); + expect(logger.statusText, contains('https://github.com/flutter/flutter/issues/new')); }); testWithoutContext('suppress analytics', () async { @@ -385,16 +379,3 @@ class CrashingCrashReportSender extends MockClient { throw exception; }); } - -class FakeDoctorText extends Fake implements DoctorText { - FakeDoctorText(String text, String piiStrippedText) - : _text = text, _piiStrippedText = piiStrippedText; - - @override - Future<String> get text async => _text; - final String _text; - - @override - Future<String> get piiStrippedText async => _piiStrippedText; - final String _piiStrippedText; -} diff --git a/packages/flutter_tools/test/general.shard/custom_devices/custom_device_test.dart b/packages/flutter_tools/test/general.shard/custom_devices/custom_device_test.dart index 068190de52894..f1b8683bffa57 100644 --- a/packages/flutter_tools/test/general.shard/custom_devices/custom_device_test.dart +++ b/packages/flutter_tools/test/general.shard/custom_devices/custom_device_test.dart @@ -19,7 +19,7 @@ import 'package:flutter_tools/src/custom_devices/custom_device.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/device.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/linux/application_package.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:meta/meta.dart'; @@ -391,7 +391,7 @@ void main() { processManager: processManager, ); - final LaunchResult launchResult = await appSession.start(debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug)); + final LaunchResult launchResult = await appSession.start(); expect(launchResult.started, true); expect(launchResult.observatoryUri, Uri.parse('http://127.0.0.1:12345/abcd/')); @@ -428,7 +428,7 @@ void main() { processManager: processManager ); - final LaunchResult launchResult = await appSession.start(debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug)); + final LaunchResult launchResult = await appSession.start(); expect(launchResult.started, true); expect(launchResult.observatoryUri, Uri.parse('http://192.168.178.123:12345/abcd/')); @@ -587,54 +587,6 @@ void main() { expect(await device.targetPlatform, TargetPlatform.linux_x64); }); - - testWithoutContext('CustomDeviceLogReader cancels subscriptions before closing logLines stream', () async { - final CustomDeviceLogReader logReader = CustomDeviceLogReader('testname'); - - final Iterable<List<int>> lines = Iterable<List<int>>.generate(5, (int _) => utf8.encode('test')); - - logReader.listenToProcessOutput( - FakeProcess( - exitCode: Future<int>.value(0), - stdout: Stream<List<int>>.fromIterable(lines), - stderr: Stream<List<int>>.fromIterable(lines), - ), - ); - - final List<MyFakeStreamSubscription<String>> subscriptions = <MyFakeStreamSubscription<String>>[]; - bool logLinesStreamDone = false; - logReader.logLines.listen((_) {}, onDone: () { - expect(subscriptions, everyElement((MyFakeStreamSubscription<String> s) => s.canceled)); - logLinesStreamDone = true; - }); - - logReader.subscriptions.replaceRange( - 0, - logReader.subscriptions.length, - logReader.subscriptions.map( - (StreamSubscription<String> e) => MyFakeStreamSubscription<String>(e) - ), - ); - - subscriptions.addAll(logReader.subscriptions.cast()); - - await logReader.dispose(); - - expect(logLinesStreamDone, true); - }); -} - -class MyFakeStreamSubscription<T> extends Fake implements StreamSubscription<T> { - MyFakeStreamSubscription(this.parent); - - StreamSubscription<T> parent; - bool canceled = false; - - @override - Future<void> cancel() { - canceled = true; - return parent.cancel(); - } } class FakeBundleBuilder extends Fake implements BundleBuilder { diff --git a/packages/flutter_tools/test/general.shard/daemon_test.dart b/packages/flutter_tools/test/general.shard/daemon_test.dart deleted file mode 100644 index fb2d9954d3571..0000000000000 --- a/packages/flutter_tools/test/general.shard/daemon_test.dart +++ /dev/null @@ -1,240 +0,0 @@ -// 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:async'; -import 'dart:typed_data'; - -import 'package:flutter_tools/src/base/common.dart'; -import 'package:flutter_tools/src/base/io.dart'; -import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/convert.dart'; -import 'package:flutter_tools/src/daemon.dart'; -import 'package:test/fake.dart'; - -import '../src/common.dart'; - -class FakeDaemonStreams extends DaemonStreams { - final StreamController<Map<String, dynamic>> inputs = StreamController<Map<String, dynamic>>(); - final StreamController<Map<String, dynamic>> outputs = StreamController<Map<String, dynamic>>(); - - @override - Stream<Map<String, dynamic>> get inputStream { - return inputs.stream; - } - - @override - void send(Map<String, dynamic> message) { - outputs.add(message); - } - - @override - Future<void> dispose() async { - await inputs.close(); - // In some tests, outputs have no listeners. We don't wait for outputs to close. - unawaited(outputs.close()); - } -} - -void main() { - late BufferLogger bufferLogger; - late FakeDaemonStreams daemonStreams; - late DaemonConnection daemonConnection; - setUp(() { - bufferLogger = BufferLogger.test(); - daemonStreams = FakeDaemonStreams(); - daemonConnection = DaemonConnection( - daemonStreams: daemonStreams, - logger: bufferLogger, - ); - }); - - tearDown(() async { - await daemonConnection.dispose(); - }); - - group('DaemonConnection receiving end', () { - testWithoutContext('redirects input to incoming commands', () async { - final Map<String, dynamic> commandToSend = <String, dynamic>{'id': 0, 'method': 'some_method'}; - daemonStreams.inputs.add(commandToSend); - - final Map<String, dynamic> commandReceived = await daemonConnection.incomingCommands.first; - await daemonStreams.dispose(); - - expect(commandReceived, commandToSend); - }); - - testWithoutContext('listenToEvent can receive the right events', () async { - final Future<List<dynamic>> events = daemonConnection.listenToEvent('event1').toList(); - - daemonStreams.inputs.add(<String, dynamic>{'event': 'event1', 'params': '1'}); - daemonStreams.inputs.add(<String, dynamic>{'event': 'event2', 'params': '2'}); - daemonStreams.inputs.add(<String, dynamic>{'event': 'event1', 'params': null}); - daemonStreams.inputs.add(<String, dynamic>{'event': 'event1', 'params': 3}); - - await pumpEventQueue(); - await daemonConnection.dispose(); - - expect(await events, <dynamic>['1', null, 3]); - }); - }); - - group('DaemonConnection sending end', () { - testWithoutContext('sending requests', () async { - unawaited(daemonConnection.sendRequest('some_method', 'param')); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - expect(data['id'], isNotNull); - expect(data['method'], 'some_method'); - expect(data['params'], 'param'); - }); - - testWithoutContext('sending requests without param', () async { - unawaited(daemonConnection.sendRequest('some_method')); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - expect(data['id'], isNotNull); - expect(data['method'], 'some_method'); - expect(data['params'], isNull); - }); - - testWithoutContext('sending response', () async { - daemonConnection.sendResponse('1', 'some_data'); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - expect(data['id'], '1'); - expect(data['method'], isNull); - expect(data['error'], isNull); - expect(data['result'], 'some_data'); - }); - - testWithoutContext('sending response without data', () async { - daemonConnection.sendResponse('1'); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - expect(data['id'], '1'); - expect(data['method'], isNull); - expect(data['error'], isNull); - expect(data['result'], isNull); - }); - - testWithoutContext('sending error response', () async { - daemonConnection.sendErrorResponse('1', 'error', StackTrace.fromString('stack trace')); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - expect(data['id'], '1'); - expect(data['method'], isNull); - expect(data['error'], 'error'); - expect(data['trace'], 'stack trace'); - }); - - testWithoutContext('sending events', () async { - daemonConnection.sendEvent('some_event', '123'); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - expect(data['id'], isNull); - expect(data['event'], 'some_event'); - expect(data['params'], '123'); - }); - - testWithoutContext('sending events without params', () async { - daemonConnection.sendEvent('some_event'); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - expect(data['id'], isNull); - expect(data['event'], 'some_event'); - expect(data['params'], isNull); - }); - }); - - group('DaemonConnection request and response', () { - testWithoutContext('receiving response from requests', () async { - final Future<dynamic> requestFuture = daemonConnection.sendRequest('some_method', 'param'); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - - expect(data['id'], isNotNull); - expect(data['method'], 'some_method'); - expect(data['params'], 'param'); - - final String id = data['id'] as String; - daemonStreams.inputs.add(<String, dynamic>{'id': id, 'result': '123'}); - expect(await requestFuture, '123'); - }); - - testWithoutContext('receiving response from requests without result', () async { - final Future<dynamic> requestFuture = daemonConnection.sendRequest('some_method', 'param'); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - - expect(data['id'], isNotNull); - expect(data['method'], 'some_method'); - expect(data['params'], 'param'); - - final String id = data['id'] as String; - daemonStreams.inputs.add(<String, dynamic>{'id': id}); - expect(await requestFuture, null); - }); - - testWithoutContext('receiving error response from requests without result', () async { - final Future<dynamic> requestFuture = daemonConnection.sendRequest('some_method', 'param'); - final Map<String, dynamic> data = await daemonStreams.outputs.stream.first; - - expect(data['id'], isNotNull); - expect(data['method'], 'some_method'); - expect(data['params'], 'param'); - - final String id = data['id'] as String; - daemonStreams.inputs.add(<String, dynamic>{'id': id, 'error': 'some_error', 'trace': 'stack trace'}); - expect(requestFuture, throwsA('some_error')); - }); - }); - - group('TcpDaemonStreams', () { - final Map<String, Object?> testCommand = <String, Object?>{ - 'id': 100, - 'method': 'test', - }; - late FakeSocket socket; - late TcpDaemonStreams daemonStreams; - setUp(() { - socket = FakeSocket(); - daemonStreams = TcpDaemonStreams(socket, logger: bufferLogger); - }); - - test('parses the message received on the socket', () async { - socket.controller.add(Uint8List.fromList(utf8.encode('[${jsonEncode(testCommand)}]\n'))); - final Map<String, Object?> command = await daemonStreams.inputStream.first; - expect(command, testCommand); - }); - - test('sends the encoded message through the socket', () async { - daemonStreams.send(testCommand); - await pumpEventQueue(); - expect(socket.writtenObjects.length, 1); - expect(socket.writtenObjects[0].toString(), '[${jsonEncode(testCommand)}]\n'); - }); - - test('dispose calls socket.close', () async { - await daemonStreams.dispose(); - expect(socket.closeCalled, isTrue); - }); - }); -} - -class FakeSocket extends Fake implements Socket { - bool closeCalled = false; - final StreamController<Uint8List> controller = StreamController<Uint8List>(); - final List<Object?> writtenObjects = <Object?>[]; - - @override - StreamSubscription<Uint8List> listen( - void Function(Uint8List event)? onData, { - Function? onError, - void Function()? onDone, - bool? cancelOnError, - }) { - return controller.stream.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError); - } - - @override - void write(Object? object) { - writtenObjects.add(object); - } - - @override - Future<void> close() async { - closeCalled = true; - } -} diff --git a/packages/flutter_tools/test/general.shard/dart_plugin_test.dart b/packages/flutter_tools/test/general.shard/dart_plugin_test.dart index 7d9d82f49e68d..7485a606fe06f 100644 --- a/packages/flutter_tools/test/general.shard/dart_plugin_test.dart +++ b/packages/flutter_tools/test/general.shard/dart_plugin_test.dart @@ -9,7 +9,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/dart/package_map.dart'; import 'package:flutter_tools/src/flutter_manifest.dart'; import 'package:flutter_tools/src/flutter_plugins.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/plugins.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:package_config/package_config.dart'; diff --git a/packages/flutter_tools/test/general.shard/desktop_device_test.dart b/packages/flutter_tools/test/general.shard/desktop_device_test.dart index c99b65059205a..c99bd6166b966 100644 --- a/packages/flutter_tools/test/general.shard/desktop_device_test.dart +++ b/packages/flutter_tools/test/general.shard/desktop_device_test.dart @@ -144,25 +144,26 @@ void main() { completer: completer, environment: const <String, String>{ 'FLUTTER_ENGINE_SWITCH_1': 'enable-dart-profiling=true', - 'FLUTTER_ENGINE_SWITCH_2': 'trace-startup=true', - 'FLUTTER_ENGINE_SWITCH_3': 'enable-software-rendering=true', - 'FLUTTER_ENGINE_SWITCH_4': 'skia-deterministic-rendering=true', - 'FLUTTER_ENGINE_SWITCH_5': 'trace-skia=true', - 'FLUTTER_ENGINE_SWITCH_6': 'trace-allowlist=foo,bar', - 'FLUTTER_ENGINE_SWITCH_7': 'trace-skia-allowlist=skia.a,skia.b', - 'FLUTTER_ENGINE_SWITCH_8': 'trace-systrace=true', - 'FLUTTER_ENGINE_SWITCH_9': 'endless-trace-buffer=true', - 'FLUTTER_ENGINE_SWITCH_10': 'dump-skp-on-shader-compilation=true', - 'FLUTTER_ENGINE_SWITCH_11': 'cache-sksl=true', - 'FLUTTER_ENGINE_SWITCH_12': 'purge-persistent-cache=true', - 'FLUTTER_ENGINE_SWITCH_13': 'enable-checked-mode=true', - 'FLUTTER_ENGINE_SWITCH_14': 'verify-entry-points=true', - 'FLUTTER_ENGINE_SWITCH_15': 'start-paused=true', - 'FLUTTER_ENGINE_SWITCH_16': 'disable-service-auth-codes=true', - 'FLUTTER_ENGINE_SWITCH_17': 'dart-flags=--null_assertions', - 'FLUTTER_ENGINE_SWITCH_18': 'use-test-fonts=true', - 'FLUTTER_ENGINE_SWITCH_19': 'verbose-logging=true', - 'FLUTTER_ENGINE_SWITCHES': '19' + 'FLUTTER_ENGINE_SWITCH_2': 'enable-background-compilation=true', + 'FLUTTER_ENGINE_SWITCH_3': 'trace-startup=true', + 'FLUTTER_ENGINE_SWITCH_4': 'enable-software-rendering=true', + 'FLUTTER_ENGINE_SWITCH_5': 'skia-deterministic-rendering=true', + 'FLUTTER_ENGINE_SWITCH_6': 'trace-skia=true', + 'FLUTTER_ENGINE_SWITCH_7': 'trace-allowlist=foo,bar', + 'FLUTTER_ENGINE_SWITCH_8': 'trace-skia-allowlist=skia.a,skia.b', + 'FLUTTER_ENGINE_SWITCH_9': 'trace-systrace=true', + 'FLUTTER_ENGINE_SWITCH_10': 'endless-trace-buffer=true', + 'FLUTTER_ENGINE_SWITCH_11': 'dump-skp-on-shader-compilation=true', + 'FLUTTER_ENGINE_SWITCH_12': 'cache-sksl=true', + 'FLUTTER_ENGINE_SWITCH_13': 'purge-persistent-cache=true', + 'FLUTTER_ENGINE_SWITCH_14': 'enable-checked-mode=true', + 'FLUTTER_ENGINE_SWITCH_15': 'verify-entry-points=true', + 'FLUTTER_ENGINE_SWITCH_16': 'start-paused=true', + 'FLUTTER_ENGINE_SWITCH_17': 'disable-service-auth-codes=true', + 'FLUTTER_ENGINE_SWITCH_18': 'dart-flags=--null_assertions', + 'FLUTTER_ENGINE_SWITCH_19': 'use-test-fonts=true', + 'FLUTTER_ENGINE_SWITCH_20': 'verbose-logging=true', + 'FLUTTER_ENGINE_SWITCHES': '20' } ), ]); @@ -206,10 +207,11 @@ void main() { completer: completer, environment: const <String, String>{ 'FLUTTER_ENGINE_SWITCH_1': 'enable-dart-profiling=true', - 'FLUTTER_ENGINE_SWITCH_2': 'trace-startup=true', - 'FLUTTER_ENGINE_SWITCH_3': 'trace-allowlist=foo,bar', - 'FLUTTER_ENGINE_SWITCH_4': 'cache-sksl=true', - 'FLUTTER_ENGINE_SWITCHES': '4' + 'FLUTTER_ENGINE_SWITCH_2': 'enable-background-compilation=true', + 'FLUTTER_ENGINE_SWITCH_3': 'trace-startup=true', + 'FLUTTER_ENGINE_SWITCH_4': 'trace-allowlist=foo,bar', + 'FLUTTER_ENGINE_SWITCH_5': 'cache-sksl=true', + 'FLUTTER_ENGINE_SWITCHES': '5' } ), ]); diff --git a/packages/flutter_tools/test/general.shard/devfs_test.dart b/packages/flutter_tools/test/general.shard/devfs_test.dart index a5bb75504af56..ddc38be05df53 100644 --- a/packages/flutter_tools/test/general.shard/devfs_test.dart +++ b/packages/flutter_tools/test/general.shard/devfs_test.dart @@ -6,20 +6,15 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io' as io show ProcessSignal, Process; import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; -import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/platform.dart'; -import 'package:flutter_tools/src/base/terminal.dart'; -import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/vmservice.dart'; @@ -475,109 +470,6 @@ void main() { expect(report.compileDuration, const Duration(seconds: 3)); expect(report.transferDuration, const Duration(seconds: 5)); }); - - - testUsingContext('DevFS actually starts compile before processing bundle', () async { - final FileSystem fileSystem = MemoryFileSystem.test(); - final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost( - requests: <VmServiceExpectation>[createDevFSRequest], - httpAddress: Uri.parse('http://localhost'), - ); - - final LoggingLogger logger = LoggingLogger(); - - final DevFS devFS = DevFS( - fakeVmServiceHost.vmService, - 'test', - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: logger, - osUtils: FakeOperatingSystemUtils(), - httpClient: FakeHttpClient.any(), - ); - - await devFS.create(); - - final MemoryIOSink frontendServerStdIn = MemoryIOSink(); - Stream<List<int>> frontendServerStdOut() async* { - int processed = 0; - while(true) { - while(frontendServerStdIn.writes.length == processed) { - await Future<dynamic>.delayed(const Duration(milliseconds: 5)); - } - - String boundaryKey; - while(processed < frontendServerStdIn.writes.length) { - final List<int> data = frontendServerStdIn.writes[processed]; - final String stringData = utf8.decode(data); - if (stringData.startsWith('compile ')) { - yield utf8.encode('result abc1\nline1\nline2\nabc1\nabc1 lib/foo.txt.dill 0\n'); - } else if (stringData.startsWith('recompile ')) { - final String line = stringData.split('\n').first; - final int spaceDelim = line.lastIndexOf(' '); - boundaryKey = line.substring(spaceDelim + 1); - } else if (boundaryKey != null && stringData.startsWith(boundaryKey)) { - yield utf8.encode('result abc2\nline1\nline2\nabc2\nabc2 lib/foo.txt.dill 0\n'); - } else { - throw 'Saw $data ($stringData)'; - } - processed++; - } - } - } - Stream<List<int>> frontendServerStdErr() async* { - // Output nothing on stderr. - } - - final AnsweringFakeProcessManager fakeProcessManager = AnsweringFakeProcessManager(frontendServerStdOut(), frontendServerStdErr(), frontendServerStdIn); - final StdoutHandler generatorStdoutHandler = StdoutHandler(logger: testLogger, fileSystem: fileSystem); - - final DefaultResidentCompiler residentCompiler = DefaultResidentCompiler( - 'sdkroot', - buildMode: BuildMode.debug, - logger: logger, - processManager: fakeProcessManager, - artifacts: Artifacts.test(), - platform: FakePlatform(), - fileSystem: fileSystem, - stdoutHandler: generatorStdoutHandler, - ); - - fileSystem.file('lib/foo.txt.dill').createSync(recursive: true); - - final UpdateFSReport report1 = await devFS.update( - mainUri: Uri.parse('lib/main.dart'), - generator: residentCompiler, - dillOutputPath: 'lib/foo.dill', - pathToReload: 'lib/foo.txt.dill', - trackWidgetCreation: false, - invalidatedFiles: <Uri>[], - packageConfig: PackageConfig.empty, - bundle: FakeBundle(), - ); - expect(report1.success, true); - logger.messages.clear(); - - final UpdateFSReport report2 = await devFS.update( - mainUri: Uri.parse('lib/main.dart'), - generator: residentCompiler, - dillOutputPath: 'lib/foo.dill', - pathToReload: 'lib/foo.txt.dill', - trackWidgetCreation: false, - invalidatedFiles: <Uri>[], - packageConfig: PackageConfig.empty, - bundle: FakeBundle(), - ); - expect(report2.success, true); - - final int processingBundleIndex = logger.messages.indexOf('Processing bundle.'); - final int bundleProcessingDoneIndex = logger.messages.indexOf('Bundle processing done.'); - final int compileLibMainIndex = logger.messages.indexWhere((String element) => element.startsWith('<- recompile lib/main.dart ')); - expect(processingBundleIndex, greaterThanOrEqualTo(0)); - expect(bundleProcessingDoneIndex, greaterThanOrEqualTo(0)); - expect(compileLibMainIndex, greaterThanOrEqualTo(0)); - expect(bundleProcessingDoneIndex, greaterThan(compileLibMainIndex)); - }); } class FakeResidentCompiler extends Fake implements ResidentCompiler { @@ -598,108 +490,3 @@ class FakeDevFSWriter implements DevFSWriter { written = true; } } - -class LoggingLogger extends BufferLogger { - LoggingLogger() : super.test(); - - List<String> messages = <String>[]; - - @override - void printError(String message, {StackTrace stackTrace, bool emphasis, TerminalColor color, int indent, int hangingIndent, bool wrap}) { - messages.add(message); - } - - @override - void printStatus(String message, {bool emphasis, TerminalColor color, bool newline, int indent, int hangingIndent, bool wrap}) { - messages.add(message); - } - - @override - void printTrace(String message) { - messages.add(message); - } -} - -class FakeBundle extends AssetBundle { - @override - List<File> get additionalDependencies => <File>[]; - - @override - Future<int> build({String manifestPath = defaultManifestPath, String assetDirPath, String packagesPath, bool deferredComponentsEnabled = false, TargetPlatform targetPlatform}) async { - return 0; - } - - @override - Map<String, Map<String, DevFSContent>> get deferredComponentsEntries => <String, Map<String, DevFSContent>>{}; - - @override - Map<String, DevFSContent> get entries => <String, DevFSContent>{}; - - @override - List<File> get inputFiles => <File>[]; - - @override - bool needsBuild({String manifestPath = defaultManifestPath}) { - return true; - } - - @override - bool wasBuiltOnce() { - return false; - } -} - -class AnsweringFakeProcessManager implements ProcessManager { - AnsweringFakeProcessManager(this.stdout, this.stderr, this.stdin); - - final Stream<List<int>> stdout; - final Stream<List<int>> stderr; - final IOSink stdin; - - @override - bool canRun(dynamic executable, {String workingDirectory}) { - return true; - } - - @override - bool killPid(int pid, [io.ProcessSignal signal = io.ProcessSignal.sigterm]) { - return true; - } - - @override - Future<ProcessResult> run(List<Object> command, {String workingDirectory, Map<String, String> environment, bool includeParentEnvironment = true, bool runInShell = false, Encoding stdoutEncoding = systemEncoding, Encoding stderrEncoding = systemEncoding}) async { - throw UnimplementedError(); - } - - @override - ProcessResult runSync(List<Object> command, {String workingDirectory, Map<String, String> environment, bool includeParentEnvironment = true, bool runInShell = false, Encoding stdoutEncoding = systemEncoding, Encoding stderrEncoding = systemEncoding}) { - throw UnimplementedError(); - } - - @override - Future<Process> start(List<Object> command, {String workingDirectory, Map<String, String> environment, bool includeParentEnvironment = true, bool runInShell = false, ProcessStartMode mode = ProcessStartMode.normal}) async { - return AnsweringFakeProcess(stdout, stderr, stdin); - } -} - -class AnsweringFakeProcess implements io.Process { - AnsweringFakeProcess(this.stdout,this.stderr, this.stdin); - - @override - final Stream<List<int>> stdout; - @override - final Stream<List<int>> stderr; - @override - final IOSink stdin; - - @override - Future<int> get exitCode async => 0; - - @override - bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) { - return true; - } - - @override - int get pid => 42; -} diff --git a/packages/flutter_tools/test/general.shard/emulator_test.dart b/packages/flutter_tools/test/general.shard/emulator_test.dart index d8ab35ef4bba3..d2aaa6989b3da 100644 --- a/packages/flutter_tools/test/general.shard/emulator_test.dart +++ b/packages/flutter_tools/test/general.shard/emulator_test.dart @@ -97,6 +97,7 @@ void main() { stdout: 'existing-avd-1', ), ]), + androidSdk: null, androidWorkflow: AndroidWorkflow( androidSdk: sdk, featureFlags: TestFeatureFlags(), diff --git a/packages/flutter_tools/test/general.shard/flutter_validator_test.dart b/packages/flutter_tools/test/general.shard/flutter_validator_test.dart index fa8db110cc471..05abf80a10dff 100644 --- a/packages/flutter_tools/test/general.shard/flutter_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_validator_test.dart @@ -44,7 +44,6 @@ void main() { environment: <String, String>{}, ), flutterVersion: () => flutterVersion, - devToolsVersion: () => '2.8.0', userMessages: UserMessages(), artifacts: artifacts, fileSystem: fileSystem, @@ -86,7 +85,6 @@ void main() { environment: <String, String>{}, ), flutterVersion: () => flutterVersion, - devToolsVersion: () => '2.8.0', userMessages: UserMessages(), artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), @@ -108,7 +106,6 @@ void main() { final FlutterValidator flutterValidator = FlutterValidator( platform: FakePlatform(operatingSystem: 'windows', localeName: 'en_US.UTF-8'), flutterVersion: () => FakeThrowingFlutterVersion(), - devToolsVersion: () => '2.8.0', userMessages: UserMessages(), artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), @@ -144,7 +141,6 @@ void main() { final FlutterValidator flutterValidator = FlutterValidator( platform: platform, flutterVersion: () => flutterVersion, - devToolsVersion: () => '2.8.0', userMessages: UserMessages(), artifacts: artifacts, fileSystem: fileSystem, @@ -172,7 +168,6 @@ void main() { }, ), flutterVersion: () => FakeFlutterVersion(frameworkVersion: '1.0.0'), - devToolsVersion: () => '2.8.0', userMessages: UserMessages(), artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), @@ -193,7 +188,6 @@ void main() { final FlutterValidator flutterValidator = FlutterValidator( platform: FakePlatform(localeName: 'en_US.UTF-8'), flutterVersion: () => FakeFlutterVersion(frameworkVersion: '1.0.0'), - devToolsVersion: () => '2.8.0', userMessages: UserMessages(), artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), @@ -216,7 +210,6 @@ void main() { frameworkVersion: '1.0.0', repositoryUrl: null, ), - devToolsVersion: () => '2.8.0', userMessages: UserMessages(), artifacts: Artifacts.test(), fileSystem: MemoryFileSystem.test(), diff --git a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_start_test.dart b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_start_test.dart index a395ab2aa2b7e..b5907217543b8 100644 --- a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_start_test.dart +++ b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_start_test.dart @@ -25,7 +25,7 @@ import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart'; import 'package:flutter_tools/src/fuchsia/pkgctl.dart'; import 'package:flutter_tools/src/fuchsia/session_control.dart'; import 'package:flutter_tools/src/fuchsia/tiles_ctl.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:meta/meta.dart'; import 'package:test/fake.dart'; diff --git a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart index caf979c3dc40a..31997d73e20db 100644 --- a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart +++ b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart @@ -25,7 +25,7 @@ import 'package:flutter_tools/src/fuchsia/fuchsia_kernel_compiler.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_pm.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/vmservice.dart'; import 'package:meta/meta.dart'; @@ -91,7 +91,7 @@ void main() { final FakeFuchsiaWorkflow fuchsiaWorkflow = FakeFuchsiaWorkflow(canListDevices: false); final FuchsiaDevices fuchsiaDevices = FuchsiaDevices( platform: FakePlatform(), - fuchsiaSdk: FakeFuchsiaSdk(devices: 'ignored'), + fuchsiaSdk: null, fuchsiaWorkflow: fuchsiaWorkflow, logger: BufferLogger.test(), ); @@ -154,7 +154,7 @@ void main() { testUsingContext('disposing device disposes the portForwarder', () async { final FakePortForwarder portForwarder = FakePortForwarder(); - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); device.portForwarder = portForwarder; await device.dispose(); @@ -162,7 +162,7 @@ void main() { }); testWithoutContext('default capabilities', () async { - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); final FlutterProject project = FlutterProject.fromDirectoryTest(memoryFileSystem.currentDirectory); memoryFileSystem.directory('fuchsia').createSync(recursive: true); memoryFileSystem.file('pubspec.yaml').createSync(); @@ -174,13 +174,13 @@ void main() { }); test('is ephemeral', () { - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); expect(device.ephemeral, true); }); testWithoutContext('supported for project', () async { - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); final FlutterProject project = FlutterProject.fromDirectoryTest(memoryFileSystem.currentDirectory); memoryFileSystem.directory('fuchsia').createSync(recursive: true); memoryFileSystem.file('pubspec.yaml').createSync(); @@ -189,7 +189,7 @@ void main() { }); testWithoutContext('not supported for project', () async { - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); final FlutterProject project = FlutterProject.fromDirectoryTest(memoryFileSystem.currentDirectory); memoryFileSystem.file('pubspec.yaml').createSync(); @@ -197,7 +197,7 @@ void main() { }); testUsingContext('targetPlatform does not throw when sshConfig is missing', () async { - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); expect(await device.targetPlatform, TargetPlatform.fuchsia_arm64); }, overrides: <Type, Generator>{ @@ -212,7 +212,7 @@ void main() { stdout: 'aarch64', )); - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); expect(await device.targetPlatform, TargetPlatform.fuchsia_arm64); }, overrides: <Type, Generator>{ FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), @@ -226,7 +226,7 @@ void main() { stdout: 'x86_64', )); - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); expect(await device.targetPlatform, TargetPlatform.fuchsia_x64); }, overrides: <Type, Generator>{ FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), @@ -240,7 +240,7 @@ void main() { stdout: 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', )); - final FuchsiaDevice device = FuchsiaDevice('id', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('id'); expect(await device.hostAddress, 'fe80::8c6c:2fff:fe3d:c5e1%25ethp0003'); }, overrides: <Type, Generator>{ FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), @@ -254,7 +254,7 @@ void main() { exitCode: 1, )); - final FuchsiaDevice device = FuchsiaDevice('id', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('id'); await expectLater(() => device.hostAddress, throwsToolExit()); }, overrides: <Type, Generator>{ FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), @@ -267,7 +267,7 @@ void main() { command: <String>['ssh', '-F', '/ssh_config', 'id', r'echo $SSH_CONNECTION'], )); - final FuchsiaDevice device = FuchsiaDevice('id', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('id'); expect(() async => device.hostAddress, throwsToolExit()); }, overrides: <Type, Generator>{ FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), @@ -289,7 +289,7 @@ void main() { processManager.addCommand(const FakeCommand( command: <String>['ssh', '-F', '/artifact', 'id', 'find /hub -name vmservice-port'], )); - final FuchsiaDevice device = FuchsiaDevice('id', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('id'); await expectLater(device.servicePorts, throwsToolExit(message: 'No Dart Observatories found. Are you running a debug build?')); }, overrides: <Type, Generator>{ @@ -766,7 +766,7 @@ void main() { }); testUsingContext('does not throw on non-existent ssh config', () async { - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); expect(await device.sdkNameAndVersion, equals('Fuchsia')); }, overrides: <Type, Generator>{ @@ -780,7 +780,7 @@ void main() { command: <String>['ssh', '-F', '/ssh_config', '123', 'cat /pkgfs/packages/build-info/0/data/version'], stdout: 'version' )); - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); expect(await device.sdkNameAndVersion, equals('Fuchsia version')); }, overrides: <Type, Generator>{ @@ -794,7 +794,7 @@ void main() { command: <String>['ssh', '-F', '/ssh_config', '123', 'cat /pkgfs/packages/build-info/0/data/version'], exitCode: 1, )); - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); expect(await device.sdkNameAndVersion, equals('Fuchsia')); }, overrides: <Type, Generator>{ @@ -807,7 +807,7 @@ void main() { processManager.addCommand(const FakeCommand( command: <String>['ssh', '-F', '/ssh_config', '123', 'cat /pkgfs/packages/build-info/0/data/version'], )); - final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); + final FuchsiaDevice device = FuchsiaDevice('123'); expect(await device.sdkNameAndVersion, equals('Fuchsia')); }, overrides: <Type, Generator>{ diff --git a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart index e850ca3fb4630..b31e2f3c194ee 100644 --- a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart +++ b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart @@ -751,7 +751,7 @@ void main() { arbDirectory: Uri.directory(defaultL10nPathString), deferredLoading: true, outputClass: 'Foo', - outputLocalizationsFile: Uri.file('bar.dart', windows: false), + outputLocalizationsFile: Uri.file('bar', windows: false), outputDirectory: Uri.directory(defaultL10nPathString, windows: false), preferredSupportedLocales: <String>['es'], templateArbFile: Uri.file(defaultTemplateArbFileName, windows: false), @@ -773,7 +773,7 @@ void main() { expect(generator.inputDirectory.path, '/lib/l10n/'); expect(generator.outputDirectory.path, '/lib/l10n/'); expect(generator.templateArbFile.path, '/lib/l10n/app_en.arb'); - expect(generator.baseOutputFile.path, '/lib/l10n/bar.dart'); + expect(generator.baseOutputFile.path, '/lib/l10n/bar'); expect(generator.className, 'Foo'); expect(generator.preferredSupportedLocales.single, LocaleInfo.fromString('es')); expect(generator.header, 'HEADER'); @@ -790,7 +790,7 @@ void main() { HEADER -import 'bar.dart'; +import 'bar'; /// The translations for English (`en`). class FooEn extends Foo { @@ -1322,94 +1322,6 @@ import 'output-localization-file_zh.dart'; ''')); }); - // Regression test for https://github.com/flutter/flutter/issues/88356 - testWithoutContext('full output file suffix is retained', () { - fs.currentDirectory.childDirectory('lib').childDirectory('l10n')..createSync(recursive: true) - ..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString); - - LocalizationsGenerator( - fileSystem: fs, - inputPathString: defaultL10nPathString, - outputPathString: defaultL10nPathString, - templateArbFileName: defaultTemplateArbFileName, - outputFileString: 'output-localization-file.g.dart', - classNameString: defaultClassNameString, - ) - ..loadResources() - ..writeOutputFiles(BufferLogger.test()); - - final String baseLocalizationsFile = fs.file( - fs.path.join(syntheticL10nPackagePath, 'output-localization-file.g.dart'), - ).readAsStringSync(); - expect(baseLocalizationsFile, contains( -''' -import 'output-localization-file_en.g.dart'; -''')); - - final String englishLocalizationsFile = fs.file( - fs.path.join(syntheticL10nPackagePath, 'output-localization-file_en.g.dart'), - ).readAsStringSync(); - expect(englishLocalizationsFile, contains( -''' -import 'output-localization-file.g.dart'; -''')); - }); - - testWithoutContext('throws an exception when invalid output file name is passed in', () { - fs.currentDirectory.childDirectory('lib').childDirectory('l10n')..createSync(recursive: true) - ..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString); - - expect( - () { - LocalizationsGenerator( - fileSystem: fs, - inputPathString: defaultL10nPathString, - outputPathString: defaultL10nPathString, - templateArbFileName: defaultTemplateArbFileName, - outputFileString: 'asdf', - classNameString: defaultClassNameString, - ) - ..loadResources() - ..writeOutputFiles(BufferLogger.test()); - }, - throwsA(isA<L10nException>().having( - (L10nException e) => e.message, - 'message', - allOf( - contains('output-localization-file'), - contains('asdf'), - contains('is invalid'), - contains('The file name must have a .dart extension.'), - ), - )), - ); - - expect( - () { - LocalizationsGenerator( - fileSystem: fs, - inputPathString: defaultL10nPathString, - outputPathString: defaultL10nPathString, - templateArbFileName: defaultTemplateArbFileName, - outputFileString: '.g.dart', - classNameString: defaultClassNameString, - ) - ..loadResources() - ..writeOutputFiles(BufferLogger.test()); - }, - throwsA(isA<L10nException>().having( - (L10nException e) => e.message, - 'message', - allOf( - contains('output-localization-file'), - contains('.g.dart'), - contains('is invalid'), - contains('The base name cannot be empty.'), - ), - )), - ); - }); - testWithoutContext('imports are deferred and loaded when useDeferredImports are set', () { fs.currentDirectory.childDirectory('lib').childDirectory('l10n')..createSync(recursive: true) ..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString); @@ -2708,47 +2620,4 @@ String orderNumber(int number) { AppLocalizations lookupAppLocalizations(Locale locale) { ''')); }); - - // Regression test for https://github.com/flutter/flutter/pull/93228 - testWithoutContext('should use num type for plural', () { - const String arbFile = ''' -{ - "tryToPollute": "{count, plural, =0{零} =1{一} other{其他}}", - "@tryToPollute": { - "placeholders": { - "count": { - "type": "int" - } - } - }, - "withoutType": "{count, plural, =0{零} =1{一} other{其他}}", - "@withoutType": { - "placeholders": { - "count": {} - } - } -}'''; - - final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') - ..createSync(recursive: true); - l10nDirectory.childFile(defaultTemplateArbFileName) - .writeAsStringSync(arbFile); - - LocalizationsGenerator( - fileSystem: fs, - inputPathString: defaultL10nPathString, - outputPathString: defaultL10nPathString, - templateArbFileName: defaultTemplateArbFileName, - outputFileString: defaultOutputFileString, - classNameString: defaultClassNameString, - ) - ..loadResources() - ..writeOutputFiles(BufferLogger.test()); - - final String localizationsFile = fs.file( - fs.path.join(syntheticL10nPackagePath, 'output-localization-file_en.dart'), - ).readAsStringSync(); - expect(localizationsFile, containsIgnoringWhitespace(r'String tryToPollute(num count) {')); - expect(localizationsFile, containsIgnoringWhitespace(r'String withoutType(num count) {')); - }); } diff --git a/packages/flutter_tools/test/general.shard/github_template_test.dart b/packages/flutter_tools/test/general.shard/github_template_test.dart index 81cbd8163fcb7..279eb9c9661b0 100644 --- a/packages/flutter_tools/test/general.shard/github_template_test.dart +++ b/packages/flutter_tools/test/general.shard/github_template_test.dart @@ -308,7 +308,4 @@ class FakeError extends Error { StackTrace get stackTrace => StackTrace.fromString(''' #0 _File.open.<anonymous closure> (dart:io/file_impl.dart:366:9) #1 _rootRunUnary (dart:async/zone.dart:1141:38)'''); - - @override - String toString() => 'PII to ignore'; } diff --git a/packages/flutter_tools/test/general.shard/integration_test_device_test.dart b/packages/flutter_tools/test/general.shard/integration_test_device_test.dart index c76232366a653..90c450fbac864 100644 --- a/packages/flutter_tools/test/general.shard/integration_test_device_test.dart +++ b/packages/flutter_tools/test/general.shard/integration_test_device_test.dart @@ -4,8 +4,6 @@ // @dart = 2.8 -import 'package:file/file.dart'; -import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/base/io.dart' as io; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/build_info.dart'; @@ -14,10 +12,8 @@ import 'package:flutter_tools/src/test/integration_test_device.dart'; import 'package:flutter_tools/src/test/test_device.dart'; import 'package:flutter_tools/src/vmservice.dart'; import 'package:stream_channel/stream_channel.dart'; -import 'package:test/fake.dart'; import 'package:vm_service/vm_service.dart' as vm_service; -import '../src/common.dart'; import '../src/context.dart'; import '../src/fake_devices.dart'; import '../src/fake_vm_services.dart'; @@ -125,26 +121,12 @@ void main() { ]); }); - testUsingContext('will not start when package missing', () async { - await expectLater( - testDevice.start('entrypointPath'), - throwsA( - isA<TestDeviceException>().having( - (Exception e) => e.toString(), - 'description', - contains('No application found for TargetPlatform.android_arm'), - ), - ), - ); - }); - testUsingContext('Can start the entrypoint', () async { await testDevice.start('entrypointPath'); expect(await testDevice.observatoryUri, observatoryUri); expect(testDevice.finished, doesNotComplete); }, overrides: <Type, Generator>{ - ApplicationPackageFactory: () => FakeApplicationPackageFactory(), VMServiceConnector: () => (Uri httpUri, { ReloadSources reloadSources, Restart restart, @@ -163,7 +145,6 @@ void main() { expect(testDevice.finished, completes); }, overrides: <Type, Generator>{ - ApplicationPackageFactory: () => FakeApplicationPackageFactory(), VMServiceConnector: () => (Uri httpUri, { ReloadSources reloadSources, Restart restart, @@ -237,7 +218,6 @@ void main() { await fakeVmServiceHost.vmService.dispose(); expect(await channel.stream.isEmpty, true); }, overrides: <Type, Generator>{ - ApplicationPackageFactory: () => FakeApplicationPackageFactory(), VMServiceConnector: () => (Uri httpUri, { ReloadSources reloadSources, Restart restart, @@ -250,14 +230,3 @@ void main() { }) async => fakeVmServiceHost.vmService, }); } - -class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFactory { - @override - Future<ApplicationPackage> getPackageForPlatform( - TargetPlatform platform, { - BuildInfo buildInfo, - File applicationBinary, - }) async => FakeApplicationPackage(); -} - -class FakeApplicationPackage extends Fake implements ApplicationPackage { } diff --git a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart index cb82324f008ff..0bb90fbac280a 100644 --- a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart @@ -11,10 +11,10 @@ import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; import 'package:flutter_tools/src/intellij/intellij_validator.dart'; import 'package:flutter_tools/src/ios/plist_parser.dart'; +import 'package:test/fake.dart'; import '../../src/common.dart'; import '../../src/fake_process_manager.dart'; -import '../../src/fakes.dart'; final Platform macPlatform = FakePlatform( operatingSystem: 'macos', @@ -373,6 +373,17 @@ void main() { }); } +class FakePlistParser extends Fake implements PlistParser { + FakePlistParser(this.values); + + final Map<String, String> values; + + @override + String? getValueFromFile(String plistFilePath, String key) { + return values[key]; + } +} + class IntelliJValidatorTestTarget extends IntelliJValidator { IntelliJValidatorTestTarget(String title, String installPath, FileSystem fileSystem) : super(title, installPath, fileSystem: fileSystem, userMessages: UserMessages()); diff --git a/packages/flutter_tools/test/general.shard/ios/code_signing_test.dart b/packages/flutter_tools/test/general.shard/ios/code_signing_test.dart index ef23d3b6fb140..0b7208922e219 100644 --- a/packages/flutter_tools/test/general.shard/ios/code_signing_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/code_signing_test.dart @@ -10,7 +10,7 @@ import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/terminal.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/code_signing.dart'; import '../../src/common.dart'; diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_install_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_install_test.dart index 846ccde0a2c62..e6b055e7d51c3 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_install_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_install_test.dart @@ -43,8 +43,7 @@ void main() { testWithoutContext('IOSDevice.installApp calls ios-deploy correctly with USB', () async { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', - uncompressedBundle: fileSystem.currentDirectory, - applicationPackage: bundleDirectory, + bundleDir: fileSystem.currentDirectory, ); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <String>[ @@ -74,8 +73,7 @@ void main() { testWithoutContext('IOSDevice.installApp calls ios-deploy correctly with network', () async { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', - uncompressedBundle: fileSystem.currentDirectory, - applicationPackage: bundleDirectory, + bundleDir: fileSystem.currentDirectory, ); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <String>[ @@ -102,11 +100,7 @@ void main() { }); testWithoutContext('IOSDevice.uninstallApp calls ios-deploy correctly', () async { - final IOSApp iosApp = PrebuiltIOSApp( - projectBundleId: 'app', - uncompressedBundle: bundleDirectory, - applicationPackage: bundleDirectory, - ); + final IOSApp iosApp = PrebuiltIOSApp(projectBundleId: 'app', bundleDir: bundleDirectory); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <String>[ iosDeployPath, @@ -129,11 +123,7 @@ void main() { group('isAppInstalled', () { testWithoutContext('catches ProcessException from ios-deploy', () async { - final IOSApp iosApp = PrebuiltIOSApp( - projectBundleId: 'app', - uncompressedBundle: bundleDirectory, - applicationPackage: bundleDirectory, - ); + final IOSApp iosApp = PrebuiltIOSApp(projectBundleId: 'app', bundleDir: bundleDirectory); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <String>[ iosDeployPath, @@ -157,11 +147,7 @@ void main() { }); testWithoutContext('returns true when app is installed', () async { - final IOSApp iosApp = PrebuiltIOSApp( - projectBundleId: 'app', - uncompressedBundle: bundleDirectory, - applicationPackage: bundleDirectory, - ); + final IOSApp iosApp = PrebuiltIOSApp(projectBundleId: 'app', bundleDir: bundleDirectory); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <String>[ iosDeployPath, @@ -185,11 +171,7 @@ void main() { }); testWithoutContext('returns false when app is not installed', () async { - final IOSApp iosApp = PrebuiltIOSApp( - projectBundleId: 'app', - uncompressedBundle: bundleDirectory, - applicationPackage: bundleDirectory, - ); + final IOSApp iosApp = PrebuiltIOSApp(projectBundleId: 'app', bundleDir: bundleDirectory); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <String>[ iosDeployPath, @@ -215,11 +197,7 @@ void main() { }); testWithoutContext('returns false on command timeout or other error', () async { - final IOSApp iosApp = PrebuiltIOSApp( - projectBundleId: 'app', - uncompressedBundle: bundleDirectory, - applicationPackage: bundleDirectory, - ); + final IOSApp iosApp = PrebuiltIOSApp(projectBundleId: 'app', bundleDir: bundleDirectory); const String stderr = '2020-03-26 17:48:43.484 ios-deploy[21518:5501783] [ !! ] Timed out waiting for device'; final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <String>[ @@ -250,8 +228,7 @@ void main() { testWithoutContext('IOSDevice.installApp catches ProcessException from ios-deploy', () async { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', - uncompressedBundle: fileSystem.currentDirectory, - applicationPackage: bundleDirectory, + bundleDir: fileSystem.currentDirectory, ); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <String>[ @@ -273,11 +250,7 @@ void main() { }); testWithoutContext('IOSDevice.uninstallApp catches ProcessException from ios-deploy', () async { - final IOSApp iosApp = PrebuiltIOSApp( - projectBundleId: 'app', - uncompressedBundle: bundleDirectory, - applicationPackage: bundleDirectory, - ); + final IOSApp iosApp = PrebuiltIOSApp(projectBundleId: 'app', bundleDir: bundleDirectory); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <String>[ iosDeployPath, diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart index 0acb7ec80ce79..eab83f1efa460 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart @@ -58,8 +58,6 @@ const List<String> kRunReleaseArgs = <String>[ 'id=123', 'ONLY_ACTIVE_ARCH=YES', 'ARCHS=arm64', - '-resultBundlePath', '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle', - '-resultBundleVersion', '3', 'FLUTTER_SUPPRESS_ANALYTICS=true', 'COMPILER_INDEX_STORE_ENABLE=NO', ]; @@ -188,7 +186,6 @@ void main() { processManager.addCommand(const FakeCommand(command: kRunReleaseArgs)); processManager.addCommand(const FakeCommand(command: <String>[ 'rsync', - '-8', '-av', '--delete', 'build/ios/Release-iphoneos/My Super Awesome App.app', diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart index 37907d08ed9bc..856cb3a2c7616 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart @@ -93,8 +93,7 @@ void main() { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', bundleName: 'Runner', - uncompressedBundle: MemoryFileSystem.test().directory('bundle'), - applicationPackage: MemoryFileSystem.test().directory('bundle'), + bundleDir: MemoryFileSystem.test().directory('bundle'), ); device.portForwarder = devicePortForwarder; @@ -117,8 +116,7 @@ void main() { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', bundleName: 'Runner', - uncompressedBundle: fileSystem.currentDirectory, - applicationPackage: fileSystem.currentDirectory, + bundleDir: fileSystem.currentDirectory, ); final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); @@ -155,8 +153,7 @@ void main() { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', bundleName: 'Runner', - uncompressedBundle: fileSystem.currentDirectory, - applicationPackage: fileSystem.currentDirectory, + bundleDir: fileSystem.currentDirectory, ); final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); @@ -194,8 +191,7 @@ void main() { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', bundleName: 'Runner', - uncompressedBundle: fileSystem.currentDirectory, - applicationPackage: fileSystem.currentDirectory, + bundleDir: fileSystem.currentDirectory, ); final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); @@ -234,8 +230,7 @@ void main() { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', bundleName: 'Runner', - uncompressedBundle: fileSystem.currentDirectory, - applicationPackage: fileSystem.currentDirectory, + bundleDir: fileSystem.currentDirectory, ); final LaunchResult launchResult = await device.startApp(iosApp, @@ -301,8 +296,7 @@ void main() { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', bundleName: 'Runner', - uncompressedBundle: fileSystem.currentDirectory, - applicationPackage: fileSystem.currentDirectory, + bundleDir: fileSystem.currentDirectory, ); final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); diff --git a/packages/flutter_tools/test/general.shard/ios/mac_test.dart b/packages/flutter_tools/test/general.shard/ios/mac_test.dart index f641e655a4858..682703256b302 100644 --- a/packages/flutter_tools/test/general.shard/ios/mac_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/mac_test.dart @@ -489,7 +489,7 @@ class FakeIosProject extends Fake implements IosProject { final File xcodeProjectInfoFile; @override - Future<String> hostAppBundleName(BuildInfo? buildInfo) async => 'UnitTestRunner.app'; + Future<String> hostAppBundleName(BuildInfo buildInfo) async => 'UnitTestRunner.app'; @override Directory get xcodeProject => xcodeProjectInfoFile.fileSystem.directory('Runner.xcodeproj'); diff --git a/packages/flutter_tools/test/general.shard/ios/simulators_test.dart b/packages/flutter_tools/test/general.shard/ios/simulators_test.dart index 7610b31f28154..499a0d58f7d4b 100644 --- a/packages/flutter_tools/test/general.shard/ios/simulators_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/simulators_test.dart @@ -14,7 +14,7 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device_port_forwarder.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/application_package.dart'; import 'package:flutter_tools/src/ios/plist_parser.dart'; import 'package:flutter_tools/src/ios/simulators.dart'; @@ -917,12 +917,7 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''' testPlistParser.setProperty('CFBundleIdentifier', 'correct'); final Directory mockDir = globals.fs.currentDirectory; - final IOSApp package = PrebuiltIOSApp( - projectBundleId: 'incorrect', - bundleName: 'name', - uncompressedBundle: mockDir, - applicationPackage: mockDir, - ); + final IOSApp package = PrebuiltIOSApp(projectBundleId: 'incorrect', bundleName: 'name', bundleDir: mockDir); const BuildInfo mockInfo = BuildInfo(BuildMode.debug, 'flavor', treeShakeIcons: false); final DebuggingOptions mockOptions = DebuggingOptions.disabled(mockInfo); @@ -945,12 +940,7 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''' ); final Directory mockDir = globals.fs.currentDirectory; - final IOSApp package = PrebuiltIOSApp( - projectBundleId: 'incorrect', - bundleName: 'name', - uncompressedBundle: mockDir, - applicationPackage: mockDir, - ); + final IOSApp package = PrebuiltIOSApp(projectBundleId: 'incorrect', bundleName: 'name', bundleDir: mockDir); const BuildInfo mockInfo = BuildInfo(BuildMode.debug, 'flavor', treeShakeIcons: false); final DebuggingOptions mockOptions = DebuggingOptions.disabled(mockInfo); @@ -977,12 +967,7 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''' testPlistParser.setProperty('CFBundleIdentifier', 'correct'); final Directory mockDir = globals.fs.currentDirectory; - final IOSApp package = PrebuiltIOSApp( - projectBundleId: 'correct', - bundleName: 'name', - uncompressedBundle: mockDir, - applicationPackage: mockDir, - ); + final IOSApp package = PrebuiltIOSApp(projectBundleId: 'correct', bundleName: 'name', bundleDir: mockDir); const BuildInfo mockInfo = BuildInfo(BuildMode.debug, 'flavor', treeShakeIcons: false); final DebuggingOptions mockOptions = DebuggingOptions.enabled(mockInfo, enableSoftwareRendering: true); diff --git a/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart b/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart index 738c31467ff69..b39c929ac9c63 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart @@ -10,7 +10,6 @@ import 'package:flutter_tools/src/macos/xcode.dart'; import '../../src/common.dart'; import '../../src/fake_process_manager.dart'; -import 'xcresult_test_data.dart'; void main() { // Creates a FakeCommand for the xcresult get call to build the app @@ -95,13 +94,12 @@ void main() { testWithoutContext( 'correctly parse sample result json when there are issues.', () async { - final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonWithIssues); + final XCResultGenerator generator = _setupGenerator(resultJson: _sampleResultJsonWithIssues); final XCResult result = await generator.generate(); expect(result.issues.length, 2); expect(result.issues.first.type, XCResultIssueType.error); expect(result.issues.first.subType, 'Semantic Issue'); expect(result.issues.first.message, "Use of undeclared identifier 'asdas'"); - expect(result.issues.first.location, '/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'); expect(result.issues.last.type, XCResultIssueType.warning); expect(result.issues.last.subType, 'Warning'); expect(result.issues.last.message, @@ -110,94 +108,9 @@ void main() { expect(result.parsingErrorMessage, isNull); }); - testWithoutContext( - 'correctly parse sample result json when there are issues but invalid url.', () async { - final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonWithIssuesAndInvalidUrl); - final XCResult result = await generator.generate(); - expect(result.issues.length, 2); - expect(result.issues.first.type, XCResultIssueType.error); - expect(result.issues.first.subType, 'Semantic Issue'); - expect(result.issues.first.message, "Use of undeclared identifier 'asdas'"); - expect(result.issues.first.location, isNull); - expect(result.issues.first.warnings.first, '(XCResult) The `url` exists but it was failed to be parsed. url: 3:00'); - expect(result.issues.last.type, XCResultIssueType.warning); - expect(result.issues.last.subType, 'Warning'); - expect(result.issues.last.message, - "The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99."); - expect(result.parseSuccess, isTrue); - expect(result.parsingErrorMessage, isNull); - }); - - testWithoutContext( - 'correctly parse sample result json and discard all warnings', () async { - final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonWithIssues); - final XCResultIssueDiscarder discarder = XCResultIssueDiscarder(typeMatcher: XCResultIssueType.warning); - final XCResult result = await generator.generate(issueDiscarders: <XCResultIssueDiscarder>[discarder]); - expect(result.issues.length, 1); - expect(result.issues.first.type, XCResultIssueType.error); - expect(result.issues.first.subType, 'Semantic Issue'); - expect(result.issues.first.message, "Use of undeclared identifier 'asdas'"); - expect(result.issues.first.location, '/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'); - expect(result.parseSuccess, isTrue); - expect(result.parsingErrorMessage, isNull); - }); - - testWithoutContext( - 'correctly parse sample result json and discard base on subType', () async { - final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonWithIssues); - final XCResultIssueDiscarder discarder = XCResultIssueDiscarder(subTypeMatcher: RegExp(r'^Warning$')); - final XCResult result = await generator.generate(issueDiscarders: <XCResultIssueDiscarder>[discarder]); - expect(result.issues.length, 1); - expect(result.issues.first.type, XCResultIssueType.error); - expect(result.issues.first.subType, 'Semantic Issue'); - expect(result.issues.first.message, "Use of undeclared identifier 'asdas'"); - expect(result.issues.first.location, '/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'); - expect(result.parseSuccess, isTrue); - expect(result.parsingErrorMessage, isNull); - }); - - testWithoutContext( - 'correctly parse sample result json and discard base on message', () async { - final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonWithIssues); - final XCResultIssueDiscarder discarder = XCResultIssueDiscarder(messageMatcher: RegExp(r"^The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.$")); - final XCResult result = await generator.generate(issueDiscarders: <XCResultIssueDiscarder>[discarder]); - expect(result.issues.length, 1); - expect(result.issues.first.type, XCResultIssueType.error); - expect(result.issues.first.subType, 'Semantic Issue'); - expect(result.issues.first.message, "Use of undeclared identifier 'asdas'"); - expect(result.issues.first.location, '/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'); - expect(result.parseSuccess, isTrue); - expect(result.parsingErrorMessage, isNull); - }); - - testWithoutContext( - 'correctly parse sample result json and discard base on location', () async { - final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonWithIssues); - final XCResultIssueDiscarder discarder = XCResultIssueDiscarder(locationMatcher: RegExp(r'/Users/m/Projects/test_create/ios/Runner/AppDelegate.m')); - final XCResult result = await generator.generate(issueDiscarders: <XCResultIssueDiscarder>[discarder]); - expect(result.issues.length, 1); - expect(result.issues.first.type, XCResultIssueType.warning); - expect(result.issues.first.subType, 'Warning'); - expect(result.issues.first.message, - "The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99."); - expect(result.parseSuccess, isTrue); - expect(result.parsingErrorMessage, isNull); - }); - - testWithoutContext( - 'correctly parse sample result json with multiple discarders.', () async { - final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonWithIssues); - final XCResultIssueDiscarder discardWarnings = XCResultIssueDiscarder(typeMatcher: XCResultIssueType.warning); - final XCResultIssueDiscarder discardSemanticIssues = XCResultIssueDiscarder(subTypeMatcher: RegExp(r'^Semantic Issue$')); - final XCResult result = await generator.generate(issueDiscarders: <XCResultIssueDiscarder>[discardWarnings, discardSemanticIssues]); - expect(result.issues, isEmpty); - expect(result.parseSuccess, isTrue); - expect(result.parsingErrorMessage, isNull); - }); - testWithoutContext('correctly parse sample result json when no issues.', () async { - final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonNoIssues); + final XCResultGenerator generator = _setupGenerator(resultJson: _sampleResultJsonNoIssues); final XCResult result = await generator.generate(); expect(result.issues.length, 0); expect(result.parseSuccess, isTrue); @@ -240,18 +153,59 @@ void main() { 'xcresult parser: Unrecognized top level json format.'); }); - testWithoutContext('error: fail to parse issue map', () async { + testWithoutContext('error: fail to parse actions map', () async { final XCResultGenerator generator = _setupGenerator(resultJson: '{}'); final XCResult result = await generator.generate(); expect(result.issues.length, 0); expect(result.parseSuccess, false); expect(result.parsingErrorMessage, - 'xcresult parser: Failed to parse the issues map.'); + 'xcresult parser: Failed to parse the actions map.'); + }); + + testWithoutContext('error: empty actions map', () async { + final XCResultGenerator generator = + _setupGenerator(resultJson: _sampleResultJsonEmptyActionsMap); + + final XCResult result = await generator.generate(); + expect(result.issues.length, 0); + expect(result.parseSuccess, false); + expect(result.parsingErrorMessage, + 'xcresult parser: Failed to parse the actions map.'); + }); + + testWithoutContext('error: empty actions map', () async { + final XCResultGenerator generator = _setupGenerator(resultJson: _sampleResultJsonEmptyActionsMap); + + final XCResult result = await generator.generate(); + expect(result.issues.length, 0); + expect(result.parseSuccess, false); + expect(result.parsingErrorMessage, + 'xcresult parser: Failed to parse the actions map.'); + }); + + testWithoutContext('error: empty actions map', () async { + final XCResultGenerator generator = _setupGenerator(resultJson: _sampleResultJsonInvalidActionMap); + + final XCResult result = await generator.generate(); + expect(result.issues.length, 0); + expect(result.parseSuccess, false); + expect(result.parsingErrorMessage, + 'xcresult parser: Failed to parse the first action map.'); + }); + + testWithoutContext('error: empty actions map', () async { + final XCResultGenerator generator = _setupGenerator(resultJson: _sampleResultJsonInvalidBuildResultMap); + + final XCResult result = await generator.generate(); + expect(result.issues.length, 0); + expect(result.parseSuccess, false); + expect(result.parsingErrorMessage, + 'xcresult parser: Failed to parse the buildResult map.'); }); - testWithoutContext('error: invalid issue map', () async { - final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonInvalidIssuesMap); + testWithoutContext('error: empty actions map', () async { + final XCResultGenerator generator = _setupGenerator(resultJson: _sampleResultJsonInvalidIssuesMap); final XCResult result = await generator.generate(); expect(result.issues.length, 0); @@ -261,4 +215,1029 @@ void main() { }); } +const String _sampleResultJsonInvalidIssuesMap = r''' +{ + "_type" : { + "_name" : "ActionsInvocationRecord" + }, + "actions" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "buildResult": { + } + } + ] + } +} +'''; + +const String _sampleResultJsonInvalidBuildResultMap = r''' +{ + "_type" : { + "_name" : "ActionsInvocationRecord" + }, + "actions" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + {} + ] + } +} +'''; + +const String _sampleResultJsonInvalidActionMap = r''' +{ + "_type" : { + "_name" : "ActionsInvocationRecord" + }, + "actions" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + [] + ] + } +} +'''; + +const String _sampleResultJsonEmptyActionsMap = r''' +{ + "_type" : { + "_name" : "ActionsInvocationRecord" + }, + "actions" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + ] + } +} +'''; + +const String _sampleResultJsonWithIssues = r''' +{ + "_type" : { + "_name" : "ActionsInvocationRecord" + }, + "actions" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "ActionRecord" + }, + "actionResult" : { + "_type" : { + "_name" : "ActionResult" + }, + "coverage" : { + "_type" : { + "_name" : "CodeCoverageInfo" + } + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + }, + "resultName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "action" + }, + "status" : { + "_type" : { + "_name" : "String" + }, + "_value" : "notRequested" + } + }, + "buildResult" : { + "_type" : { + "_name" : "ActionResult" + }, + "coverage" : { + "_type" : { + "_name" : "CodeCoverageInfo" + } + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + }, + "errorSummaries" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "IssueSummary" + }, + "documentLocationInCreatingWorkspace" : { + "_type" : { + "_name" : "DocumentLocation" + }, + "concreteTypeName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "DVTTextDocumentLocation" + }, + "url" : { + "_type" : { + "_name" : "String" + }, + "_value" : "file:\/\/\/Users\/m\/Projects\/test_create\/ios\/Runner\/AppDelegate.m#CharacterRangeLen=0&CharacterRangeLoc=263&EndingColumnNumber=56&EndingLineNumber=7&LocationEncoding=1&StartingColumnNumber=56&StartingLineNumber=7" + } + }, + "issueType" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Semantic Issue" + }, + "message" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Use of undeclared identifier 'asdas'" + } + } + ] + }, + "warningSummaries" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "IssueSummary" + }, + "issueType" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Warning" + }, + "message" : { + "_type" : { + "_name" : "String" + }, + "_value" : "The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99." + } + } + ] + } + }, + "logRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~bjiFq9EH53z6VfWSr47dakT0w_aGcY_GFqgPuexHq1JsoKMmvf_6GLglMcWBYRCSNufKEX6l1YgbFmnuobsw5w==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActivityLogSection" + } + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + }, + "errorCount" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "1" + }, + "warningCount" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "1" + } + }, + "resultName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "build" + }, + "status" : { + "_type" : { + "_name" : "String" + }, + "_value" : "failed" + } + }, + "endedTime" : { + "_type" : { + "_name" : "Date" + }, + "_value" : "2020-09-28T14:31:16.931-0700" + }, + "runDestination" : { + "_type" : { + "_name" : "ActionRunDestinationRecord" + }, + "displayName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Any iOS Device" + }, + "localComputerRecord" : { + "_type" : { + "_name" : "ActionDeviceRecord" + }, + "busSpeedInMHz" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "100" + }, + "cpuCount" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "1" + }, + "cpuKind" : { + "_type" : { + "_name" : "String" + }, + "_value" : "8-Core Intel Xeon W" + }, + "cpuSpeedInMHz" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "3200" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "87BE7059-56E3-5470-B52D-31A0F76402B3" + }, + "isConcreteDevice" : { + "_type" : { + "_name" : "Bool" + }, + "_value" : "true" + }, + "logicalCPUCoresPerPackage" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "16" + }, + "modelCode" : { + "_type" : { + "_name" : "String" + }, + "_value" : "iMacPro1,1" + }, + "modelName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "iMac Pro" + }, + "modelUTI" : { + "_type" : { + "_name" : "String" + }, + "_value" : "com.apple.imacpro-2017" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "My Mac" + }, + "nativeArchitecture" : { + "_type" : { + "_name" : "String" + }, + "_value" : "x86_64h" + }, + "operatingSystemVersion" : { + "_type" : { + "_name" : "String" + }, + "_value" : "10.15.5" + }, + "operatingSystemVersionWithBuildNumber" : { + "_type" : { + "_name" : "String" + }, + "_value" : "10.15.5 (19F101)" + }, + "physicalCPUCoresPerPackage" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "8" + }, + "platformRecord" : { + "_type" : { + "_name" : "ActionPlatformRecord" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "com.apple.platform.macosx" + }, + "userDescription" : { + "_type" : { + "_name" : "String" + }, + "_value" : "macOS" + } + }, + "ramSizeInMegabytes" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "65536" + } + }, + "targetArchitecture" : { + "_type" : { + "_name" : "String" + }, + "_value" : "arm64e" + }, + "targetDeviceRecord" : { + "_type" : { + "_name" : "ActionDeviceRecord" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder" + }, + "modelCode" : { + "_type" : { + "_name" : "String" + }, + "_value" : "GenericiOS" + }, + "modelName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "GenericiOS" + }, + "modelUTI" : { + "_type" : { + "_name" : "String" + }, + "_value" : "com.apple.dt.Xcode.device.GenericiOS" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Any iOS Device" + }, + "nativeArchitecture" : { + "_type" : { + "_name" : "String" + }, + "_value" : "arm64e" + }, + "platformRecord" : { + "_type" : { + "_name" : "ActionPlatformRecord" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "com.apple.platform.iphoneos" + }, + "userDescription" : { + "_type" : { + "_name" : "String" + }, + "_value" : "iOS" + } + } + }, + "targetSDKRecord" : { + "_type" : { + "_name" : "ActionSDKRecord" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "iphoneos14.0" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "iOS 14.0" + }, + "operatingSystemVersion" : { + "_type" : { + "_name" : "String" + }, + "_value" : "14.0" + } + } + }, + "schemeCommandName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Run" + }, + "schemeTaskName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Build" + }, + "startedTime" : { + "_type" : { + "_name" : "Date" + }, + "_value" : "2020-09-28T14:31:13.125-0700" + }, + "title" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Build \"Runner\"" + } + } + ] + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + }, + "errorSummaries" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "IssueSummary" + }, + "documentLocationInCreatingWorkspace" : { + "_type" : { + "_name" : "DocumentLocation" + }, + "concreteTypeName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "DVTTextDocumentLocation" + }, + "url" : { + "_type" : { + "_name" : "String" + }, + "_value" : "file:\/\/\/Users\/m\/Projects\/test_create\/ios\/Runner\/AppDelegate.m#CharacterRangeLen=0&CharacterRangeLoc=263&EndingColumnNumber=56&EndingLineNumber=7&LocationEncoding=1&StartingColumnNumber=56&StartingLineNumber=7" + } + }, + "issueType" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Semantic Issue" + }, + "message" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Use of undeclared identifier 'asdas'" + } + } + ] + }, + "warningSummaries" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "IssueSummary" + }, + "issueType" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Warning" + }, + "message" : { + "_type" : { + "_name" : "String" + }, + "_value" : "The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99." + } + } + ] + } + }, + "metadataRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~hrKQOFMo2Ri-TrlvSpVK8vTHcYQxwuWYJuRHCjoxIleliOdh5fHOdfIALZV0S0FtjVmUB83FpKkPbWajga4wxA==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActionsInvocationMetadata" + } + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + }, + "errorCount" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "1" + }, + "warningCount" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "1" + } + } +} +'''; + +const String _sampleResultJsonNoIssues = r''' +{ + "_type" : { + "_name" : "ActionsInvocationRecord" + }, + "actions" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "ActionRecord" + }, + "actionResult" : { + "_type" : { + "_name" : "ActionResult" + }, + "coverage" : { + "_type" : { + "_name" : "CodeCoverageInfo" + } + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + }, + "resultName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "action" + }, + "status" : { + "_type" : { + "_name" : "String" + }, + "_value" : "notRequested" + } + }, + "buildResult" : { + "_type" : { + "_name" : "ActionResult" + }, + "coverage" : { + "_type" : { + "_name" : "CodeCoverageInfo" + } + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + } + }, + "logRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~XBP6QfgBACcao7crWD8_8W18SPIqMzlK0U0oBhSvElOM8k-vQKO4ZmCtUhL-BfTDFSylC3qEPStUI3jNsBPTXA==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActivityLogSection" + } + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + }, + "resultName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "build" + }, + "status" : { + "_type" : { + "_name" : "String" + }, + "_value" : "succeeded" + } + }, + "endedTime" : { + "_type" : { + "_name" : "Date" + }, + "_value" : "2021-10-27T13:13:38.875-0700" + }, + "runDestination" : { + "_type" : { + "_name" : "ActionRunDestinationRecord" + }, + "displayName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Any iOS Device" + }, + "localComputerRecord" : { + "_type" : { + "_name" : "ActionDeviceRecord" + }, + "busSpeedInMHz" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "100" + }, + "cpuCount" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "1" + }, + "cpuKind" : { + "_type" : { + "_name" : "String" + }, + "_value" : "12-Core Intel Xeon E5" + }, + "cpuSpeedInMHz" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "2700" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "2BE58010-D352-540B-92E6-9A945BA6D36D" + }, + "isConcreteDevice" : { + "_type" : { + "_name" : "Bool" + }, + "_value" : "true" + }, + "logicalCPUCoresPerPackage" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "24" + }, + "modelCode" : { + "_type" : { + "_name" : "String" + }, + "_value" : "MacPro6,1" + }, + "modelName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Mac Pro" + }, + "modelUTI" : { + "_type" : { + "_name" : "String" + }, + "_value" : "com.apple.macpro-cylinder" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "My Mac" + }, + "nativeArchitecture" : { + "_type" : { + "_name" : "String" + }, + "_value" : "x86_64" + }, + "operatingSystemVersion" : { + "_type" : { + "_name" : "String" + }, + "_value" : "11.6" + }, + "operatingSystemVersionWithBuildNumber" : { + "_type" : { + "_name" : "String" + }, + "_value" : "11.6 (20G165)" + }, + "physicalCPUCoresPerPackage" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "12" + }, + "platformRecord" : { + "_type" : { + "_name" : "ActionPlatformRecord" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "com.apple.platform.macosx" + }, + "userDescription" : { + "_type" : { + "_name" : "String" + }, + "_value" : "macOS" + } + }, + "ramSizeInMegabytes" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "65536" + } + }, + "targetArchitecture" : { + "_type" : { + "_name" : "String" + }, + "_value" : "arm64e" + }, + "targetDeviceRecord" : { + "_type" : { + "_name" : "ActionDeviceRecord" + }, + "busSpeedInMHz" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "0" + }, + "cpuCount" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "0" + }, + "cpuSpeedInMHz" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "0" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder" + }, + "logicalCPUCoresPerPackage" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "0" + }, + "modelCode" : { + "_type" : { + "_name" : "String" + }, + "_value" : "GenericiOS" + }, + "modelName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "GenericiOS" + }, + "modelUTI" : { + "_type" : { + "_name" : "String" + }, + "_value" : "com.apple.dt.Xcode.device.GenericiOS" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Any iOS Device" + }, + "nativeArchitecture" : { + "_type" : { + "_name" : "String" + }, + "_value" : "arm64e" + }, + "physicalCPUCoresPerPackage" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "0" + }, + "platformRecord" : { + "_type" : { + "_name" : "ActionPlatformRecord" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "com.apple.platform.iphoneos" + }, + "userDescription" : { + "_type" : { + "_name" : "String" + }, + "_value" : "iOS" + } + }, + "ramSizeInMegabytes" : { + "_type" : { + "_name" : "Int" + }, + "_value" : "0" + } + }, + "targetSDKRecord" : { + "_type" : { + "_name" : "ActionSDKRecord" + }, + "identifier" : { + "_type" : { + "_name" : "String" + }, + "_value" : "iphoneos15.0" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "iOS 15.0" + }, + "operatingSystemVersion" : { + "_type" : { + "_name" : "String" + }, + "_value" : "15.0" + } + } + }, + "schemeCommandName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Run" + }, + "schemeTaskName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Build" + }, + "startedTime" : { + "_type" : { + "_name" : "Date" + }, + "_value" : "2021-10-27T13:13:02.396-0700" + }, + "title" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Build \"XCResultTestApp\"" + } + } + ] + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + } + }, + "metadataRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~4PY3oMxYEC19JHgIcIfOFnFe-ngUSzJD4NzcBevC8Y2-5y41lCyXxYXhi9eObvKdlU14arnDn8ilaTw6B_bbQQ==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActionsInvocationMetadata" + } + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + } +} + +'''; + const String _tempResultPath = 'temp'; diff --git a/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart b/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart deleted file mode 100644 index a638e041f25f1..0000000000000 --- a/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart +++ /dev/null @@ -1,304 +0,0 @@ -// 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. - -/// An example xcresult bundle json with invalid issues map. -const String kSampleResultJsonInvalidIssuesMap = r''' -{ - "_type" : { - "_name" : "ActionsInvocationRecord" - }, - "issues": [] -} -'''; - -/// An example xcresult bundle json that contains warnings and errors that needs to be discarded per https://github.com/flutter/flutter/issues/95354. -const String kSampleResultJsonWithIssuesToBeDiscarded = r''' -{ - "issues" : { - "_type" : { - "_name" : "ResultIssueSummaries" - }, - "errorSummaries" : { - "_type" : { - "_name" : "Array" - }, - "_values" : [ - { - "_type" : { - "_name" : "IssueSummary" - }, - "documentLocationInCreatingWorkspace" : { - "_type" : { - "_name" : "DocumentLocation" - }, - "concreteTypeName" : { - "_type" : { - "_name" : "String" - }, - "_value" : "DVTTextDocumentLocation" - }, - "url" : { - "_type" : { - "_name" : "String" - }, - "_value" : "file:\/\/\/Users\/m\/Projects\/test_create\/ios\/Runner\/AppDelegate.m#CharacterRangeLen=0&CharacterRangeLoc=263&EndingColumnNumber=56&EndingLineNumber=7&LocationEncoding=1&StartingColumnNumber=56&StartingLineNumber=7" - } - }, - "issueType" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Semantic Issue" - }, - "message" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Use of undeclared identifier 'asdas'" - } - }, - { - "_type" : { - "_name" : "IssueSummary" - }, - "issueType" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Uncategorized" - }, - "message" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Command PhaseScriptExecution failed with a nonzero exit code" - } - } - ] - }, - "warningSummaries" : { - "_type" : { - "_name" : "Array" - }, - "_values" : [ - { - "_type" : { - "_name" : "IssueSummary" - }, - "issueType" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Warning" - }, - "message" : { - "_type" : { - "_name" : "String" - }, - "_value" : "The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99." - } - } - ] - } - } -} -'''; - -/// An example xcresult bundle json that contains some warning and some errors. -const String kSampleResultJsonWithIssues = r''' -{ - "issues" : { - "_type" : { - "_name" : "ResultIssueSummaries" - }, - "errorSummaries" : { - "_type" : { - "_name" : "Array" - }, - "_values" : [ - { - "_type" : { - "_name" : "IssueSummary" - }, - "documentLocationInCreatingWorkspace" : { - "_type" : { - "_name" : "DocumentLocation" - }, - "concreteTypeName" : { - "_type" : { - "_name" : "String" - }, - "_value" : "DVTTextDocumentLocation" - }, - "url" : { - "_type" : { - "_name" : "String" - }, - "_value" : "file:\/\/\/Users\/m\/Projects\/test_create\/ios\/Runner\/AppDelegate.m#CharacterRangeLen=0&CharacterRangeLoc=263&EndingColumnNumber=56&EndingLineNumber=7&LocationEncoding=1&StartingColumnNumber=56&StartingLineNumber=7" - } - }, - "issueType" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Semantic Issue" - }, - "message" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Use of undeclared identifier 'asdas'" - } - } - ] - }, - "warningSummaries" : { - "_type" : { - "_name" : "Array" - }, - "_values" : [ - { - "_type" : { - "_name" : "IssueSummary" - }, - "issueType" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Warning" - }, - "message" : { - "_type" : { - "_name" : "String" - }, - "_value" : "The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99." - } - } - ] - } - } -} -'''; - -/// An example xcresult bundle json that contains some warning and some errors. -const String kSampleResultJsonWithIssuesAndInvalidUrl = r''' -{ - "issues" : { - "_type" : { - "_name" : "ResultIssueSummaries" - }, - "errorSummaries" : { - "_type" : { - "_name" : "Array" - }, - "_values" : [ - { - "_type" : { - "_name" : "IssueSummary" - }, - "documentLocationInCreatingWorkspace" : { - "_type" : { - "_name" : "DocumentLocation" - }, - "concreteTypeName" : { - "_type" : { - "_name" : "String" - }, - "_value" : "DVTTextDocumentLocation" - }, - "url" : { - "_type" : { - "_name" : "String" - }, - "_value" : "3:00" - } - }, - "issueType" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Semantic Issue" - }, - "message" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Use of undeclared identifier 'asdas'" - } - } - ] - }, - "warningSummaries" : { - "_type" : { - "_name" : "Array" - }, - "_values" : [ - { - "_type" : { - "_name" : "IssueSummary" - }, - "issueType" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Warning" - }, - "message" : { - "_type" : { - "_name" : "String" - }, - "_value" : "The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99." - } - } - ] - } - } -} -'''; - -/// An example xcresult bundle json that contains no issues. -const String kSampleResultJsonNoIssues = r''' -{ - "issues" : { - "_type" : { - "_name" : "ResultIssueSummaries" - } - } -} -'''; - -/// An example xcresult bundle json with some provision profile issue. -const String kSampleResultJsonWithProvisionIssue = r''' -{ - "issues" : { - "_type" : { - "_name" : "ResultIssueSummaries" - }, - "errorSummaries" : { - "_type" : { - "_name" : "Array" - }, - "_values" : [ - { - "_type" : { - "_name" : "IssueSummary" - }, - "issueType" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Semantic Issue" - }, - "message" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Some Provisioning profile issue." - } - } - ] - } - } -} -'''; diff --git a/packages/flutter_tools/test/general.shard/macos/application_package_test.dart b/packages/flutter_tools/test/general.shard/macos/application_package_test.dart index 490f21622c389..2f13bd33adc75 100644 --- a/packages/flutter_tools/test/general.shard/macos/application_package_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/application_package_test.dart @@ -12,7 +12,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/utils.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/plist_parser.dart'; import 'package:flutter_tools/src/macos/application_package.dart'; import 'package:flutter_tools/src/project.dart'; @@ -100,7 +100,7 @@ group('PrebuiltMacOSApp', () { final PrebuiltMacOSApp macosApp = MacOSApp.fromPrebuiltApp(fileSystem.file('bundle.app')) as PrebuiltMacOSApp; expect(logger.errorText, isEmpty); - expect(macosApp.uncompressedBundle.path, 'bundle.app'); + expect(macosApp.bundleDir.path, 'bundle.app'); expect(macosApp.id, 'fooBundleId'); expect(macosApp.bundleName, 'bundle.app'); }, overrides: overrides); @@ -152,7 +152,7 @@ group('PrebuiltMacOSApp', () { final PrebuiltMacOSApp macosApp = MacOSApp.fromPrebuiltApp(fileSystem.file('app.zip')) as PrebuiltMacOSApp; expect(logger.errorText, isEmpty); - expect(macosApp.uncompressedBundle.path, endsWith('bundle.app')); + expect(macosApp.bundleDir.path, endsWith('bundle.app')); expect(macosApp.id, 'fooBundleId'); expect(macosApp.bundleName, endsWith('bundle.app')); }, overrides: overrides); diff --git a/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart b/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart index a27a1cc7a24a6..62085f75b3c7d 100644 --- a/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart @@ -432,8 +432,8 @@ void main() { buildMode: BuildMode.debug, ); - expect(logger.warningText, contains('Warning: Podfile is out of date')); - expect(logger.warningText, contains('rm macos/Podfile')); + expect(logger.errorText, contains('Warning: Podfile is out of date')); + expect(logger.errorText, contains('rm macos/Podfile')); expect(fakeProcessManager, hasNoRemainingExpectations); }); @@ -491,52 +491,46 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by ); }); - final Map<String, String> possibleErrors = <String, String>{ - 'symbol not found': 'LoadError - dlsym(0x7fbbeb6837d0, Init_ffi_c): symbol not found - /Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle', - 'incompatible architecture': "LoadError - (mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64')), '/usr/lib/ffi_c.bundle' (no such file) - /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.4/lib/ffi_c.bundle", - }; - possibleErrors.forEach((String errorName, String cocoaPodsError) { - testUsingContext('ffi $errorName failure on ARM macOS prompts gem install', () async { - final FlutterProject projectUnderTest = setupProjectUnderTest(); - pretendPodIsInstalled(); - pretendPodVersionIs('1.10.0'); - fileSystem.file(fileSystem.path.join('project', 'ios', 'Podfile')) - ..createSync() - ..writeAsStringSync('Existing Podfile'); - - fakeProcessManager.addCommands(<FakeCommand>[ - FakeCommand( - command: const <String>['pod', 'install', '--verbose'], - workingDirectory: 'project/ios', - environment: const <String, String>{ - 'COCOAPODS_DISABLE_STATS': 'true', - 'LANG': 'en_US.UTF-8', - }, - exitCode: 1, - stdout: cocoaPodsError, - ), - const FakeCommand( - command: <String>['which', 'sysctl'], - ), - const FakeCommand( - command: <String>['sysctl', 'hw.optional.arm64'], - stdout: 'hw.optional.arm64: 1', - ), - ]); - - await expectToolExitLater( - cocoaPodsUnderTest.processPods( - xcodeProject: projectUnderTest.ios, - buildMode: BuildMode.debug, - ), - equals('Error running pod install'), - ); - expect( - logger.errorText, - contains('set up CocoaPods for ARM macOS'), - ); - expect(usage.events, contains(const TestUsageEvent('pod-install-failure', 'arm-ffi'))); - }); + testUsingContext('ffi failure on ARM macOS prompts gem install', () async { + final FlutterProject projectUnderTest = setupProjectUnderTest(); + pretendPodIsInstalled(); + pretendPodVersionIs('1.10.0'); + fileSystem.file(fileSystem.path.join('project', 'ios', 'Podfile')) + ..createSync() + ..writeAsStringSync('Existing Podfile'); + + fakeProcessManager.addCommands(<FakeCommand>[ + const FakeCommand( + command: <String>['pod', 'install', '--verbose'], + workingDirectory: 'project/ios', + environment: <String, String>{ + 'COCOAPODS_DISABLE_STATS': 'true', + 'LANG': 'en_US.UTF-8', + }, + exitCode: 1, + stdout: 'LoadError - dlsym(0x7fbbeb6837d0, Init_ffi_c): symbol not found - /Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle', + ), + const FakeCommand( + command: <String>['which', 'sysctl'], + ), + const FakeCommand( + command: <String>['sysctl', 'hw.optional.arm64'], + stdout: 'hw.optional.arm64: 1', + ), + ]); + + await expectToolExitLater( + cocoaPodsUnderTest.processPods( + xcodeProject: projectUnderTest.ios, + buildMode: BuildMode.debug, + ), + equals('Error running pod install'), + ); + expect( + logger.errorText, + contains('set up CocoaPods for ARM macOS'), + ); + expect(usage.events, contains(const TestUsageEvent('pod-install-failure', 'arm-ffi'))); }); testUsingContext('ffi failure on x86 macOS does not prompt gem install', () async { diff --git a/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart b/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart index 518a1ff979394..c37981255b864 100644 --- a/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart @@ -136,7 +136,7 @@ void main() { expect(await device.stopApp(null), isFalse); await expectLater(() => device.startApp(null, debuggingOptions: null), throwsA(isA<UnimplementedError>())); - await expectLater(() => device.buildForDevice(null, buildInfo: BuildInfo.debug), throwsA(isA<UnimplementedError>())); + await expectLater(() => device.buildForDevice(null), throwsA(isA<UnimplementedError>())); expect(device.executablePathForDevice(null, null), null); }); } diff --git a/packages/flutter_tools/test/general.shard/macos/xcode_test.dart b/packages/flutter_tools/test/general.shard/macos/xcode_test.dart index 8c79acb033aaa..9546cc08d01f5 100644 --- a/packages/flutter_tools/test/general.shard/macos/xcode_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/xcode_test.dart @@ -148,7 +148,7 @@ void main() { testWithoutContext('xcodeVersionSatisfactory is true when version meets minimum', () { xcodeProjectInterpreter.isInstalled = true; - xcodeProjectInterpreter.version = Version(12, 3, null); + xcodeProjectInterpreter.version = Version(12, 0, 1); expect(xcode.isRequiredVersionSatisfactory, isTrue); }); @@ -162,21 +162,21 @@ void main() { testWithoutContext('xcodeVersionSatisfactory is true when minor version exceeds minimum', () { xcodeProjectInterpreter.isInstalled = true; - xcodeProjectInterpreter.version = Version(12, 5, 0); + xcodeProjectInterpreter.version = Version(12, 3, 0); expect(xcode.isRequiredVersionSatisfactory, isTrue); }); testWithoutContext('xcodeVersionSatisfactory is true when patch version exceeds minimum', () { xcodeProjectInterpreter.isInstalled = true; - xcodeProjectInterpreter.version = Version(12, 3, 1); + xcodeProjectInterpreter.version = Version(12, 0, 2); expect(xcode.isRequiredVersionSatisfactory, isTrue); }); testWithoutContext('isRecommendedVersionSatisfactory is false when version is less than minimum', () { xcodeProjectInterpreter.isInstalled = true; - xcodeProjectInterpreter.version = Version(12, null, null); + xcodeProjectInterpreter.version = Version(11, 0, 0); expect(xcode.isRecommendedVersionSatisfactory, isFalse); }); @@ -232,7 +232,7 @@ void main() { testWithoutContext('isInstalledAndMeetsVersionCheck is true when macOS and installed and version is satisfied', () { xcodeProjectInterpreter.isInstalled = true; - xcodeProjectInterpreter.version = Version(12, 3, null); + xcodeProjectInterpreter.version = Version(12, 0, 1); expect(xcode.isInstalledAndMeetsVersionCheck, isTrue); expect(fakeProcessManager.hasRemainingExpectations, isFalse); diff --git a/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart b/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart index 4a8451e2e5a4d..6799262baebb5 100644 --- a/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart @@ -56,20 +56,20 @@ void main() { final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.partial); expect(result.messages.last.type, ValidationMessageType.error); - expect(result.messages.last.message, contains('Flutter requires a minimum Xcode version of 12.3')); + expect(result.messages.last.message, contains('Flutter requires a minimum Xcode version of 12.0.1')); }); testWithoutContext('Emits partial status when Xcode below recommended version', () async { final ProcessManager processManager = FakeProcessManager.any(); final Xcode xcode = Xcode.test( processManager: processManager, - xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: Version(12, 4, null)), + xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: Version(12, 0, 1)), ); final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.partial); expect(result.messages.last.type, ValidationMessageType.hint); - expect(result.messages.last.message, contains('Flutter recommends a minimum Xcode version of 13')); + expect(result.messages.last.message, contains('Flutter recommends a minimum Xcode version of 13.0.0')); }); testWithoutContext('Emits partial status when Xcode EULA not signed', () async { diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart index a51ffc89a366d..f6ee05aef179e 100644 --- a/packages/flutter_tools/test/general.shard/plugins_test.dart +++ b/packages/flutter_tools/test/general.shard/plugins_test.dart @@ -16,7 +16,7 @@ import 'package:flutter_tools/src/base/utils.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/flutter_manifest.dart'; import 'package:flutter_tools/src/flutter_plugins.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/plugins.dart'; import 'package:flutter_tools/src/project.dart'; @@ -30,46 +30,6 @@ import '../src/context.dart'; import '../src/fakes.dart' hide FakeOperatingSystemUtils; import '../src/pubspec_schema.dart'; -/// Information for a platform entry in the 'platforms' section of a plugin's -/// pubspec.yaml. -class _PluginPlatformInfo { - const _PluginPlatformInfo({ - this.pluginClass, - this.dartPluginClass, - this.androidPackage, - this.fileName - }) : assert(pluginClass != null || dartPluginClass != null), - assert(androidPackage == null || pluginClass != null); - - /// The pluginClass entry, if any. - final String pluginClass; - - /// The dartPluginClass entry, if any. - final String dartPluginClass; - - /// The package entry for an Android plugin implementation using pluginClass. - final String androidPackage; - - /// The fileName entry for a web plugin implementation. - final String fileName; - - /// Returns the body of a platform section for a plugin's pubspec, properly - /// indented. - String get indentedPubspecSection { - const String indentation = ' '; - return <String>[ - if (pluginClass != null) - '${indentation}pluginClass: $pluginClass', - if (dartPluginClass != null) - '${indentation}dartPluginClass: $dartPluginClass', - if (androidPackage != null) - '${indentation}package: $androidPackage', - if (fileName != null) - '${indentation}fileName: $fileName', - ].join('\n'); - } -} - void main() { group('plugins', () { FileSystem fs; @@ -371,7 +331,7 @@ flutter: ); } - Directory createLegacyPluginWithDependencies({ + Directory createPluginWithDependencies({ @required String name, @required List<String> dependencies, }) { @@ -387,44 +347,6 @@ flutter: plugin: androidPackage: plugin2 pluginClass: UseNewEmbedding -dependencies: -'''); - for (final String dependency in dependencies) { - pluginDirectory - .childFile('pubspec.yaml') - .writeAsStringSync(' $dependency:\n', mode: FileMode.append); - } - flutterProject.directory - .childFile('.packages') - .writeAsStringSync( - '$name:${pluginDirectory.childDirectory('lib').uri.toString()}\n', - mode: FileMode.append, - ); - return pluginDirectory; - } - - Directory createPlugin({ - @required String name, - @required Map<String, _PluginPlatformInfo> platforms, - List<String> dependencies = const <String>[], - }) { - assert(name != null); - assert(dependencies != null); - - final Iterable<String> platformSections = platforms.entries.map((MapEntry<String, _PluginPlatformInfo> entry) => ''' - ${entry.key}: -${entry.value.indentedPubspecSection} -'''); - final Directory pluginDirectory = fs.systemTempDirectory.createTempSync('flutter_plugin.'); - pluginDirectory - .childFile('pubspec.yaml') - .writeAsStringSync(''' -name: $name -flutter: - plugin: - platforms: -${platformSections.join('\n')} - dependencies: '''); for (final String dependency in dependencies) { @@ -498,9 +420,9 @@ dependencies: testUsingContext( 'Refreshing the plugin list modifies .flutter-plugins ' 'and .flutter-plugins-dependencies when there are plugins', () async { - final Directory pluginA = createLegacyPluginWithDependencies(name: 'plugin-a', dependencies: const <String>['plugin-b', 'plugin-c', 'random-package']); - final Directory pluginB = createLegacyPluginWithDependencies(name: 'plugin-b', dependencies: const <String>['plugin-c']); - final Directory pluginC = createLegacyPluginWithDependencies(name: 'plugin-c', dependencies: const <String>[]); + final Directory pluginA = createPluginWithDependencies(name: 'plugin-a', dependencies: const <String>['plugin-b', 'plugin-c', 'random-package']); + final Directory pluginB = createPluginWithDependencies(name: 'plugin-b', dependencies: const <String>['plugin-c']); + final Directory pluginC = createPluginWithDependencies(name: 'plugin-c', dependencies: const <String>[]); iosProject.testExists = true; final DateTime dateCreated = DateTime(1970); @@ -527,25 +449,22 @@ dependencies: <String, dynamic> { 'name': 'plugin-a', 'path': '${pluginA.path}/', - 'native_build': true, 'dependencies': <String>[ 'plugin-b', 'plugin-c' - ], + ] }, <String, dynamic> { 'name': 'plugin-b', 'path': '${pluginB.path}/', - 'native_build': true, 'dependencies': <String>[ 'plugin-c' - ], + ] }, <String, dynamic> { 'name': 'plugin-c', 'path': '${pluginC.path}/', - 'native_build': true, - 'dependencies': <String>[], + 'dependencies': <String>[] }, ]; expect(plugins['ios'], expectedPlugins); @@ -595,51 +514,6 @@ dependencies: FlutterVersion: () => flutterVersion }); - testUsingContext( - '.flutter-plugins-dependencies indicates native build inclusion', () async { - createPlugin( - name: 'plugin-a', - platforms: const <String, _PluginPlatformInfo>{ - // Native-only; should include native build. - 'android': _PluginPlatformInfo(pluginClass: 'Foo', androidPackage: 'bar.foo'), - // Hybrid native and Dart; should include native build. - 'ios': _PluginPlatformInfo(pluginClass: 'Foo', dartPluginClass: 'Bar'), - // Web; should not have the native build key at all since it doesn't apply. - 'web': _PluginPlatformInfo(pluginClass: 'Foo', fileName: 'lib/foo.dart'), - // Dart-only; should not include native build. - 'windows': _PluginPlatformInfo(dartPluginClass: 'Foo'), - }); - iosProject.testExists = true; - - final DateTime dateCreated = DateTime(1970); - systemClock.currentTime = dateCreated; - - await refreshPluginsList(flutterProject); - - expect(flutterProject.flutterPluginsDependenciesFile.existsSync(), true); - final String pluginsString = flutterProject.flutterPluginsDependenciesFile.readAsStringSync(); - final Map<String, dynamic> jsonContent = json.decode(pluginsString) as Map<String, dynamic>; - final Map<String, dynamic> plugins = jsonContent['plugins'] as Map<String, dynamic>; - - // Extracts the native_build key (if any) from the first plugin for the - // given platform. - bool getNativeBuildValue(String platform) { - final List<Map<String, dynamic>> platformPlugins = (plugins[platform] - as List<dynamic>).cast<Map<String, dynamic>>(); - expect(platformPlugins.length, 1); - return platformPlugins[0]['native_build'] as bool; - } - expect(getNativeBuildValue('android'), true); - expect(getNativeBuildValue('ios'), true); - expect(getNativeBuildValue('web'), null); - expect(getNativeBuildValue('windows'), false); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - SystemClock: () => systemClock, - FlutterVersion: () => flutterVersion - }); - testUsingContext('Changes to the plugin list invalidates the Cocoapod lockfiles', () async { simulatePodInstallRun(iosProject); simulatePodInstallRun(macosProject); @@ -873,7 +747,7 @@ dependencies: .childFile('GeneratedPluginRegistrant.java'); expect(registrant.readAsStringSync(), contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));')); - expect(testLogger.warningText, equals( + expect(testLogger.errorText, equals( 'The plugin `plugin3` uses a deprecated version of the Android embedding.\n' 'To avoid unexpected runtime failures, or future build failures, try to see if this plugin supports the Android V2 embedding. ' 'Otherwise, consider removing it since a future release of Flutter will remove these deprecated APIs.\n' @@ -953,7 +827,7 @@ dependencies: await injectPlugins(flutterProject, androidPlatform: true); - expect(testLogger.warningText, equals( + expect(testLogger.errorText, equals( 'This app is using a deprecated version of the Android embedding.\n' 'To avoid unexpected runtime failures, or future build failures, try to migrate this app to the V2 embedding.\n' 'Take a look at the docs for migrating an app: https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects\n' @@ -980,7 +854,7 @@ dependencies: contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));')); expect(registrant.readAsStringSync(), contains('plugin4.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin4.UseOldEmbedding"));')); - expect(testLogger.warningText, equals( + expect(testLogger.errorText, equals( 'The plugins `plugin3, plugin4` use a deprecated version of the Android embedding.\n' 'To avoid unexpected runtime failures, or future build failures, try to see if these plugins support the Android V2 embedding. ' 'Otherwise, consider removing them since a future release of Flutter will remove these deprecated APIs.\n' @@ -1008,7 +882,7 @@ dependencies: contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));')); expect(registrant.readAsStringSync(), contains('plugin4.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin4.UseOldEmbedding"));')); - expect(testLogger.warningText, equals( + expect(testLogger.errorText, equals( 'The plugins `plugin3, plugin4` use a deprecated version of the Android embedding.\n' 'To avoid unexpected runtime failures, or future build failures, try to see if these plugins support the Android V2 embedding. ' 'Otherwise, consider removing them since a future release of Flutter will remove these deprecated APIs.\n' @@ -1758,11 +1632,6 @@ class FakeAndroidProject extends Fake implements AndroidProject { AndroidEmbeddingVersion getEmbeddingVersion() { return embeddingVersion; } - - @override - AndroidEmbeddingVersionResult computeEmbeddingVersion() { - return AndroidEmbeddingVersionResult(embeddingVersion, 'reasons for version'); - } } class FakeWebProject extends Fake implements WebProject { diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index 0214d3d8475f4..066158c5df7dc 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -14,7 +14,7 @@ import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/flutter_manifest.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/plist_parser.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/project.dart'; @@ -182,47 +182,9 @@ void main() { // v1 embedding, as opposed to having <meta-data // android:name="flutterEmbedding" android:value="2" />. - project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.ignore); - expect(testLogger.statusText, contains('https://flutter.dev/go/android-project-migration')); - }); - _testInMemory('Android project not on v2 embedding exits', () async { - final FlutterProject project = await someProject(); - // The default someProject with an empty <manifest> already indicates - // v1 embedding, as opposed to having <meta-data - // android:name="flutterEmbedding" android:value="2" />. - - await expectToolExitLater( - Future<dynamic>.sync(() => project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.exit)), - contains('Build failed due to use of deprecated Android v1 embedding.') - ); - expect(testLogger.statusText, contains('https://flutter.dev/go/android-project-migration')); - expect(testLogger.statusText, contains('No `<meta-data android:name="flutterEmbedding" android:value="2"/>` in ')); - }); - _testInMemory('Project not on v2 embedding does not warn if deprecation status is irrelevant', () async { - final FlutterProject project = await someProject(); - // The default someProject with an empty <manifest> already indicates - // v1 embedding, as opposed to having <meta-data - // android:name="flutterEmbedding" android:value="2" />. - - project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.none); - expect(testLogger.statusText, isEmpty); - }); - _testInMemory('Android project not on v2 embedding ignore continues', () async { - final FlutterProject project = await someProject(); - // The default someProject with an empty <manifest> already indicates - // v1 embedding, as opposed to having <meta-data - // android:name="flutterEmbedding" android:value="2" />. - - project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.ignore); + await project.regeneratePlatformSpecificTooling(); expect(testLogger.statusText, contains('https://flutter.dev/go/android-project-migration')); }); - _testInMemory('Android plugin project does not throw v1 embedding deprecation warning', () async { - final FlutterProject project = await aPluginProject(); - - project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.exit); - expect(testLogger.statusText, isNot(contains('https://flutter.dev/go/android-project-migration'))); - expect(testLogger.statusText, isNot(contains('No `<meta-data android:name="flutterEmbedding" android:value="2"/>` in '))); - }); _testInMemory('Android plugin without example app does not show a warning', () async { final FlutterProject project = await aPluginProject(); project.example.directory.deleteSync(); @@ -996,7 +958,7 @@ String gradleFileWithApplicationId(String id) { return ''' apply plugin: 'com.android.application' android { - compileSdkVersion 31 + compileSdkVersion 30 defaultConfig { applicationId '$id' @@ -1013,7 +975,7 @@ version '1.0-SNAPSHOT' apply plugin: 'com.android.library' android { - compileSdkVersion 31 + compileSdkVersion 30 } '''; } diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 6b7f7b5554826..f6adc3df654fd 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -26,7 +26,7 @@ import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device_port_forwarder.dart'; import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/resident_devtools_handler.dart'; import 'package:flutter_tools/src/resident_runner.dart'; @@ -906,7 +906,7 @@ void main() { Usage: () => TestUsage(), })); - testUsingContext('ResidentRunner can remove breakpoints and exception-pause-mode from paused isolate during hot restart', () => testbed.run(() async { + testUsingContext('ResidentRunner can remove breakpoints from paused isolate during hot restart', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[ listViews, listViews, @@ -922,13 +922,6 @@ void main() { method: 'getVM', jsonResponse: vm_service.VM.parse(<String, Object>{}).toJson(), ), - const FakeVmServiceRequest( - method: 'setIsolatePauseMode', - args: <String, String>{ - 'isolateId': '1', - 'exceptionPauseMode': 'None', - } - ), const FakeVmServiceRequest( method: 'removeBreakpoint', args: <String, String>{ diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index f1cd3c5837e7c..46781731141a2 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -22,7 +22,7 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/isolated/devfs_web.dart'; import 'package:flutter_tools/src/isolated/resident_web_runner.dart'; import 'package:flutter_tools/src/project.dart'; diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart index c9d879527faaa..e44b23693ddaf 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart @@ -11,7 +11,7 @@ import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/runner/flutter_command_runner.dart'; import 'package:flutter_tools/src/version.dart'; diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart index 6a05f0e6850e0..77a09dd8b7edb 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart @@ -116,7 +116,7 @@ void main() { final CommandRunner<void> runner = createTestCommandRunner(flutterCommand); await runner.run(<String>['deprecated']); - expect(testLogger.warningText, + expect(testLogger.errorText, contains('The "deprecated" command is deprecated and will be removed in ' 'a future version of Flutter.')); expect(flutterCommand.usage, diff --git a/packages/flutter_tools/test/general.shard/runner/runner_test.dart b/packages/flutter_tools/test/general.shard/runner/runner_test.dart index ef5e1200e1777..457edc36f739d 100644 --- a/packages/flutter_tools/test/general.shard/runner/runner_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/runner_test.dart @@ -12,18 +12,16 @@ import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart' as io; -import 'package:flutter_tools/src/base/net.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/reporting/crash_reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import '../../src/common.dart'; import '../../src/context.dart'; -import '../../src/fake_http_client.dart'; const String kCustomBugInstructions = 'These are instructions to report with a custom bug tracker.'; @@ -98,7 +96,6 @@ void main() { ProcessManager: () => FakeProcessManager.any(), Usage: () => CrashingUsage(), Artifacts: () => Artifacts.test(), - HttpClientFactory: () => () => FakeHttpClient.any() }); // This Completer completes when CrashingFlutterCommand.runCommand @@ -141,20 +138,9 @@ void main() { ProcessManager: () => FakeProcessManager.any(), CrashReporter: () => WaitingCrashReporter(commandCompleter.future), Artifacts: () => Artifacts.test(), - HttpClientFactory: () => () => FakeHttpClient.any() }); testUsingContext('create local report', () async { - // Since crash reporting calls the doctor, which checks for the devtools - // version file in the cache, write a version file to the memory fs. - Cache.flutterRoot = '/path/to/flutter'; - final Directory devtoolsDir = globals.fs.directory( - '${Cache.flutterRoot}/bin/cache/dart-sdk/bin/resources/devtools', - )..createSync(recursive: true); - devtoolsDir.childFile('version.json').writeAsStringSync( - '{"version": "1.2.3"}', - ); - final Completer<void> completer = Completer<void>(); // runner.run() asynchronously calls the exit function set above, so we // catch it in a zone. @@ -198,7 +184,7 @@ void main() { expect(sentDetails.command, 'flutter crash'); expect(sentDetails.error, 'an exception % --'); expect(sentDetails.stackTrace.toString(), contains('CrashingFlutterCommand.runCommand')); - expect(await sentDetails.doctorText.text, contains('[✓] Flutter')); + expect(sentDetails.doctorText, contains('[✓] Flutter')); }, overrides: <Type, Generator>{ Platform: () => FakePlatform( environment: <String, String>{ @@ -210,8 +196,7 @@ void main() { ProcessManager: () => FakeProcessManager.any(), UserMessages: () => CustomBugInstructions(), Artifacts: () => Artifacts.test(), - CrashReporter: () => WaitingCrashReporter(Future<void>.value()), - HttpClientFactory: () => () => FakeHttpClient.any() + CrashReporter: () => WaitingCrashReporter(Future<void>.value()) }); }); } diff --git a/packages/flutter_tools/test/general.shard/template_test.dart b/packages/flutter_tools/test/general.shard/template_test.dart index 2a66a30d1cd6f..9d007a7efa00b 100644 --- a/packages/flutter_tools/test/general.shard/template_test.dart +++ b/packages/flutter_tools/test/general.shard/template_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. -import 'dart:typed_data'; - import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -43,80 +41,29 @@ void main() { throwsToolExit()); }); - group('renders template', () { - late Directory destination; + testWithoutContext('Template.render replaces .img.tmpl files with files from the image source', () { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final Directory templateDir = fileSystem.directory('templates'); + final Directory imageSourceDir = fileSystem.directory('template_images'); + final Directory destination = fileSystem.directory('target'); const String imageName = 'some_image.png'; - late File sourceImage; - late BufferLogger logger; - late Template template; - - setUp(() { - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - final Directory templateDir = fileSystem.directory('templates'); - final Directory imageSourceDir = fileSystem.directory('template_images'); - destination = fileSystem.directory('target'); - templateDir.childFile('$imageName.img.tmpl').createSync(recursive: true); - sourceImage = imageSourceDir.childFile(imageName); - sourceImage.createSync(recursive: true); - sourceImage.writeAsStringSync("Ceci n'est pas une pipe"); - - logger = BufferLogger.test(); - template = Template( - templateDir, - imageSourceDir, - fileSystem: fileSystem, - logger: logger, - templateRenderer: FakeTemplateRenderer(), - ); - }); - - testWithoutContext('overwrites .img.tmpl files with files from the image source', () { - expect(template.render(destination, <String, Object>{}), 1); - - final File destinationImage = destination.childFile(imageName); - final Uint8List sourceImageBytes = sourceImage.readAsBytesSync(); - expect(destinationImage, exists); - expect(destinationImage.readAsBytesSync(), equals(sourceImageBytes)); - - expect(logger.errorText, isEmpty); - expect(logger.statusText, contains('${destinationImage.path} (created)')); - logger.clear(); - - // Run it again to overwrite (returns 1 file updated). - expect(template.render(destination, <String, Object>{}), 1); - - expect(destinationImage.readAsBytesSync(), equals(sourceImageBytes)); - expect(logger.errorText, isEmpty); - expect(logger.statusText, contains('${destinationImage.path} (overwritten)')); - }); - - testWithoutContext('does not overwrite .img.tmpl files with files from the image source', () { - expect(template.render(destination, <String, Object>{}), 1); - - final File destinationImage = destination.childFile(imageName); - expect(destinationImage, exists); + templateDir.childFile('$imageName.img.tmpl').createSync(recursive: true); + final File sourceImage = imageSourceDir.childFile(imageName); + sourceImage.createSync(recursive: true); + sourceImage.writeAsStringSync("Ceci n'est pas une pipe"); - expect(logger.errorText, isEmpty); - expect(logger.statusText, contains('${destinationImage.path} (created)')); - logger.clear(); - - // Run it again, do not overwrite (returns 0 files updated). - expect(template.render(destination, <String, Object>{}, overwriteExisting: false), 0); - - expect(destinationImage, exists); - expect(logger.errorText, isEmpty); - expect(logger.statusText, isEmpty); - }); - - testWithoutContext('can suppress file printing', () { - template.render(destination, <String, Object>{}, printStatusWhenWriting: false); - - final File destinationImage = destination.childFile(imageName); - expect(destinationImage, exists); + final Template template = Template( + templateDir, + imageSourceDir, + fileSystem: fileSystem, + logger: BufferLogger.test(), + templateRenderer: FakeTemplateRenderer(), + ); + template.render(destination, <String, Object>{}); - expect(logger.errorText, isEmpty); - expect(logger.statusText, isEmpty); - }); + final File destinationImage = destination.childFile(imageName); + expect(destinationImage, exists); + expect(destinationImage.readAsBytesSync(), equals(sourceImage.readAsBytesSync())); }); } diff --git a/packages/flutter_tools/test/general.shard/testbed_test.dart b/packages/flutter_tools/test/general.shard/testbed_test.dart index d34211df7d1f1..77f89cbda5bcc 100644 --- a/packages/flutter_tools/test/general.shard/testbed_test.dart +++ b/packages/flutter_tools/test/general.shard/testbed_test.dart @@ -13,7 +13,7 @@ import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/error_handling_io.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/process.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../src/common.dart'; import '../src/testbed.dart'; diff --git a/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart b/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart index 04d0b9e67ac71..f4e7ae8acf783 100644 --- a/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart +++ b/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart @@ -36,6 +36,7 @@ void main() { final FlutterTesterApp app = FlutterTesterApp.fromCurrentDirectory(fileSystem); expect(app.name, 'my_project'); + expect(app.packagesFile.path, fileSystem.path.join(projectPath, '.packages')); }); group('FlutterTesterDevices', () { diff --git a/packages/flutter_tools/test/general.shard/tracing_test.dart b/packages/flutter_tools/test/general.shard/tracing_test.dart index 3d654c4a41972..fa0804fee5776 100644 --- a/packages/flutter_tools/test/general.shard/tracing_test.dart +++ b/packages/flutter_tools/test/general.shard/tracing_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -88,19 +90,19 @@ void main() { vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFlutterEngineMainEnterEventName, 'ts': 0, - })!, + }), vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFrameworkInitEventName, 'ts': 1, - })!, + }), vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFirstFrameBuiltEventName, 'ts': 2, - })!, + }), vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFirstFrameRasterizedEventName, 'ts': 3, - })!, + }), ], ).toJson(), ), @@ -195,11 +197,11 @@ void main() { vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFlutterEngineMainEnterEventName, 'ts': 0, - })!, + }), vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFrameworkInitEventName, 'ts': 1, - })!, + }), ], ).toJson(), ), @@ -230,11 +232,11 @@ void main() { vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFlutterEngineMainEnterEventName, 'ts': 0, - })!, + }), vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFrameworkInitEventName, 'ts': 1, - })!, + }), ], ).toJson(), ), @@ -275,19 +277,19 @@ void main() { vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFlutterEngineMainEnterEventName, 'ts': 0, - })!, + }), vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFrameworkInitEventName, 'ts': 1, - })!, + }), vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFirstFrameBuiltEventName, 'ts': 2, - })!, + }), vm_service.TimelineEvent.parse(<String, Object>{ 'name': kFirstFrameRasterizedEventName, 'ts': 3, - })!, + }), ], ).toJson(), ), @@ -308,25 +310,25 @@ void main() { logger: logger, ); - final Map<String, Object> expectedTimeline = <String, Object>{ + final Map<String, dynamic> expectedTimeline = <String, dynamic>{ 'type': 'Timeline', - 'traceEvents': <Object>[ - <String, Object>{ + 'traceEvents': <dynamic>[ + <String, dynamic>{ 'name': 'FlutterEngineMainEnter', 'ts': 0, 'type': 'TimelineEvent', }, - <String, Object>{ + <String, dynamic>{ 'name': 'Framework initialization', 'ts': 1, 'type': 'TimelineEvent', }, - <String, Object>{ + <String, dynamic>{ 'name': 'Widgets built first useful frame', 'ts': 2, 'type': 'TimelineEvent', }, - <String, Object>{ + <String, dynamic>{ 'name': 'Rasterized first useful frame', 'ts': 3, 'type': 'TimelineEvent', diff --git a/packages/flutter_tools/test/general.shard/update_packages_test.dart b/packages/flutter_tools/test/general.shard/update_packages_test.dart index 74e191cfc5be1..0a422c30b637a 100644 --- a/packages/flutter_tools/test/general.shard/update_packages_test.dart +++ b/packages/flutter_tools/test/general.shard/update_packages_test.dart @@ -79,36 +79,36 @@ dependencies: '''; void main() { - FileSystem fileSystem; - Directory flutterSdk; - Directory flutter; + testWithoutContext('createTemporaryFlutterSdk creates an unpinned flutter SDK', () { + final FileSystem fileSystem = MemoryFileSystem.test(); - setUp(() { - fileSystem = MemoryFileSystem.test(); // Setup simplified Flutter SDK. - flutterSdk = fileSystem.directory('flutter')..createSync(); + final Directory flutterSdk = fileSystem.directory('flutter') + ..createSync(); // Create version file flutterSdk.childFile('version').writeAsStringSync('1.2.3'); // Create a pubspec file - flutter = flutterSdk.childDirectory('packages').childDirectory('flutter') + final Directory flutter = flutterSdk + .childDirectory('packages') + .childDirectory('flutter') ..createSync(recursive: true); - flutter.childFile('pubspec.yaml').writeAsStringSync(kFlutterPubspecYaml); - }); + flutter + .childFile('pubspec.yaml') + .writeAsStringSync(kFlutterPubspecYaml); - testWithoutContext( - 'createTemporaryFlutterSdk creates an unpinned flutter SDK', () { // A stray extra package should not cause a crash. final Directory extra = flutterSdk - .childDirectory('packages') - .childDirectory('extra') + .childDirectory('packages') + .childDirectory('extra') ..createSync(recursive: true); - extra.childFile('pubspec.yaml').writeAsStringSync(kExtraPubspecYaml); + extra + .childFile('pubspec.yaml') + .writeAsStringSync(kExtraPubspecYaml); // Create already parsed pubspecs. final PubspecYaml flutterPubspec = PubspecYaml(flutter); - final PubspecDependency gitDependency = flutterPubspec.dependencies - .firstWhere((PubspecDependency dep) => dep.kind == DependencyKind.git); + final PubspecDependency gitDependency = flutterPubspec.dependencies.whereType<PubspecDependency>().firstWhere((PubspecDependency dep) => dep.kind == DependencyKind.git); expect( gitDependency.lockLine, ''' @@ -129,7 +129,7 @@ void main() { // We get a warning about the unexpected package. expect( - bufferLogger.warningText, + bufferLogger.errorText, contains("Unexpected package 'extra' found in packages directory"), ); @@ -152,57 +152,25 @@ void main() { }); testWithoutContext('Throws a StateError on a malformed git: reference', () { - // Create an invalid pubspec file. - flutter.childFile('pubspec.yaml').writeAsStringSync(kInvalidGitPubspec); + final FileSystem fileSystem = MemoryFileSystem.test(); + + // Setup simplified Flutter SDK. + final Directory flutterSdk = fileSystem.directory('flutter') + ..createSync(); + // Create version file + flutterSdk.childFile('version').writeAsStringSync('1.2.3'); + // Create a pubspec file + final Directory flutter = flutterSdk + .childDirectory('packages') + .childDirectory('flutter') + ..createSync(recursive: true); + flutter + .childFile('pubspec.yaml') + .writeAsStringSync(kInvalidGitPubspec); expect( () => PubspecYaml(flutter), throwsStateError, ); }); - - testWithoutContext('PubspecYaml Loads dependencies', () async { - final PubspecYaml pubspecYaml = PubspecYaml(flutter); - expect( - pubspecYaml.allDependencies - .map<String>((PubspecDependency dependency) => '${dependency.name}: ${dependency.version}') - .toSet(), - equals(<String>{ - 'collection: 1.14.11', - 'meta: 1.1.8', - 'typed_data: 1.1.6', - 'vector_math: 2.0.8', - 'sky_engine: ', - 'gallery: ', - 'flutter_test: ', - 'flutter_goldens: ', - 'archive: 2.0.11', - })); - expect( - pubspecYaml.allExplicitDependencies - .map<String>((PubspecDependency dependency) => '${dependency.name}: ${dependency.version}') - .toSet(), - equals(<String>{ - 'collection: 1.14.11', - 'meta: 1.1.8', - 'typed_data: 1.1.6', - 'vector_math: 2.0.8', - 'sky_engine: ', - 'gallery: ', - 'flutter_test: ', - 'flutter_goldens: ' - })); - expect( - pubspecYaml.dependencies - .map<String>((PubspecDependency dependency) => '${dependency.name}: ${dependency.version}') - .toSet(), - equals(<String>{ - 'collection: 1.14.11', - 'meta: 1.1.8', - 'typed_data: 1.1.6', - 'vector_math: 2.0.8', - 'sky_engine: ', - 'gallery: ' - })); - }); } diff --git a/packages/flutter_tools/test/general.shard/version_test.dart b/packages/flutter_tools/test/general.shard/version_test.dart index af66ab95b7bf7..ba1ef1c223be2 100644 --- a/packages/flutter_tools/test/general.shard/version_test.dart +++ b/packages/flutter_tools/test/general.shard/version_test.dart @@ -11,7 +11,7 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/base/time.dart'; import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/version.dart'; import 'package:test/fake.dart'; @@ -20,8 +20,8 @@ import '../src/context.dart'; import '../src/fake_process_manager.dart'; final SystemClock _testClock = SystemClock.fixed(DateTime(2015)); -final DateTime _stampUpToDate = _testClock.ago(VersionFreshnessValidator.checkAgeConsideredUpToDate ~/ 2); -final DateTime _stampOutOfDate = _testClock.ago(VersionFreshnessValidator.checkAgeConsideredUpToDate * 2); +final DateTime _stampUpToDate = _testClock.ago(checkAgeConsideredUpToDate ~/ 2); +final DateTime _stampOutOfDate = _testClock.ago(checkAgeConsideredUpToDate * 2); void main() { FakeCache cache; @@ -42,17 +42,17 @@ void main() { for (final String channel in kOfficialChannels) { DateTime getChannelUpToDateVersion() { - return _testClock.ago(VersionFreshnessValidator.versionAgeConsideredUpToDate(channel) ~/ 2); + return _testClock.ago(versionAgeConsideredUpToDate(channel) ~/ 2); } DateTime getChannelOutOfDateVersion() { - return _testClock.ago(VersionFreshnessValidator.versionAgeConsideredUpToDate(channel) * 2); + return _testClock.ago(versionAgeConsideredUpToDate(channel) * 2); } group('$FlutterVersion for $channel', () { setUpAll(() { Cache.disableLocking(); - VersionFreshnessValidator.timeToPauseToLetUserReadTheMessage = Duration.zero; + timeToPauseToLetUserReadTheMessage = Duration.zero; }); testUsingContext('prints nothing when Flutter installation looks fresh', () async { @@ -126,7 +126,7 @@ void main() { 'Flutter • channel $channel • unknown source\n' 'Framework • revision 1234abcd (1 second ago) • ${getChannelUpToDateVersion()}\n' 'Engine • revision abcdefg\n' - 'Tools • Dart 2.12.0 • DevTools 2.8.0', + 'Tools • Dart 2.12.0', ); expect(flutterVersion.frameworkAge, '1 second ago'); expect(flutterVersion.getVersionString(), '$channel/1234abcd'); @@ -151,14 +151,14 @@ void main() { ); cache.versionStamp = json.encode(stamp); - await VersionFreshnessValidator( - version: flutterVersion, + await checkVersionFreshness( + flutterVersion, cache: cache, clock: _testClock, logger: logger, localFrameworkCommitDate: getChannelOutOfDateVersion(), latestFlutterCommitDate: getChannelOutOfDateVersion(), - ).run(); + ); _expectVersionMessage('', logger); }); @@ -172,14 +172,14 @@ void main() { ); cache.versionStamp = json.encode(stamp); - await VersionFreshnessValidator( - version: flutterVersion, + await checkVersionFreshness( + flutterVersion, cache: cache, clock: _testClock, logger: logger, localFrameworkCommitDate: getChannelOutOfDateVersion(), latestFlutterCommitDate: getChannelUpToDateVersion(), - ).run(); + ); _expectVersionMessage(newVersionAvailableMessage(), logger); expect(cache.setVersionStamp, true); @@ -195,14 +195,14 @@ void main() { ); cache.versionStamp = json.encode(stamp); - await VersionFreshnessValidator( - version: flutterVersion, + await checkVersionFreshness( + flutterVersion, cache: cache, clock: _testClock, logger: logger, localFrameworkCommitDate: getChannelOutOfDateVersion(), latestFlutterCommitDate: getChannelUpToDateVersion(), - ).run(); + ); _expectVersionMessage('', logger); }); @@ -212,14 +212,14 @@ void main() { final BufferLogger logger = BufferLogger.test(); cache.versionStamp = '{}'; - await VersionFreshnessValidator( - version: flutterVersion, + await checkVersionFreshness( + flutterVersion, cache: cache, clock: _testClock, logger: logger, localFrameworkCommitDate: getChannelOutOfDateVersion(), latestFlutterCommitDate: getChannelUpToDateVersion(), - ).run(); + ); _expectVersionMessage(newVersionAvailableMessage(), logger); expect(cache.setVersionStamp, true); @@ -234,14 +234,14 @@ void main() { ); cache.versionStamp = json.encode(stamp); - await VersionFreshnessValidator( - version: flutterVersion, + await checkVersionFreshness( + flutterVersion, cache: cache, clock: _testClock, logger: logger, localFrameworkCommitDate: getChannelOutOfDateVersion(), latestFlutterCommitDate: getChannelUpToDateVersion(), - ).run(); + ); _expectVersionMessage(newVersionAvailableMessage(), logger); }); @@ -251,14 +251,14 @@ void main() { final BufferLogger logger = BufferLogger.test(); cache.versionStamp = '{}'; - await VersionFreshnessValidator( - version: flutterVersion, + await checkVersionFreshness( + flutterVersion, cache: cache, clock: _testClock, logger: logger, localFrameworkCommitDate: getChannelUpToDateVersion(), - // latestFlutterCommitDate defaults to null because we failed to get remote version - ).run(); + latestFlutterCommitDate: null, // Failed to get remote version + ); _expectVersionMessage('', logger); }); @@ -272,14 +272,14 @@ void main() { ); cache.versionStamp = json.encode(stamp); - await VersionFreshnessValidator( - version: flutterVersion, + await checkVersionFreshness( + flutterVersion, cache: cache, clock: _testClock, logger: logger, localFrameworkCommitDate: getChannelOutOfDateVersion(), - // latestFlutterCommitDate defaults to null because we failed to get remote version - ).run(); + latestFlutterCommitDate: null, // Failed to get remote version + ); _expectVersionMessage(versionOutOfDateMessage(_testClock.now().difference(getChannelOutOfDateVersion())), logger); }); @@ -605,9 +605,6 @@ class FakeCache extends Fake implements Cache { @override String get engineRevision => 'abcdefg'; - @override - String get devToolsVersion => '2.8.0'; - @override String get dartSdkVersion => '2.12.0'; diff --git a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart index b9b4e192ad38e..af2e5d36cd001 100644 --- a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart +++ b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart @@ -13,7 +13,7 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/targets/web.dart'; import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/convert.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/isolated/devfs_web.dart'; import 'package:flutter_tools/src/web/compile.dart'; import 'package:package_config/package_config.dart'; @@ -539,30 +539,31 @@ void main() { expect((await response.read().toList()).first, source.readAsBytesSync()); })); - test('serves asset files from in filesystem with known mime type and empty content', () => testbed.run(() async { - final File source = globals.fs.file(globals.fs.path.join('web', 'foo.js')) - ..createSync(recursive: true); + test('serves asset files files from in filesystem with unknown mime type and length > 12', () => testbed.run(() async { + final File source = globals.fs.file(globals.fs.path.join('build', 'flutter_assets', 'foo')) + ..createSync(recursive: true) + ..writeAsBytesSync(List<int>.filled(100, 0)); final Response response = await webAssetServer - .handleRequest(Request('GET', Uri.parse('http://foobar/foo.js'))); + .handleRequest(Request('GET', Uri.parse('http://foobar/assets/foo'))); expect(response.headers, allOf(<Matcher>[ - containsPair(HttpHeaders.contentLengthHeader, '0'), - containsPair(HttpHeaders.contentTypeHeader, 'application/javascript'), + containsPair(HttpHeaders.contentLengthHeader, '100'), + containsPair(HttpHeaders.contentTypeHeader, 'application/octet-stream'), ])); expect((await response.read().toList()).first, source.readAsBytesSync()); })); - test('serves asset files files from in filesystem with unknown mime type', () => testbed.run(() async { + test('serves asset files files from in filesystem with unknown mime type and length < 12', () => testbed.run(() async { final File source = globals.fs.file(globals.fs.path.join('build', 'flutter_assets', 'foo')) ..createSync(recursive: true) - ..writeAsBytesSync(List<int>.filled(100, 0)); + ..writeAsBytesSync(<int>[1, 2, 3]); final Response response = await webAssetServer .handleRequest(Request('GET', Uri.parse('http://foobar/assets/foo'))); expect(response.headers, allOf(<Matcher>[ - containsPair(HttpHeaders.contentLengthHeader, '100'), + containsPair(HttpHeaders.contentLengthHeader, '3'), containsPair(HttpHeaders.contentTypeHeader, 'application/octet-stream'), ])); expect((await response.read().toList()).first, source.readAsBytesSync()); @@ -593,7 +594,7 @@ void main() { expect(response.headers, allOf(<Matcher>[ containsPair(HttpHeaders.contentLengthHeader, '3'), - containsPair(HttpHeaders.contentTypeHeader, 'text/x-dart'), + containsPair(HttpHeaders.contentTypeHeader, 'application/octet-stream'), ])); expect((await response.read().toList()).first, source.readAsBytesSync()); })); diff --git a/packages/flutter_tools/test/general.shard/web/golden_comparator_process_test.dart b/packages/flutter_tools/test/general.shard/web/golden_comparator_process_test.dart index 300747bd2d2fa..cab59d11c410a 100644 --- a/packages/flutter_tools/test/general.shard/web/golden_comparator_process_test.dart +++ b/packages/flutter_tools/test/general.shard/web/golden_comparator_process_test.dart @@ -8,7 +8,7 @@ import 'dart:convert'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/test/flutter_web_goldens.dart'; import '../../src/common.dart'; diff --git a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart index cb428c69e13ff..2335d50477240 100644 --- a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart +++ b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart @@ -39,20 +39,6 @@ const Map<String, dynamic> _defaultResponse = <String, dynamic>{ }, }; -// A minimum version of a response where a VS 2022 installation was found. -const Map<String, dynamic> _vs2022Response = <String, dynamic>{ - 'installationPath': visualStudioPath, - 'displayName': 'Visual Studio Community 2022', - 'installationVersion': '17.0.31903.59', - 'isRebootRequired': false, - 'isComplete': true, - 'isLaunchable': true, - 'isPrerelease': false, - 'catalog': <String, dynamic>{ - 'productDisplayVersion': '17.0.0', - }, -}; - // A minimum version of a response where a Build Tools installation was found. const Map<String, dynamic> _defaultBuildToolsResponse = <String, dynamic>{ 'installationPath': visualStudioPath, @@ -746,7 +732,6 @@ void main() { expect(visualStudio.isAtLeastMinimumVersion, true); expect(visualStudio.hasNecessaryComponents, true); expect(visualStudio.cmakePath, equals(cmakePath)); - expect(visualStudio.cmakeGenerator, equals('Visual Studio 16 2019')); }); testWithoutContext('Everything returns good values when Build Tools is present with all components', () { @@ -770,23 +755,6 @@ void main() { expect(visualStudio.cmakePath, equals(cmakePath)); }); - testWithoutContext('properties return the right value for Visual Studio 2022', () { - final VisualStudioFixture fixture = setUpVisualStudio(); - final VisualStudio visualStudio = fixture.visualStudio; - - setMockCompatibleVisualStudioInstallation( - _vs2022Response, - fixture.fileSystem, - fixture.processManager, - ); - - expect(visualStudio.isInstalled, true); - expect(visualStudio.isAtLeastMinimumVersion, true); - expect(visualStudio.hasNecessaryComponents, true); - expect(visualStudio.cmakePath, equals(cmakePath)); - expect(visualStudio.cmakeGenerator, equals('Visual Studio 17 2022')); - }); - testWithoutContext('Metadata is for compatible version when latest is missing components', () { final VisualStudioFixture fixture = setUpVisualStudio(); final VisualStudio visualStudio = fixture.visualStudio; diff --git a/packages/flutter_tools/test/integration.shard/analyze_once_test.dart b/packages/flutter_tools/test/integration.shard/analyze_once_test.dart index d27868ce9135f..c679cffd9bca6 100644 --- a/packages/flutter_tools/test/integration.shard/analyze_once_test.dart +++ b/packages/flutter_tools/test/integration.shard/analyze_once_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import '../src/common.dart'; @@ -10,12 +12,12 @@ import 'test_utils.dart'; final String analyzerSeparator = platform.isWindows ? '-' : '•'; void main() { - late Directory tempDir; - late String projectPath; - late File libMain; + Directory tempDir; + String projectPath; + File libMain; Future<void> runCommand({ - List<String> arguments = const <String>[], + List<String> arguments, List<String> statusTextContains = const <String>[], List<String> errorTextContains = const <String>[], String exitMessageContains = '', diff --git a/packages/flutter_tools/test/integration.shard/analyze_size_test.dart b/packages/flutter_tools/test/integration.shard/analyze_size_test.dart index 949bf6fe30803..1fe91a542afe7 100644 --- a/packages/flutter_tools/test/integration.shard/analyze_size_test.dart +++ b/packages/flutter_tools/test/integration.shard/analyze_size_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:file/file.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/io.dart'; diff --git a/packages/flutter_tools/test/integration.shard/android_plugin_compilesdkversion_mismatch_test.dart b/packages/flutter_tools/test/integration.shard/android_plugin_compilesdkversion_mismatch_test.dart deleted file mode 100644 index 4ead7e6654329..0000000000000 --- a/packages/flutter_tools/test/integration.shard/android_plugin_compilesdkversion_mismatch_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -// 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 'package:file_testing/file_testing.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/base/io.dart'; -import 'package:flutter_tools/src/cache.dart'; - -import '../src/common.dart'; -import 'test_utils.dart'; - -void main() { - - late Directory tempDir; - - setUp(() { - Cache.flutterRoot = getFlutterRoot(); - tempDir = createResolvedTempDirectorySync('flutter_plugin_test.'); - }); - - tearDown(() async { - tryToDelete(tempDir); - }); - - test('error logged when plugin Android compileSdkVersion higher than project', () async { - final String flutterBin = fileSystem.path.join( - getFlutterRoot(), - 'bin', - 'flutter', - ); - - // Create dummy plugin - processManager.runSync(<String>[ - flutterBin, - ...getLocalEngineArguments(), - 'create', - '--template=plugin', - '--platforms=android', - 'test_plugin', - ], workingDirectory: tempDir.path); - - final Directory pluginAppDir = tempDir.childDirectory('test_plugin'); - final File pluginGradleFile = pluginAppDir.childDirectory('android').childFile('build.gradle'); - expect(pluginGradleFile, exists); - - final String pluginBuildGradle = pluginGradleFile.readAsStringSync(); - - // Bump up plugin compileSdkVersion to 31 - final RegExp androidCompileSdkVersionRegExp = RegExp(r'compileSdkVersion ([0-9]+|flutter.compileSdkVersion)'); - final String newPluginGradleFile = pluginBuildGradle.replaceAll( - androidCompileSdkVersionRegExp, 'compileSdkVersion 31'); - pluginGradleFile.writeAsStringSync(newPluginGradleFile); - - final Directory pluginExampleAppDir = pluginAppDir.childDirectory('example'); - - final File projectGradleFile = pluginExampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle'); - expect(projectGradleFile, exists); - - final String projectBuildGradle = projectGradleFile.readAsStringSync(); - - // Bump down plugin example app compileSdkVersion to 30 - final String newProjectGradleFile = projectBuildGradle.replaceAll( - androidCompileSdkVersionRegExp, 'compileSdkVersion 30'); - projectGradleFile.writeAsStringSync(newProjectGradleFile); - - // Run flutter build apk to build plugin example project - final ProcessResult result = processManager.runSync(<String>[ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'apk', - '--target-platform=android-arm', - ], workingDirectory: pluginExampleAppDir.path); - - // Check error message is thrown - expect(result.stdout, - contains('Warning: The plugin test_plugin requires Android SDK version 31.') - ); - expect(result.stderr, - contains(''' -One or more plugins require a higher Android SDK version. -Fix this issue by adding the following to ${projectGradleFile.path}: -android { - compileSdkVersion 31 - ... -} - -''' - )); - }); -} diff --git a/packages/flutter_tools/test/integration.shard/android_plugin_example_app_build_test.dart b/packages/flutter_tools/test/integration.shard/android_plugin_example_app_build_test.dart index 86ffbd3b8a04b..a39dc1e2934ce 100644 --- a/packages/flutter_tools/test/integration.shard/android_plugin_example_app_build_test.dart +++ b/packages/flutter_tools/test/integration.shard/android_plugin_example_app_build_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -9,7 +11,7 @@ import '../src/common.dart'; import 'test_utils.dart'; void main() { - late Directory tempDir; + Directory tempDir; setUp(() async { tempDir = createResolvedTempDirectorySync('flutter_plugin_test.'); @@ -45,7 +47,7 @@ void main() { RegExp(r'com\.android\.tools\.build:gradle:(\d+\.\d+\.\d+)'); // Use AGP 4.1.0 - final String newBuildGradle = buildGradle.replaceAll( + String newBuildGradle = buildGradle.replaceAll( androidPluginRegExp, 'com.android.tools.build:gradle:4.1.0'); buildGradleFile.writeAsStringSync(newBuildGradle); @@ -81,6 +83,11 @@ void main() { .join(exampleAppDir.path, 'android', 'gradle', 'wrapper')) .deleteSync(recursive: true); + // Use AGP 3.3.0 + newBuildGradle = buildGradle.replaceAll( + androidPluginRegExp, 'com.android.tools.build:gradle:3.3.0'); + buildGradleFile.writeAsStringSync(newBuildGradle); + // Enable R8 in gradle.properties final File gradleProperties = exampleAppDir.childDirectory('android').childFile('gradle.properties'); diff --git a/packages/flutter_tools/test/integration.shard/background_isolate_test.dart b/packages/flutter_tools/test/integration.shard/background_isolate_test.dart index 2ef29372bdcb8..bc1cb9a67f9a7 100644 --- a/packages/flutter_tools/test/integration.shard/background_isolate_test.dart +++ b/packages/flutter_tools/test/integration.shard/background_isolate_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'dart:async'; import 'package:file/file.dart'; @@ -12,7 +14,7 @@ import 'test_driver.dart'; import 'test_utils.dart'; void main() { - late Directory tempDir; + Directory tempDir; setUp(() async { tempDir = createResolvedTempDirectorySync('hot_reload_test.'); @@ -54,8 +56,8 @@ void main() { // Wait a tiny amount of time in case we did not kill the background isolate. await Future<void>.delayed(const Duration(milliseconds: 10)); await subscription.cancel(); - await flutter.stop(); - }, skip: true); // Flake: https://github.com/flutter/flutter/issues/96677 + await flutter?.stop(); + }); testWithoutContext('Hot reload updates background isolates', () async { final RepeatingBackgroundProject project = RepeatingBackgroundProject(); @@ -82,6 +84,6 @@ void main() { await flutter.hotReload(); await sawNewBackgroundMessage.future; await subscription.cancel(); - await flutter.stop(); + await flutter?.stop(); }); } diff --git a/packages/flutter_tools/test/integration.shard/build_ios_config_only_test.dart b/packages/flutter_tools/test/integration.shard/build_ios_config_only_test.dart index 63d1abfe57913..f5adc08a02879 100644 --- a/packages/flutter_tools/test/integration.shard/build_ios_config_only_test.dart +++ b/packages/flutter_tools/test/integration.shard/build_ios_config_only_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; diff --git a/packages/flutter_tools/test/integration.shard/cache_test.dart b/packages/flutter_tools/test/integration.shard/cache_test.dart index 962d02e2f281e..8f155d6c59a85 100644 --- a/packages/flutter_tools/test/integration.shard/cache_test.dart +++ b/packages/flutter_tools/test/integration.shard/cache_test.dart @@ -10,15 +10,12 @@ import 'package:file/file.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:process/process.dart'; -import 'package:test/fake.dart'; import '../src/common.dart'; import '../src/context.dart'; -import '../src/fakes.dart'; import 'test_utils.dart'; final String dart = fileSystem.path @@ -27,122 +24,53 @@ final String dart = fileSystem.path void main() { group('Cache.lock', () { // Windows locking is too flaky for this to work reliably. - if (platform.isWindows) { - return; - } - testWithoutContext( - 'should log a message to stderr when lock is not acquired', () async { - final String oldRoot = Cache.flutterRoot; - final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('cache_test.'); - final BufferLogger logger = BufferLogger( - terminal: Terminal.test(supportsColor: false, supportsEmoji: false), - outputPreferences: OutputPreferences(), - ); - logger.fatalWarnings = true; - try { - Cache.flutterRoot = tempDir.absolute.path; - final Cache cache = Cache.test( - fileSystem: fileSystem, - processManager: FakeProcessManager.any(), - logger: logger, + if (!platform.isWindows) { + testWithoutContext( + 'should log a message to stderr when lock is not acquired', () async { + final String oldRoot = Cache.flutterRoot; + final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('cache_test.'); + final BufferLogger logger = BufferLogger( + terminal: Terminal.test(supportsColor: false, supportsEmoji: false), + outputPreferences: OutputPreferences(), ); - final File cacheFile = fileSystem.file(fileSystem.path - .join(Cache.flutterRoot, 'bin', 'cache', 'lockfile')) - ..createSync(recursive: true); - final File script = fileSystem.file(fileSystem.path - .join(Cache.flutterRoot, 'bin', 'cache', 'test_lock.dart')); - script.writeAsStringSync(r''' + try { + Cache.flutterRoot = tempDir.absolute.path; + final Cache cache = Cache.test( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + ); + final File cacheFile = fileSystem.file(fileSystem.path + .join(Cache.flutterRoot, 'bin', 'cache', 'lockfile')) + ..createSync(recursive: true); + final File script = fileSystem.file(fileSystem.path + .join(Cache.flutterRoot, 'bin', 'cache', 'test_lock.dart')); + script.writeAsStringSync(r''' import 'dart:async'; import 'dart:io'; Future<void> main(List<String> args) async { -File file = File(args[0]); -RandomAccessFile lock = file.openSync(mode: FileMode.write); -lock.lockSync(); -await Future<void>.delayed(const Duration(milliseconds: 1000)); -exit(0); + File file = File(args[0]); + RandomAccessFile lock = file.openSync(mode: FileMode.write); + lock.lockSync(); + await Future<void>.delayed(const Duration(milliseconds: 1000)); + exit(0); } '''); - final Process process = await const LocalProcessManager().start( - <String>[dart, script.absolute.path, cacheFile.absolute.path], - ); - await Future<void>.delayed(const Duration(milliseconds: 500)); - await cache.lock(); - process.kill(io.ProcessSignal.sigkill); - } finally { - tryToDelete(tempDir); - Cache.flutterRoot = oldRoot; - } - expect(logger.statusText, isEmpty); - expect(logger.errorText, isEmpty); - expect(logger.warningText, - equals('Waiting for another flutter command to release the startup lock...\n')); - expect(logger.hadErrorOutput, isFalse); - // Should still be false, since the particular "Waiting..." message above aims to - // avoid triggering failure as a fatal warning. - expect(logger.hadWarningOutput, isFalse); - }); - testWithoutContext( - 'should log a warning message for unknown version ', () async { - final String oldRoot = Cache.flutterRoot; - final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('cache_test.'); - final BufferLogger logger = BufferLogger( - terminal: Terminal.test(supportsColor: false, supportsEmoji: false), - outputPreferences: OutputPreferences(), - ); - logger.fatalWarnings = true; - try { - Cache.flutterRoot = tempDir.absolute.path; - final Cache cache = Cache.test( - fileSystem: fileSystem, - processManager: FakeProcessManager.any(), - logger: logger, - ); - final FakeVersionlessArtifact artifact = FakeVersionlessArtifact(cache); - cache.registerArtifact(artifact); - await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils()); - } finally { - tryToDelete(tempDir); - Cache.flutterRoot = oldRoot; - } - expect(logger.statusText, isEmpty); - expect(logger.warningText, equals('No known version for the artifact name "fake". ' - 'Flutter can continue, but the artifact may be re-downloaded on ' - 'subsequent invocations until the problem is resolved.\n')); - expect(logger.hadErrorOutput, isFalse); - expect(logger.hadWarningOutput, isTrue); - }); + final Process process = await const LocalProcessManager().start( + <String>[dart, script.absolute.path, cacheFile.absolute.path], + ); + await Future<void>.delayed(const Duration(milliseconds: 500)); + await cache.lock(); + process.kill(io.ProcessSignal.sigkill); + } finally { + tryToDelete(tempDir); + Cache.flutterRoot = oldRoot; + } + expect(logger.statusText, isEmpty); + expect(logger.errorText, + equals('Waiting for another flutter command to release the startup lock...\n')); + }); + } }); } - -class FakeArtifactUpdater extends Fake implements ArtifactUpdater { - void Function(String, Uri, Directory) onDownloadZipArchive; - void Function(String, Uri, Directory) onDownloadZipTarball; - - @override - Future<void> downloadZippedTarball(String message, Uri url, Directory location) async { - onDownloadZipTarball?.call(message, url, location); - } - - @override - Future<void> downloadZipArchive(String message, Uri url, Directory location) async { - onDownloadZipArchive?.call(message, url, location); - } - - @override - void removeDownloadedFiles() { } -} - -class FakeVersionlessArtifact extends CachedArtifact { - FakeVersionlessArtifact(Cache cache) : super( - 'fake', - cache, - DevelopmentArtifact.universal, - ); - - @override - String get version => null; - - @override - Future<void> updateInner(ArtifactUpdater artifactUpdater, FileSystem fileSystem, OperatingSystemUtils operatingSystemUtils) async { } -} diff --git a/packages/flutter_tools/test/integration.shard/command_output_test.dart b/packages/flutter_tools/test/integration.shard/command_output_test.dart index 0023ce8753b8e..e1fa2197b8534 100644 --- a/packages/flutter_tools/test/integration.shard/command_output_test.dart +++ b/packages/flutter_tools/test/integration.shard/command_output_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'dart:convert'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -136,11 +138,11 @@ void main() { '--machine', ]); - final Map<String, Object?> versionInfo = json.decode(result.stdout + final Map<String, Object> versionInfo = json.decode(result.stdout .toString() .replaceAll('Building flutter tool...', '') .replaceAll('Waiting for another flutter command to release the startup lock...', '') - .trim()) as Map<String, Object?>; + .trim()) as Map<String, Object>; expect(versionInfo, containsPair('flutterRoot', isNotNull)); }); diff --git a/packages/flutter_tools/test/integration.shard/coverage_collection_test.dart b/packages/flutter_tools/test/integration.shard/coverage_collection_test.dart index 22a52a3a01067..d6bbe45e683b4 100644 --- a/packages/flutter_tools/test/integration.shard/coverage_collection_test.dart +++ b/packages/flutter_tools/test/integration.shard/coverage_collection_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:file/file.dart'; import 'package:file_testing/file_testing.dart'; @@ -12,7 +14,7 @@ import 'test_driver.dart'; import 'test_utils.dart'; void main() { - late Directory tempDir; + Directory tempDir; setUp(() async { tempDir = createResolvedTempDirectorySync('flutter_coverage_collection_test.'); diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart index 5de689234c2bc..f7d76140fd7fd 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart @@ -187,87 +187,6 @@ void main() { await dap.client.terminate(); }); - - testWithoutContext('can hot restart when exceptions occur on outgoing isolates', () async { - final BasicProjectThatThrows _project = BasicProjectThatThrows(); - await _project.setUpIn(tempDir); - - // Launch the app and wait for it to stop at an exception. - int originalThreadId, newThreadId; - await Future.wait(<Future<Object>>[ - // Capture the thread ID of the stopped thread. - dap.client.stoppedEvents.first.then((StoppedEventBody event) => originalThreadId = event.threadId), - dap.client.start( - exceptionPauseMode: 'All', // Ensure we stop on all exceptions - launch: () => dap.client.launch( - cwd: _project.dir.path, - toolArgs: <String>['-d', 'flutter-tester'], - ), - ), - ], eagerError: true); - - // Hot restart, ensuring it completes and capturing the ID of the new thread - // to pause. - await Future.wait(<Future<Object>>[ - // Capture the thread ID of the newly stopped thread. - dap.client.stoppedEvents.first.then((StoppedEventBody event) => newThreadId = event.threadId), - dap.client.hotRestart(), - ], eagerError: true); - - // We should not have stopped on the original thread, but the new thread - // from after the restart. - expect(newThreadId, isNot(equals(originalThreadId))); - - await dap.client.terminate(); - }); - - testWithoutContext('sends events for extension state updates', () async { - final BasicProject _project = BasicProject(); - await _project.setUpIn(tempDir); - const String debugPaintRpc = 'ext.flutter.debugPaint'; - - // Create a future to capture the isolate ID when the debug paint service - // extension loads, as we'll need that to call it later. - final Future<String> isolateIdForDebugPaint = dap.client - .serviceExtensionAdded(debugPaintRpc) - .then((Map<String, Object/*?*/> body) => body['isolateId'] as String); - - // Launch the app and wait for it to print "topLevelFunction" so we know - // it's up and running. - await Future.wait(<Future<Object>>[ - dap.client.outputEvents.firstWhere((OutputEventBody output) => - output.output.startsWith('topLevelFunction')), - dap.client.start( - launch: () => dap.client.launch( - cwd: _project.dir.path, - toolArgs: <String>['-d', 'flutter-tester'], - ), - ), - ], eagerError: true); - - // Capture the next relevant state-change event (which should occur as a - // result of the call below). - final Future<Map<String, Object/*?*/>> stateChangeEventFuture = - dap.client.serviceExtensionStateChanged(debugPaintRpc); - - // Enable debug paint to trigger the state change. - await dap.client.custom( - 'callService', - <String, Object/*?*/>{ - 'method': debugPaintRpc, - 'params': <String, Object/*?*/>{ - 'enabled': true, - 'isolateId': await isolateIdForDebugPaint, - }, - }, - ); - - // Ensure the event occurred, and its value was as expected. - final Map<String, Object/*?*/> stateChangeEvent = await stateChangeEventFuture; - expect(stateChangeEvent['value'], 'true'); // extension state change values are always strings - - await dap.client.terminate(); - }); } /// Extracts the output from a set of [OutputEventBody], removing any diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/test_adapter_test.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/test_adapter_test.dart index 072941093f2c7..7fd6a4d302a22 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/test_adapter_test.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/test_adapter_test.dart @@ -122,8 +122,8 @@ final List<Object> _testsProjectExpectedOutput = <Object>[ '✓ Flutter tests can pass', // Second test '══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════', - 'The following TestFailure was thrown running a test:', - 'Expected: false', + 'The following TestFailure object was thrown running a test:', + ' Expected: false', ' Actual: <true>', '', 'The test description was: can fail', diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/test_client.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/test_client.dart index e0513176fcc21..2359787e73ce5 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/test_client.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/test_client.dart @@ -56,10 +56,6 @@ class DapTestClient { Stream<OutputEventBody> get outputEvents => events('output') .map((Event e) => OutputEventBody.fromJson(e.body! as Map<String, Object?>)); - /// Returns a stream of [StoppedEventBody] events. - Stream<StoppedEventBody> get stoppedEvents => events('stopped') - .map((Event e) => StoppedEventBody.fromJson(e.body! as Map<String, Object?>)); - /// Returns a stream of the string output from [OutputEventBody] events. Stream<String> get output => outputEvents.map((OutputEventBody output) => output.output); @@ -78,16 +74,6 @@ class DapTestClient { return _eventController.stream.where((Event e) => e.event == event); } - /// Returns a stream of custom 'dart.serviceExtensionAdded' events. - Stream<Map<String, Object?>> get serviceExtensionAddedEvents => - events('dart.serviceExtensionAdded') - .map((Event e) => e.body! as Map<String, Object?>); - - /// Returns a stream of custom 'flutter.serviceExtensionStateChanged' events. - Stream<Map<String, Object?>> get serviceExtensionStateChangedEvents => - events('flutter.serviceExtensionStateChanged') - .map((Event e) => e.body! as Map<String, Object?>); - /// Returns a stream of 'dart.testNotification' custom events from the /// package:test JSON reporter. Stream<Map<String, Object?>> get testNotificationEvents => @@ -181,28 +167,15 @@ class DapTestClient { return completer.future; } - /// Returns a Future that completes with the next serviceExtensionAdded - /// event for [extension]. - Future<Map<String, Object?>> serviceExtensionAdded(String extension) => serviceExtensionAddedEvents.firstWhere( - (Map<String, Object?> body) => body['extensionRPC'] == extension, - orElse: () => throw 'Did not recieve $extension extension added event before stream closed'); - - /// Returns a Future that completes with the next serviceExtensionStateChanged - /// event for [extension]. - Future<Map<String, Object?>> serviceExtensionStateChanged(String extension) => serviceExtensionStateChangedEvents.firstWhere( - (Map<String, Object?> body) => body['extension'] == extension, - orElse: () => throw 'Did not recieve $extension extension state changed event before stream closed'); - /// Initializes the debug adapter and launches [program]/[cwd] or calls the /// custom [launch] method. Future<void> start({ String? program, String? cwd, - String exceptionPauseMode = 'None', Future<Object?> Function()? launch, }) { return Future.wait(<Future<Object?>>[ - initialize(exceptionPauseMode: exceptionPauseMode), + initialize(), launch?.call() ?? this.launch(program: program, cwd: cwd), ], eagerError: true); } @@ -228,7 +201,7 @@ class DapTestClient { } else { completer.completeError(message); } - } else if (message is Event && !_eventController.isClosed) { + } else if (message is Event) { _eventController.add(message); // When we see a terminated event, close the event stream so if any diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/test_server.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/test_server.dart index 03bf6dd83b16e..59b6e9d1222df 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/test_server.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/test_server.dart @@ -9,7 +9,7 @@ import 'dart:io'; import 'package:dds/src/dap/logging.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/debug_adapters/server.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; /// Enable to run from local source when running out-of-process (useful in /// development to avoid having to keep rebuilding the flutter tool). @@ -73,16 +73,13 @@ class OutOfProcessDapTestServer extends DapTestServer { Logger? logger, ) { // Treat anything written to stderr as the DAP crashing and fail the test - // unless it's "Waiting for another flutter command to release the startup - // lock" or we're tearing down. + // unless it's "Waiting for another flutter command to release the startup lock". _process.stderr .transform(utf8.decoder) .where((String error) => !error.contains('Waiting for another flutter command to release the startup lock')) .listen((String error) { logger?.call(error); - if (!_isShuttingDown) { - throw error; - } + throw error; }); unawaited(_process.exitCode.then((int code) { final String message = 'Out-of-process DAP server terminated with code $code'; diff --git a/packages/flutter_tools/test/integration.shard/debugger_stepping_test.dart b/packages/flutter_tools/test/integration.shard/debugger_stepping_test.dart index 2b259c2b70665..a6f96d925d43c 100644 --- a/packages/flutter_tools/test/integration.shard/debugger_stepping_test.dart +++ b/packages/flutter_tools/test/integration.shard/debugger_stepping_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:file/file.dart'; import '../src/common.dart'; @@ -10,7 +12,7 @@ import 'test_driver.dart'; import 'test_utils.dart'; void main() { - late Directory tempDir; + Directory tempDir; setUp(() async { tempDir = createResolvedTempDirectorySync('debugger_stepping_test.'); @@ -30,13 +32,13 @@ void main() { await _flutter.addBreakpoint(_project.breakpointUri, _project.breakpointLine); await _flutter.resume(waitForNextPause: true); // Now we should be on the breakpoint. - expect((await _flutter.getSourceLocation())?.line, equals(_project.breakpointLine)); + expect((await _flutter.getSourceLocation()).line, equals(_project.breakpointLine)); // Issue 5 steps, ensuring that we end up on the annotated lines each time. for (int i = 1; i <= _project.numberOfSteps; i += 1) { await _flutter.stepOverOrOverAsyncSuspension(); - final SourcePosition? location = await _flutter.getSourceLocation(); - final int? actualLine = location?.line; + final SourcePosition location = await _flutter.getSourceLocation(); + final int actualLine = location.line; // Get the line we're expected to stop at by searching for the comment // within the source code. diff --git a/packages/flutter_tools/test/integration.shard/deferred_components_test.dart b/packages/flutter_tools/test/integration.shard/deferred_components_test.dart index 33fb485a13f23..d96d852d34b17 100644 --- a/packages/flutter_tools/test/integration.shard/deferred_components_test.dart +++ b/packages/flutter_tools/test/integration.shard/deferred_components_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:archive/archive.dart'; import 'package:file/file.dart'; import 'package:file_testing/file_testing.dart'; @@ -13,8 +15,8 @@ import 'test_driver.dart'; import 'test_utils.dart'; void main() { - late Directory tempDir; - late FlutterRunTestDriver _flutter; + Directory tempDir; + FlutterRunTestDriver _flutter; setUp(() async { tempDir = createResolvedTempDirectorySync('run_test.'); diff --git a/packages/flutter_tools/test/integration.shard/expression_evaluation_test.dart b/packages/flutter_tools/test/integration.shard/expression_evaluation_test.dart index 52118fae7e52b..7f058764ea8ec 100644 --- a/packages/flutter_tools/test/integration.shard/expression_evaluation_test.dart +++ b/packages/flutter_tools/test/integration.shard/expression_evaluation_test.dart @@ -168,7 +168,7 @@ Future<void> evaluateComplexReturningExpressions(FlutterTestDriver flutter) asyn // Ensure we got a reasonable approximation. The more accurate we try to // make this, the more likely it'll fail due to differences in the time // in the remote VM and the local VM at the time the code runs. - final ObjRef res = await flutter.evaluate(resp.id, r'"$year-$month-$day"'); + final InstanceRef res = await flutter.evaluate(resp.id, r'"$year-$month-$day"'); expectValue(res, '${now.year}-${now.month}-${now.day}'); } diff --git a/packages/flutter_tools/test/integration.shard/gen_l10n_test.dart b/packages/flutter_tools/test/integration.shard/gen_l10n_test.dart index 8d1a2d153e0d1..12f72904294d7 100644 --- a/packages/flutter_tools/test/integration.shard/gen_l10n_test.dart +++ b/packages/flutter_tools/test/integration.shard/gen_l10n_test.dart @@ -123,47 +123,45 @@ void main() { '#l10n 68 (Cabriolet has "acceleration")\n' '#l10n 69 (Oh, she found 1 item!)\n' '#l10n 70 (Indeed, they like Flutter!)\n' - '#l10n 71 (Indeed, he likes ice cream!)\n' - '#l10n 72 (Indeed, she likes chocolate!)\n' - '#l10n 73 (--- es ---)\n' - '#l10n 74 (ES - Hello world)\n' - '#l10n 75 (ES - Hello _NEWLINE_ World)\n' - '#l10n 76 (ES - Hola \$ Mundo)\n' - '#l10n 77 (ES - Hello Mundo)\n' - '#l10n 78 (ES - Hola Mundo)\n' - '#l10n 79 (ES - Hello World on viernes, 1 de enero de 1960)\n' - '#l10n 80 (ES - Hello world argument on 1/1/1960 at 0:00)\n' - '#l10n 81 (ES - Hello World from 1960 to 2020)\n' - '#l10n 82 (ES - Hello for 123)\n' - '#l10n 83 (ES - Hello)\n' - '#l10n 84 (ES - Hello World)\n' - '#l10n 85 (ES - Hello two worlds)\n' - '#l10n 86 (ES - Hello)\n' - '#l10n 87 (ES - Hello nuevo World)\n' - '#l10n 88 (ES - Hello two nuevo worlds)\n' - '#l10n 89 (ES - Hello on viernes, 1 de enero de 1960)\n' - '#l10n 90 (ES - Hello World, on viernes, 1 de enero de 1960)\n' - '#l10n 91 (ES - Hello two worlds, on viernes, 1 de enero de 1960)\n' - '#l10n 92 (ES - Hello other 0 worlds, with a total of 100 citizens)\n' - '#l10n 93 (ES - Hello World of 101 citizens)\n' - '#l10n 94 (ES - Hello two worlds with 102 total citizens)\n' - '#l10n 95 (ES - [Hola] -Mundo- #123#)\n' - '#l10n 96 (ES - \$!)\n' - '#l10n 97 (ES - One \$)\n' - "#l10n 98 (ES - Flutter's amazing!)\n" - "#l10n 99 (ES - Flutter's amazing, times 2!)\n" - '#l10n 100 (ES - Flutter is "amazing"!)\n' - '#l10n 101 (ES - Flutter is "amazing", times 2!)\n' - '#l10n 102 (ES - 16 wheel truck)\n' - "#l10n 103 (ES - Sedan's elegance)\n" - '#l10n 104 (ES - Cabriolet has "acceleration")\n' - '#l10n 105 (ES - Oh, she found ES - 1 itemES - !)\n' - '#l10n 106 (ES - Indeed, ES - they like ES - Flutter!)\n' - '#l10n 107 (--- es_419 ---)\n' + '#l10n 71 (--- es ---)\n' + '#l10n 72 (ES - Hello world)\n' + '#l10n 73 (ES - Hello _NEWLINE_ World)\n' + '#l10n 74 (ES - Hola \$ Mundo)\n' + '#l10n 75 (ES - Hello Mundo)\n' + '#l10n 76 (ES - Hola Mundo)\n' + '#l10n 77 (ES - Hello World on viernes, 1 de enero de 1960)\n' + '#l10n 78 (ES - Hello world argument on 1/1/1960 at 0:00)\n' + '#l10n 79 (ES - Hello World from 1960 to 2020)\n' + '#l10n 80 (ES - Hello for 123)\n' + '#l10n 81 (ES - Hello)\n' + '#l10n 82 (ES - Hello World)\n' + '#l10n 83 (ES - Hello two worlds)\n' + '#l10n 84 (ES - Hello)\n' + '#l10n 85 (ES - Hello nuevo World)\n' + '#l10n 86 (ES - Hello two nuevo worlds)\n' + '#l10n 87 (ES - Hello on viernes, 1 de enero de 1960)\n' + '#l10n 88 (ES - Hello World, on viernes, 1 de enero de 1960)\n' + '#l10n 89 (ES - Hello two worlds, on viernes, 1 de enero de 1960)\n' + '#l10n 90 (ES - Hello other 0 worlds, with a total of 100 citizens)\n' + '#l10n 91 (ES - Hello World of 101 citizens)\n' + '#l10n 92 (ES - Hello two worlds with 102 total citizens)\n' + '#l10n 93 (ES - [Hola] -Mundo- #123#)\n' + '#l10n 94 (ES - \$!)\n' + '#l10n 95 (ES - One \$)\n' + "#l10n 96 (ES - Flutter's amazing!)\n" + "#l10n 97 (ES - Flutter's amazing, times 2!)\n" + '#l10n 98 (ES - Flutter is "amazing"!)\n' + '#l10n 99 (ES - Flutter is "amazing", times 2!)\n' + '#l10n 100 (ES - 16 wheel truck)\n' + "#l10n 101 (ES - Sedan's elegance)\n" + '#l10n 102 (ES - Cabriolet has "acceleration")\n' + '#l10n 103 (ES - Oh, she found ES - 1 itemES - !)\n' + '#l10n 104 (ES - Indeed, ES - they like ES - Flutter!)\n' + '#l10n 105 (--- es_419 ---)\n' + '#l10n 106 (ES 419 - Hello World)\n' + '#l10n 107 (ES 419 - Hello)\n' '#l10n 108 (ES 419 - Hello World)\n' - '#l10n 109 (ES 419 - Hello)\n' - '#l10n 110 (ES 419 - Hello World)\n' - '#l10n 111 (ES 419 - Hello two worlds)\n' + '#l10n 109 (ES 419 - Hello two worlds)\n' '#l10n END\n' ); } diff --git a/packages/flutter_tools/test/integration.shard/generated_plugin_registrant_test.dart b/packages/flutter_tools/test/integration.shard/generated_plugin_registrant_test.dart index ee18d1c34b8da..7332f77c0cc5a 100644 --- a/packages/flutter_tools/test/integration.shard/generated_plugin_registrant_test.dart +++ b/packages/flutter_tools/test/integration.shard/generated_plugin_registrant_test.dart @@ -14,7 +14,7 @@ import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/create.dart'; import 'package:flutter_tools/src/dart/pub.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../src/common.dart'; import '../src/context.dart'; diff --git a/packages/flutter_tools/test/integration.shard/overall_experience_test.dart b/packages/flutter_tools/test/integration.shard/overall_experience_test.dart index 91325061d5532..8f49bba039e4f 100644 --- a/packages/flutter_tools/test/integration.shard/overall_experience_test.dart +++ b/packages/flutter_tools/test/integration.shard/overall_experience_test.dart @@ -361,9 +361,7 @@ void main() { } finally { tryToDelete(fileSystem.directory(tempDirectory)); } - // This test is expected to be skipped when Platform.isWindows: - // [intended] Windows doesn't support sending signals so we don't care if it can store the PID. - }, skip: true); // Flake: https://github.com/flutter/flutter/issues/92042 + }, skip: Platform.isWindows); // [intended] Windows doesn't support sending signals so we don't care if it can store the PID. testWithoutContext('flutter run handle SIGUSR1/2', () async { final String tempDirectory = fileSystem.systemTempDirectory.createTempSync('flutter_overall_experience_test.').resolveSymbolicLinksSync(); diff --git a/packages/flutter_tools/test/integration.shard/plist_parser_test.dart b/packages/flutter_tools/test/integration.shard/plist_parser_test.dart index 5b28265869940..3f43ed2874e29 100644 --- a/packages/flutter_tools/test/integration.shard/plist_parser_test.dart +++ b/packages/flutter_tools/test/integration.shard/plist_parser_test.dart @@ -33,20 +33,6 @@ const String base64PlistJson = 'eyJDRkJ1bmRsZUV4ZWN1dGFibGUiOiJBcHAiLCJDRkJ1bmRsZUlkZW50aWZpZXIiOiJpby5mb' 'HV0dGVyLmZsdXR0ZXIuYXBwIn0='; -const String base64PlistXmlWithComplexDatatypes = - 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0I' - 'FBVQkxJQyAiLS8vQXBwbGUvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5hcHBsZS' - '5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo' - '8ZGljdD4KICA8a2V5PkNGQnVuZGxlRXhlY3V0YWJsZTwva2V5PgogIDxzdHJpbmc+QXBwPC9z' - 'dHJpbmc+CiAgPGtleT5DRkJ1bmRsZUlkZW50aWZpZXI8L2tleT4KICA8c3RyaW5nPmlvLmZsd' - 'XR0ZXIuZmx1dHRlci5hcHA8L3N0cmluZz4KICA8a2V5PmludFZhbHVlPC9rZXk+CiAgPGludG' - 'VnZXI+MjwvaW50ZWdlcj4KICA8a2V5PmRvdWJsZVZhbHVlPC9rZXk+CiAgPHJlYWw+MS41PC9' - 'yZWFsPgogIDxrZXk+YmluYXJ5VmFsdWU8L2tleT4KICA8ZGF0YT5ZV0pqWkE9PTwvZGF0YT4K' - 'ICA8a2V5PmFycmF5VmFsdWU8L2tleT4KICA8YXJyYXk+CiAgICA8dHJ1ZSAvPgogICAgPGZhb' - 'HNlIC8+CiAgICA8aW50ZWdlcj4zPC9pbnRlZ2VyPgogIDwvYXJyYXk+CiAgPGtleT5kYXRlVm' - 'FsdWU8L2tleT4KICA8ZGF0ZT4yMDIxLTEyLTAxVDEyOjM0OjU2WjwvZGF0ZT4KPC9kaWN0Pgo' - '8L3BsaXN0Pg=='; - void main() { // The tests herein explicitly don't use `MemoryFileSystem` or a mocked // `ProcessManager` because doing so wouldn't actually test what we want to @@ -76,79 +62,62 @@ void main() { file.deleteSync(); }); - testWithoutContext('PlistParser.getStringValueFromFile works with xml file', () { + testWithoutContext('PlistParser.getValueFromFile works with xml file', () { file.writeAsBytesSync(base64.decode(base64PlistXml)); - expect(parser.getStringValueFromFile(file.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); - expect(parser.getStringValueFromFile(file.absolute.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); + expect(parser.getValueFromFile(file.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); + expect(parser.getValueFromFile(file.absolute.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); expect(logger.statusText, isEmpty); expect(logger.errorText, isEmpty); }, skip: !platform.isMacOS); // [intended] requires macos tool chain. - testWithoutContext('PlistParser.getStringValueFromFile works with binary file', () { + testWithoutContext('PlistParser.getValueFromFile works with binary file', () { file.writeAsBytesSync(base64.decode(base64PlistBinary)); - expect(parser.getStringValueFromFile(file.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); - expect(parser.getStringValueFromFile(file.absolute.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); + expect(parser.getValueFromFile(file.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); + expect(parser.getValueFromFile(file.absolute.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); expect(logger.statusText, isEmpty); expect(logger.errorText, isEmpty); }, skip: !platform.isMacOS); // [intended] requires macos tool chain. - testWithoutContext('PlistParser.getStringValueFromFile works with json file', () { + testWithoutContext('PlistParser.getValueFromFile works with json file', () { file.writeAsBytesSync(base64.decode(base64PlistJson)); - expect(parser.getStringValueFromFile(file.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); - expect(parser.getStringValueFromFile(file.absolute.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); + expect(parser.getValueFromFile(file.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); + expect(parser.getValueFromFile(file.absolute.path, 'CFBundleIdentifier'), 'io.flutter.flutter.app'); expect(logger.statusText, isEmpty); expect(logger.errorText, isEmpty); }, skip: !platform.isMacOS); // [intended] requires macos tool chain. - testWithoutContext('PlistParser.getStringValueFromFile returns null for non-existent plist file', () { - expect(parser.getStringValueFromFile('missing.plist', 'CFBundleIdentifier'), null); + testWithoutContext('PlistParser.getValueFromFile returns null for non-existent plist file', () { + expect(parser.getValueFromFile('missing.plist', 'CFBundleIdentifier'), null); expect(logger.statusText, isEmpty); expect(logger.errorText, isEmpty); }, skip: !platform.isMacOS); // [intended] requires macos tool chain. - testWithoutContext('PlistParser.getStringValueFromFile returns null for non-existent key within plist', () { + testWithoutContext('PlistParser.getValueFromFile returns null for non-existent key within plist', () { file.writeAsBytesSync(base64.decode(base64PlistXml)); - expect(parser.getStringValueFromFile(file.path, 'BadKey'), null); - expect(parser.getStringValueFromFile(file.absolute.path, 'BadKey'), null); + expect(parser.getValueFromFile(file.path, 'BadKey'), null); + expect(parser.getValueFromFile(file.absolute.path, 'BadKey'), null); expect(logger.statusText, isEmpty); expect(logger.errorText, isEmpty); }, skip: !platform.isMacOS); // [intended] requires macos tool chain. - testWithoutContext('PlistParser.getStringValueFromFile returns null for malformed plist file', () { + testWithoutContext('PlistParser.getValueFromFile returns null for malformed plist file', () { file.writeAsBytesSync(const <int>[1, 2, 3, 4, 5, 6]); - expect(parser.getStringValueFromFile(file.path, 'CFBundleIdentifier'), null); + expect(parser.getValueFromFile(file.path, 'CFBundleIdentifier'), null); expect(logger.statusText, isNotEmpty); expect(logger.errorText, isEmpty); }, skip: !platform.isMacOS); // [intended] requires macos tool chain. - testWithoutContext('PlistParser.getStringValueFromFile throws when /usr/bin/plutil is not found', () async { - file.writeAsBytesSync(base64.decode(base64PlistXml)); - + testWithoutContext('PlistParser.getValueFromFile throws when /usr/bin/plutil is not found', () async { expect( - () => parser.getStringValueFromFile(file.path, 'unused'), + () => parser.getValueFromFile('irrelevant.plist', 'ununsed'), throwsA(isA<FileNotFoundException>()), ); expect(logger.statusText, isEmpty); expect(logger.errorText, isEmpty); }, skip: platform.isMacOS); // [intended] requires macos tool chain. - - testWithoutContext('PlistParser.parseFile can handle different datatypes', () async { - file.writeAsBytesSync(base64.decode(base64PlistXmlWithComplexDatatypes)); - final Map<String, Object> values = parser.parseFile(file.path); - - expect(values['CFBundleIdentifier'], 'io.flutter.flutter.app'); - expect(values['CFBundleIdentifier'], 'io.flutter.flutter.app'); - expect(values['intValue'], 2); - expect(values['doubleValue'], 1.5); - expect(values['binaryValue'], base64.decode('YWJjZA==')); - expect(values['arrayValue'], <dynamic>[true, false, 3]); - expect(values['dateValue'], DateTime.utc(2021, 12, 1, 12, 34, 56)); - expect(logger.statusText, isEmpty); - expect(logger.errorText, isEmpty); - }, skip: !platform.isMacOS); // [intended] requires macos tool chain. } diff --git a/packages/flutter_tools/test/integration.shard/test_data/basic_project.dart b/packages/flutter_tools/test/integration.shard/test_data/basic_project.dart index 7f3cc0f8d578f..0090d69003472 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/basic_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/basic_project.dart @@ -53,68 +53,6 @@ class BasicProject extends Project { int get topLevelFunctionBreakpointLine => lineContaining(main, '// TOP LEVEL BREAKPOINT'); } -/// A project that throws multiple exceptions during Widget builds. -/// -/// A repro for the issue at https://github.com/Dart-Code/Dart-Code/issues/3448 -/// where Hot Restart could become stuck on exceptions and never complete. -class BasicProjectThatThrows extends Project { - - @override - final String pubspec = ''' - name: test - environment: - sdk: ">=2.12.0-0 <3.0.0" - - dependencies: - flutter: - sdk: flutter - '''; - - @override - final String main = r''' - import 'package:flutter/material.dart'; - - void a() { - throw Exception('a'); - } - - void b() { - try { - a(); - } catch (e) { - throw Exception('b'); - } - } - - void c() { - try { - b(); - } catch (e) { - throw Exception('c'); - } - } - - void main() { - runApp(App()); - } - - class App extends StatelessWidget { - @override - Widget build(BuildContext context) { - c(); - return MaterialApp( - debugShowCheckedModeBanner: false, - title: 'Study Flutter', - theme: ThemeData( - primarySwatch: Colors.green, - ), - home: Container(), - ); - } - } - '''; -} - class BasicProjectWithTimelineTraces extends Project { @override final String pubspec = ''' diff --git a/packages/flutter_tools/test/integration.shard/test_data/compile_error_project.dart b/packages/flutter_tools/test/integration.shard/test_data/compile_error_project.dart index 687113cbc56ff..bca20f15f7384 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/compile_error_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/compile_error_project.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'project.dart'; class CompileErrorProject extends Project { diff --git a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_config.dart b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_config.dart index 7bec934f267e1..5de7e2dfa1748 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_config.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_config.dart @@ -108,7 +108,7 @@ class DeferredComponentModule { apply plugin: "com.android.dynamic-feature" android { - compileSdkVersion 31 + compileSdkVersion 30 sourceSets { applicationVariants.all { variant -> @@ -119,7 +119,7 @@ class DeferredComponentModule { defaultConfig { minSdkVersion 16 - targetSdkVersion 31 + targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart b/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart index 02e7045f01542..55531ac564a53 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart @@ -227,8 +227,6 @@ class Home extends StatelessWidget { "${localizations.doubleQuoteSelect('cabriolet')}", "${localizations.pluralInString(1)}", "${localizations.selectInString('he')}", - "${localizations.selectWithPlaceholder('male', 'ice cream')}", - "${localizations.selectWithPlaceholder('female', 'chocolate')}", ]); }, ), @@ -657,15 +655,6 @@ void main() { "placeholders": { "gender": {} } - }, - - "selectWithPlaceholder": "Indeed, {gender, select, male {he likes {preference}} female {she likes {preference}} other {they like {preference}}}!", - "@selectWithPlaceholder": { - "description": "A select message with prefix, suffix strings, and a placeholder.", - "placeholders": { - "gender": {}, - "preference": {} - } } } '''; diff --git a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart index bafe8d4475c7f..7db55f9bd81be 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart @@ -162,7 +162,7 @@ class MultidexProject extends Project { apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 31 + compileSdkVersion 30 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/packages/flutter_tools/test/integration.shard/test_driver.dart b/packages/flutter_tools/test/integration.shard/test_driver.dart index 190a64a8e1816..1b83ddf110c9d 100644 --- a/packages/flutter_tools/test/integration.shard/test_driver.dart +++ b/packages/flutter_tools/test/integration.shard/test_driver.dart @@ -58,7 +58,6 @@ abstract class FlutterTestDriver { VmService? _vmService; String get lastErrorInfo => _errorBuffer.toString(); Stream<String> get stdout => _stdout.stream; - Stream<String> get stderr => _stderr.stream; int? get vmServicePort => _vmServiceWsUri?.port; bool get hasExited => _hasExited; Uri? get vmServiceWsUri => _vmServiceWsUri; @@ -164,9 +163,9 @@ abstract class FlutterTestDriver { await waitForPause(); if (pauseOnExceptions) { - await _vmService!.setIsolatePauseMode( + await _vmService!.setExceptionPauseMode( await _getFlutterIsolateId(), - exceptionPauseMode: ExceptionPauseMode.kUnhandled, + ExceptionPauseMode.kUnhandled, ); } } @@ -356,9 +355,9 @@ abstract class FlutterTestDriver { ); } - Future<ObjRef> evaluate(String targetId, String expression) async { - return _timeoutWithMessages<ObjRef>( - () async => await _vmService!.evaluate(await _getFlutterIsolateId(), targetId, expression) as ObjRef, + Future<InstanceRef> evaluate(String targetId, String expression) async { + return _timeoutWithMessages<InstanceRef>( + () async => await _vmService!.evaluate(await _getFlutterIsolateId(), targetId, expression) as InstanceRef, task: 'Evaluating expression ($expression for $targetId)', ); } diff --git a/packages/flutter_tools/test/integration.shard/test_test.dart b/packages/flutter_tools/test/integration.shard/test_test.dart index c8aef8f09df4a..25ef8a854bed6 100644 --- a/packages/flutter_tools/test/integration.shard/test_test.dart +++ b/packages/flutter_tools/test/integration.shard/test_test.dart @@ -115,66 +115,84 @@ void main() { testWithoutContext('flutter test should run a test when its name matches a regexp', () async { final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory, extraArguments: const <String>['--name', 'inc.*de']); - expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!'))); + if (!(result.stdout as String).contains('+1: All tests passed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } expect(result.exitCode, 0); }); testWithoutContext('flutter test should run a test when its name contains a string', () async { final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory, extraArguments: const <String>['--plain-name', 'include']); - expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!'))); + if (!(result.stdout as String).contains('+1: All tests passed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } expect(result.exitCode, 0); }); testWithoutContext('flutter test should run a test with a given tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory, extraArguments: const <String>['--tags', 'include-tag']); - expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!'))); + if (!(result.stdout as String).contains('+1: All tests passed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } expect(result.exitCode, 0); }); testWithoutContext('flutter test should not run a test with excluded tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory, extraArguments: const <String>['--exclude-tags', 'exclude-tag']); - expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!'))); + if (!(result.stdout as String).contains('+1: All tests passed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } expect(result.exitCode, 0); }); testWithoutContext('flutter test should run all tests when tags are unspecified', () async { final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory); - expect(result.stdout, contains(RegExp(r'\+\d+ -1: Some tests failed\.'))); + if (!(result.stdout as String).contains('+1 -1: Some tests failed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } expect(result.exitCode, 1); }); testWithoutContext('flutter test should run a widgetTest with a given tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory, extraArguments: const <String>['--tags', 'include-tag']); - expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!'))); + if (!(result.stdout as String).contains('+1: All tests passed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } expect(result.exitCode, 0); }); testWithoutContext('flutter test should not run a widgetTest with excluded tag', () async { final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory, extraArguments: const <String>['--exclude-tags', 'exclude-tag']); - expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!'))); + if (!(result.stdout as String).contains('+1: All tests passed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } expect(result.exitCode, 0); }); testWithoutContext('flutter test should run all widgetTest when tags are unspecified', () async { final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory); - expect(result.stdout, contains(RegExp(r'\+\d+ -1: Some tests failed\.'))); + if (!(result.stdout as String).contains('+1 -1: Some tests failed')) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } expect(result.exitCode, 1); }); testWithoutContext('flutter test should test runs to completion', () async { final ProcessResult result = await _runFlutterTest('trivial', automatedTestsDirectory, flutterTestDirectory, extraArguments: const <String>['--verbose']); - final String stdout = (result.stdout as String).replaceAll('\r', '\n'); - expect(stdout, contains(RegExp(r'\+\d+: All tests passed\!'))); - expect(stdout, contains('test 0: Starting flutter_tester process with command')); - expect(stdout, contains('test 0: deleting temporary directory')); - expect(stdout, contains('test 0: finished')); - expect(stdout, contains('test package returned with exit code 0')); + final String stdout = result.stdout as String; + if ((!stdout.contains('+1: All tests passed')) || + (!stdout.contains('test 0: Starting flutter_tester process with command')) || + (!stdout.contains('test 0: deleting temporary directory')) || + (!stdout.contains('test 0: finished')) || + (!stdout.contains('test package returned with exit code 0'))) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } if ((result.stderr as String).isNotEmpty) { fail('unexpected error output from test:\n\n${result.stderr}\n-- end stderr --\n\n'); } @@ -184,12 +202,14 @@ void main() { testWithoutContext('flutter test should run all tests inside of a directory with no trailing slash', () async { final ProcessResult result = await _runFlutterTest(null, automatedTestsDirectory, '$flutterTestDirectory/child_directory', extraArguments: const <String>['--verbose']); - final String stdout = (result.stdout as String).replaceAll('\r', '\n'); - expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed\!'))); - expect(stdout, contains('test 0: Starting flutter_tester process with command')); - expect(stdout, contains('test 0: deleting temporary directory')); - expect(stdout, contains('test 0: finished')); - expect(stdout, contains('test package returned with exit code 0')); + final String stdout = result.stdout as String; + if ((!stdout.contains('+2: All tests passed')) || + (!stdout.contains('test 0: Starting flutter_tester process with command')) || + (!stdout.contains('test 0: deleting temporary directory')) || + (!stdout.contains('test 0: finished')) || + (!stdout.contains('test package returned with exit code 0'))) { + fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); + } if ((result.stderr as String).isNotEmpty) { fail('unexpected error output from test:\n\n${result.stderr}\n-- end stderr --\n\n'); } diff --git a/packages/flutter_tools/test/integration.shard/vmservice_integration_test.dart b/packages/flutter_tools/test/integration.shard/vmservice_integration_test.dart index 871587f7256ff..1acfc1ff29135 100644 --- a/packages/flutter_tools/test/integration.shard/vmservice_integration_test.dart +++ b/packages/flutter_tools/test/integration.shard/vmservice_integration_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.8 + import 'package:file/file.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:vm_service/vm_service.dart'; @@ -14,9 +16,9 @@ import 'test_utils.dart'; void main() { group('Flutter Tool VMService method', () { - late Directory tempDir; - late FlutterRunTestDriver flutter; - late VmService vmService; + Directory tempDir; + FlutterRunTestDriver flutter; + VmService vmService; setUp(() async { tempDir = createResolvedTempDirectorySync('vmservice_integration_test.'); @@ -26,13 +28,12 @@ void main() { flutter = FlutterRunTestDriver(tempDir); await flutter.run(withDebugger: true); - final int? port = flutter.vmServicePort; - expect(port != null, true); + final int port = flutter.vmServicePort; vmService = await vmServiceConnectUri('ws://localhost:$port/ws'); }); tearDown(() async { - await flutter.stop(); + await flutter?.stop(); tryToDelete(tempDir); }); @@ -40,7 +41,7 @@ void main() { final ProtocolList protocolList = await vmService.getSupportedProtocols(); expect(protocolList.protocols, hasLength(2)); - for (final Protocol protocol in protocolList.protocols!) { + for (final Protocol protocol in protocolList.protocols) { expect(protocol.protocolName, anyOf('VM Service', 'DDS')); } }); @@ -61,10 +62,10 @@ void main() { testWithoutContext('reloadSources can be called', () async { final VM vm = await vmService.getVM(); - final IsolateRef? isolateRef = vm.isolates?.first; - expect(isolateRef != null, true); + final IsolateRef isolateRef = vm.isolates.first; + final Response response = await vmService.callMethod('s0.reloadSources', - isolateId: isolateRef!.id); + isolateId: isolateRef.id); expect(response.type, 'Success'); }); @@ -76,10 +77,10 @@ void main() { testWithoutContext('hotRestart can be called', () async { final VM vm = await vmService.getVM(); - final IsolateRef? isolateRef = vm.isolates?.first; - expect(isolateRef != null, true); + final IsolateRef isolateRef = vm.isolates.first; + final Response response = - await vmService.callMethod('s0.hotRestart', isolateId: isolateRef!.id); + await vmService.callMethod('s0.hotRestart', isolateId: isolateRef.id); expect(response.type, 'Success'); }); @@ -101,7 +102,7 @@ void main() { 'ext.flutter.brightnessOverride', isolateId: isolate.id, ); - expect(response.json?['value'], 'Brightness.light'); + expect(response.json['value'], 'Brightness.light'); final Response updateResponse = await vmService.callServiceExtension( 'ext.flutter.brightnessOverride', @@ -110,7 +111,7 @@ void main() { 'value': 'Brightness.dark', } ); - expect(updateResponse.json?['value'], 'Brightness.dark'); + expect(updateResponse.json['value'], 'Brightness.dark'); // Change the brightness back to light final Response verifyResponse = await vmService.callServiceExtension( @@ -120,7 +121,7 @@ void main() { 'value': 'Brightness.light', } ); - expect(verifyResponse.json?['value'], 'Brightness.light'); + expect(verifyResponse.json['value'], 'Brightness.light'); // Change with a bogus value final Response bogusResponse = await vmService.callServiceExtension( @@ -130,7 +131,7 @@ void main() { 'value': 'dark', // Intentionally invalid value. } ); - expect(bogusResponse.json?['value'], 'Brightness.light'); + expect(bogusResponse.json['value'], 'Brightness.light'); }); testWithoutContext('ext.flutter.debugPaint can toggle debug painting', () async { @@ -139,7 +140,7 @@ void main() { 'ext.flutter.debugPaint', isolateId: isolate.id, ); - expect(response.json?['enabled'], 'false'); + expect(response.json['enabled'], 'false'); final Response updateResponse = await vmService.callServiceExtension( 'ext.flutter.debugPaint', @@ -148,7 +149,7 @@ void main() { 'enabled': 'true', } ); - expect(updateResponse.json?['enabled'], 'true'); + expect(updateResponse.json['enabled'], 'true'); }); }); } diff --git a/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart b/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart index c0fe24d32c56c..2aa55bac3d5bf 100644 --- a/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart +++ b/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart @@ -8,7 +8,7 @@ import 'dart:io' as io; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import '../src/common.dart'; diff --git a/packages/flutter_tools/test/src/android_common.dart b/packages/flutter_tools/test/src/android_common.dart index 4b4aa3aca4a78..11bec7727a186 100644 --- a/packages/flutter_tools/test/src/android_common.dart +++ b/packages/flutter_tools/test/src/android_common.dart @@ -5,7 +5,7 @@ import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/build_info.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; /// A fake implementation of [AndroidBuilder]. diff --git a/packages/flutter_tools/test/src/common.dart b/packages/flutter_tools/test/src/common.dart index 62b3e4b675f50..2e0094204476f 100644 --- a/packages/flutter_tools/test/src/common.dart +++ b/packages/flutter_tools/test/src/common.dart @@ -10,7 +10,7 @@ import 'package:flutter_tools/src/base/context.dart'; 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'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; // flutter_ignore: package_path_import import 'package:test_api/test_api.dart' as test_package show test; // ignore: deprecated_member_use diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart index 0c38b69eb93f0..68ece0dd63bb6 100644 --- a/packages/flutter_tools/test/src/context.dart +++ b/packages/flutter_tools/test/src/context.dart @@ -25,7 +25,7 @@ import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/ios/plist_parser.dart'; import 'package:flutter_tools/src/ios/simulators.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; @@ -294,10 +294,10 @@ class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter { bool get isInstalled => true; @override - String get versionText => 'Xcode 12.3'; + String get versionText => 'Xcode 12.0.1'; @override - Version get version => Version(12, 3, null); + Version get version => Version(12, 0, 1); @override Future<Map<String, String>> getBuildSettings( diff --git a/packages/flutter_tools/test/src/dap/flutter_adapter_test.dart b/packages/flutter_tools/test/src/dap/flutter_adapter_test.dart deleted file mode 100644 index 042de41e115fb..0000000000000 --- a/packages/flutter_tools/test/src/dap/flutter_adapter_test.dart +++ /dev/null @@ -1,83 +0,0 @@ -// 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:async'; - -import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/debug_adapters/flutter_adapter_args.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:test/test.dart'; - -import 'mocks.dart'; - -void main() { - group('flutter adapter', () { - setUpAll(() { - Cache.flutterRoot = '/fake/flutter'; - }); - - test('includes toolArgs', () async { - final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform); - final Completer<void> responseCompleter = Completer<void>(); - - final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', - program: 'foo.dart', - toolArgs: <String>['tool_arg'], - noDebug: true, - ); - - await adapter.configurationDoneRequest(MockRequest(), null, () {}); - await adapter.launchRequest(MockRequest(), args, responseCompleter.complete); - await responseCompleter.future; - - expect(adapter.executable, equals('/fake/flutter/bin/flutter')); - expect(adapter.processArgs, contains('tool_arg')); - }); - - group('includes customTool', () { - test('with no args replaced', () async { - final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform); - final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', - program: 'foo.dart', - customTool: '/custom/flutter', - noDebug: true, - ); - - await adapter.configurationDoneRequest(MockRequest(), null, () {}); - final Completer<void> responseCompleter = Completer<void>(); - await adapter.launchRequest(MockRequest(), args, responseCompleter.complete); - await responseCompleter.future; - - expect(adapter.executable, equals('/custom/flutter')); - // args should be in-tact - expect(adapter.processArgs, contains('--machine')); - }); - - test('with all args replaced', () async { - final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform); - final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', - program: 'foo.dart', - customTool: '/custom/flutter', - customToolReplacesArgs: 9999, // replaces all built-in args - noDebug: true, - toolArgs: <String>['tool_args'], // should still be in args - ); - - await adapter.configurationDoneRequest(MockRequest(), null, () {}); - final Completer<void> responseCompleter = Completer<void>(); - await adapter.launchRequest(MockRequest(), args, responseCompleter.complete); - await responseCompleter.future; - - expect(adapter.executable, equals('/custom/flutter')); - // normal built-in args are replaced by customToolReplacesArgs, but - // user-provided toolArgs are not. - expect(adapter.processArgs, isNot(contains('--machine'))); - expect(adapter.processArgs, contains('tool_args')); - }); - }); - }); -} diff --git a/packages/flutter_tools/test/src/dap/flutter_test_adapter_test.dart b/packages/flutter_tools/test/src/dap/flutter_test_adapter_test.dart deleted file mode 100644 index 3d980444238f6..0000000000000 --- a/packages/flutter_tools/test/src/dap/flutter_test_adapter_test.dart +++ /dev/null @@ -1,90 +0,0 @@ -// 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:async'; - -import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/debug_adapters/flutter_adapter_args.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:test/test.dart'; - -import 'mocks.dart'; - -void main() { - group('flutter test adapter', () { - setUpAll(() { - Cache.flutterRoot = '/fake/flutter'; - }); - - test('includes toolArgs', () async { - final MockFlutterTestDebugAdapter adapter = MockFlutterTestDebugAdapter( - fileSystem: globals.fs, - platform: globals.platform, - ); - final Completer<void> responseCompleter = Completer<void>(); - final MockRequest request = MockRequest(); - final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', - program: 'foo.dart', - toolArgs: <String>['tool_arg'], - noDebug: true, - ); - - await adapter.configurationDoneRequest(request, null, () {}); - await adapter.launchRequest(request, args, responseCompleter.complete); - await responseCompleter.future; - - expect(adapter.executable, equals('/fake/flutter/bin/flutter')); - expect(adapter.processArgs, contains('tool_arg')); - }); - - group('includes customTool', () { - test('with no args replaced', () async { - final MockFlutterTestDebugAdapter adapter = MockFlutterTestDebugAdapter(fileSystem: globals.fs, - platform: globals.platform,); - final Completer<void> responseCompleter = Completer<void>(); - final MockRequest request = MockRequest(); - final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', - program: 'foo.dart', - customTool: '/custom/flutter', - noDebug: true, - ); - - await adapter.configurationDoneRequest(request, null, () {}); - await adapter.launchRequest(request, args, responseCompleter.complete); - await responseCompleter.future; - - expect(adapter.executable, equals('/custom/flutter')); - // args should be in-tact - expect(adapter.processArgs, contains('--machine')); - }); - - test('with all args replaced', () async { - final MockFlutterTestDebugAdapter adapter = MockFlutterTestDebugAdapter(fileSystem: globals.fs, - platform: globals.platform,); - final Completer<void> responseCompleter = Completer<void>(); - final MockRequest request = MockRequest(); - final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', - program: 'foo.dart', - customTool: '/custom/flutter', - customToolReplacesArgs: 9999, // replaces all built-in args - noDebug: true, - toolArgs: <String>['tool_args'], // should still be in args - ); - - await adapter.configurationDoneRequest(request, null, () {}); - await adapter.launchRequest(request, args, responseCompleter.complete); - await responseCompleter.future; - - expect(adapter.executable, equals('/custom/flutter')); - // normal built-in args are replaced by customToolReplacesArgs, but - // user-provided toolArgs are not. - expect(adapter.processArgs, isNot(contains('--machine'))); - expect(adapter.processArgs, contains('tool_args')); - }); - }); - }); -} diff --git a/packages/flutter_tools/test/src/dap/mocks.dart b/packages/flutter_tools/test/src/dap/mocks.dart deleted file mode 100644 index 066e6b31c2d79..0000000000000 --- a/packages/flutter_tools/test/src/dap/mocks.dart +++ /dev/null @@ -1,106 +0,0 @@ -// 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:async'; - -import 'package:dds/dap.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/base/platform.dart'; -import 'package:flutter_tools/src/debug_adapters/flutter_adapter.dart'; -import 'package:flutter_tools/src/debug_adapters/flutter_test_adapter.dart'; - -/// A [FlutterDebugAdapter] that captures what process/args will be launched. -class MockFlutterDebugAdapter extends FlutterDebugAdapter { - factory MockFlutterDebugAdapter({ - required FileSystem fileSystem, - required Platform platform, - }) { - final StreamController<List<int>> stdinController = StreamController<List<int>>(); - final StreamController<List<int>> stdoutController = StreamController<List<int>>(); - final ByteStreamServerChannel channel = ByteStreamServerChannel(stdinController.stream, stdoutController.sink, null); - - return MockFlutterDebugAdapter._( - stdinController.sink, - stdoutController.stream, - channel, - fileSystem: fileSystem, - platform: platform, - ); - } - - MockFlutterDebugAdapter._( - this.stdin, - this.stdout, - ByteStreamServerChannel channel, { - required FileSystem fileSystem, - required Platform platform, - }) : super(channel, fileSystem: fileSystem, platform: platform); - - final StreamSink<List<int>> stdin; - final Stream<List<int>> stdout; - - late String executable; - late List<String> processArgs; - - @override - Future<void> launchAsProcess(String executable, List<String> processArgs) async { - this.executable = executable; - this.processArgs = processArgs; - - // Pretend we launched the app and got the app.started event so that - // launchRequest will complete. - appStartedCompleter.complete(); - } -} - -/// A [FlutterTestDebugAdapter] that captures what process/args will be launched. -class MockFlutterTestDebugAdapter extends FlutterTestDebugAdapter { - factory MockFlutterTestDebugAdapter({ - required FileSystem fileSystem, - required Platform platform, - }) { - final StreamController<List<int>> stdinController = StreamController<List<int>>(); - final StreamController<List<int>> stdoutController = StreamController<List<int>>(); - final ByteStreamServerChannel channel = ByteStreamServerChannel(stdinController.stream, stdoutController.sink, null); - - return MockFlutterTestDebugAdapter._( - stdinController.sink, - stdoutController.stream, - channel, - fileSystem: fileSystem, - platform: platform, - ); - } - - MockFlutterTestDebugAdapter._( - this.stdin, - this.stdout, - ByteStreamServerChannel channel, { - required FileSystem fileSystem, - required Platform platform, - }) : super(channel, fileSystem: fileSystem, platform: platform); - - final StreamSink<List<int>> stdin; - final Stream<List<int>> stdout; - - late String executable; - late List<String> processArgs; - - @override - Future<void> launchAsProcess(String executable, List<String> processArgs,) async { - this.executable = executable; - this.processArgs = processArgs; - } -} - -class MockRequest extends Request { - MockRequest() - : super.fromMap(<String, Object?>{ - 'command': 'mock_command', - 'type': 'mock_type', - 'seq': _requestId++, - }); - - static int _requestId = 1; -} diff --git a/packages/flutter_tools/test/src/fake_process_manager.dart b/packages/flutter_tools/test/src/fake_process_manager.dart index 1b5d194ba9f5f..43d232f8b2cea 100644 --- a/packages/flutter_tools/test/src/fake_process_manager.dart +++ b/packages/flutter_tools/test/src/fake_process_manager.dart @@ -108,7 +108,7 @@ class FakeCommand { List<String> command, String? workingDirectory, Map<String, String>? environment, - Encoding? encoding, + Encoding encoding, ) { expect(command, equals(this.command)); if (this.workingDirectory != null) { @@ -244,7 +244,7 @@ abstract class FakeProcessManager implements ProcessManager { List<String> command, String? workingDirectory, Map<String, String>? environment, - Encoding? encoding, + Encoding encoding, ); int _pid = 9999; @@ -253,7 +253,7 @@ abstract class FakeProcessManager implements ProcessManager { List<String> command, String? workingDirectory, Map<String, String>? environment, - Encoding? encoding, + Encoding encoding, ) { _pid += 1; final FakeCommand fakeCommand = findCommand(command, workingDirectory, environment, encoding); @@ -301,8 +301,8 @@ abstract class FakeProcessManager implements ProcessManager { Map<String, String>? environment, bool includeParentEnvironment = true, // ignored bool runInShell = false, // ignored - Encoding? stdoutEncoding = io.systemEncoding, - Encoding? stderrEncoding = io.systemEncoding, + Encoding stdoutEncoding = io.systemEncoding, + Encoding stderrEncoding = io.systemEncoding, }) async { final _FakeProcess process = _runCommand(command.cast<String>(), workingDirectory, environment, stdoutEncoding); await process.exitCode; @@ -321,8 +321,8 @@ abstract class FakeProcessManager implements ProcessManager { Map<String, String>? environment, bool includeParentEnvironment = true, // ignored bool runInShell = false, // ignored - Encoding? stdoutEncoding = io.systemEncoding, // actual encoder is ignored - Encoding? stderrEncoding = io.systemEncoding, // actual encoder is ignored + Encoding stdoutEncoding = io.systemEncoding, // actual encoder is ignored + Encoding stderrEncoding = io.systemEncoding, // actual encoder is ignored }) { final _FakeProcess process = _runCommand(command.cast<String>(), workingDirectory, environment, stdoutEncoding); return io.ProcessResult( @@ -361,7 +361,7 @@ class _FakeAnyProcessManager extends FakeProcessManager { List<String> command, String? workingDirectory, Map<String, String>? environment, - Encoding? encoding, + Encoding encoding, ) { return FakeCommand( command: command, @@ -391,7 +391,7 @@ class _SequenceProcessManager extends FakeProcessManager { List<String> command, String? workingDirectory, Map<String, String>? environment, - Encoding? encoding, + Encoding encoding, ) { expect(_commands, isNotEmpty, reason: 'ProcessManager was told to execute $command (in $workingDirectory) ' diff --git a/packages/flutter_tools/test/src/fake_vm_services.dart b/packages/flutter_tools/test/src/fake_vm_services.dart index 7a40580daf35d..b84ecf1d8acef 100644 --- a/packages/flutter_tools/test/src/fake_vm_services.dart +++ b/packages/flutter_tools/test/src/fake_vm_services.dart @@ -26,14 +26,14 @@ class FakeVmServiceHost { ), httpAddress: httpAddress, wsAddress: wsAddress); _applyStreamListen(); _output.stream.listen((String data) { - final Map<String, Object?> request = json.decode(data) as Map<String, Object?>; + final Map<String, Object> request = json.decode(data) as Map<String, Object>; if (_requests.isEmpty) { throw Exception('Unexpected request: $request'); } final FakeVmServiceRequest fakeRequest = _requests.removeAt(0) as FakeVmServiceRequest; - expect(request, isA<Map<String, Object?>>() - .having((Map<String, Object?> request) => request['method'], 'method', fakeRequest.method) - .having((Map<String, Object?> request) => request['params'], 'args', fakeRequest.args) + expect(request, isA<Map<String, Object>>() + .having((Map<String, Object> request) => request['method'], 'method', fakeRequest.method) + .having((Map<String, Object> request) => request['params'], 'args', fakeRequest.args) ); if (fakeRequest.close) { unawaited(_vmService.dispose()); @@ -52,7 +52,6 @@ class FakeVmServiceHost { 'id': request['id'], 'error': <String, Object?>{ 'code': fakeRequest.errorCode, - 'message': 'error', } })); } @@ -109,7 +108,7 @@ class FakeVmServiceRequest implements VmServiceExpectation { /// standard response. final int? errorCode; final Map<String, Object>? args; - final Map<String, Object?>? jsonResponse; + final Map<String, Object>? jsonResponse; @override bool get isRequest => true; diff --git a/packages/flutter_tools/test/src/fakes.dart b/packages/flutter_tools/test/src/fakes.dart index 1c0bde47f2205..85be1b1fb700c 100644 --- a/packages/flutter_tools/test/src/fakes.dart +++ b/packages/flutter_tools/test/src/fakes.dart @@ -289,26 +289,20 @@ class FakeStdio extends Stdio { } class FakePlistParser implements PlistParser { - FakePlistParser([Map<String, Object>? underlyingValues]): - _underlyingValues = underlyingValues ?? <String, Object>{}; + final Map<String, dynamic> _underlyingValues = <String, String>{}; - final Map<String, Object> _underlyingValues; - - void setProperty(String key, Object value) { + void setProperty(String key, dynamic value) { _underlyingValues[key] = value; } @override - String? plistXmlContent(String plistFilePath) => throw UnimplementedError(); - - @override - Map<String, Object> parseFile(String plistFilePath) { + Map<String, dynamic> parseFile(String plistFilePath) { return _underlyingValues; } @override - String? getStringValueFromFile(String plistFilePath, String key) { - return _underlyingValues[key] as String?; + String getValueFromFile(String plistFilePath, String key) { + return _underlyingValues[key] as String; } } @@ -326,7 +320,6 @@ class FakeFlutterVersion implements FlutterVersion { FakeFlutterVersion({ this.channel = 'unknown', this.dartSdkVersion = '12', - this.devToolsVersion = '2.8.0', this.engineRevision = 'abcdefghijklmnopqrstuvwxyz', this.engineRevisionShort = 'abcde', this.repositoryUrl = 'https://github.com/flutter/flutter.git', @@ -347,9 +340,6 @@ class FakeFlutterVersion implements FlutterVersion { @override final String channel; - @override - final String devToolsVersion; - @override final String dartSdkVersion; diff --git a/packages/flutter_tools/test/src/pubspec_schema.dart b/packages/flutter_tools/test/src/pubspec_schema.dart index be2aef5e5cdc8..e2b18fa61e41f 100644 --- a/packages/flutter_tools/test/src/pubspec_schema.dart +++ b/packages/flutter_tools/test/src/pubspec_schema.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'package:flutter_tools/src/flutter_manifest.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:yaml/yaml.dart'; import 'common.dart'; diff --git a/packages/flutter_tools/test/src/test_flutter_command_runner.dart b/packages/flutter_tools/test/src/test_flutter_command_runner.dart index b8ad91f76b4f4..3080377f3bc3e 100644 --- a/packages/flutter_tools/test/src/test_flutter_command_runner.dart +++ b/packages/flutter_tools/test/src/test_flutter_command_runner.dart @@ -14,7 +14,7 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/create.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/runner/flutter_command_runner.dart'; diff --git a/packages/flutter_tools/test/src/testbed.dart b/packages/flutter_tools/test/src/testbed.dart index c47037803b789..710fe1619c55a 100644 --- a/packages/flutter_tools/test/src/testbed.dart +++ b/packages/flutter_tools/test/src/testbed.dart @@ -18,7 +18,7 @@ import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/context_runner.dart'; import 'package:flutter_tools/src/dart/pub.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/version.dart'; diff --git a/packages/flutter_tools/test/web.shard/chrome_test.dart b/packages/flutter_tools/test/web.shard/chrome_test.dart index 56225b365b62a..ada39d994e163 100644 --- a/packages/flutter_tools/test/web.shard/chrome_test.dart +++ b/packages/flutter_tools/test/web.shard/chrome_test.dart @@ -490,15 +490,6 @@ void main() { }); testWithoutContext('gives up retrying when an error happens more than 3 times', () async { - final BufferLogger logger = BufferLogger.test(); - final ChromiumLauncher chromiumLauncher = ChromiumLauncher( - fileSystem: fileSystem, - platform: platform, - processManager: processManager, - operatingSystemUtils: operatingSystemUtils, - browserFinder: findChromeExecutable, - logger: logger, - ); for (int i = 0; i < 4; i++) { processManager.addCommand(const FakeCommand( command: <String>[ @@ -517,14 +508,13 @@ void main() { } await expectToolExitLater( - chromiumLauncher.launch( + chromeLauncher.launch( 'example_url', skipCheck: true, headless: true, ), contains('Failed to launch browser.'), ); - expect(logger.errorText, contains('nothing in the std error indicating glibc error')); }); testWithoutContext('Logs an error and exits if connection check fails.', () async { diff --git a/packages/flutter_tools/test/web.shard/output_web_test.dart b/packages/flutter_tools/test/web.shard/output_web_test.dart deleted file mode 100644 index b14660ee4a824..0000000000000 --- a/packages/flutter_tools/test/web.shard/output_web_test.dart +++ /dev/null @@ -1,81 +0,0 @@ -// 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. - -// @dart = 2.8 - -import 'package:file/file.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service/vm_service_io.dart'; - -import '../integration.shard/test_data/basic_project.dart'; -import '../integration.shard/test_driver.dart'; -import '../integration.shard/test_utils.dart'; -import '../src/common.dart'; - -void main() { - Directory tempDir; - final BasicProjectWithUnaryMain project = BasicProjectWithUnaryMain(); - FlutterRunTestDriver flutter; - - setUp(() async { - tempDir = createResolvedTempDirectorySync('run_test.'); - await project.setUpIn(tempDir); - flutter = FlutterRunTestDriver(tempDir); - //flutter.stdout.listen(print); - }); - - tearDown(() async { - await flutter.stop(); - tryToDelete(tempDir); - }); - - Future<void> start({bool verbose = false}) async { - // The non-test project has a loop around its breakpoints. - // No need to start paused as all breakpoint would be eventually reached. - await flutter.run( - withDebugger: true, - chrome: true, - expressionEvaluation: true, - additionalCommandArgs: <String>[ - if (verbose) '--verbose', - '--web-renderer=html', - ]); - } - - Future<void> evaluate() async { - final ObjRef res = - await flutter.evaluate('package:characters/characters.dart', 'true'); - expect(res, isA<InstanceRef>() - .having((InstanceRef o) => o.kind, 'kind', 'Bool')); - } - - Future<void> sendEvent(Map<String, Object> event) async { - final VmService client = await vmServiceConnectUri( - '${flutter.vmServiceWsUri}'); - final Response result = await client.callServiceExtension( - 'ext.dwds.sendEvent', - args: event, - ); - expect(result, isA<Success>()); - await client.dispose(); - } - - testWithoutContext('flutter run outputs info messages from dwds in verbose mode', () async { - final Future<dynamic> info = expectLater( - flutter.stdout, emitsThrough(contains('Loaded debug metadata'))); - await start(verbose: true); - await evaluate(); - await flutter.stop(); - await info; - }); - - testWithoutContext('flutter run outputs warning messages from dwds in non-verbose mode', () async { - final Future<dynamic> warning = expectLater( - flutter.stderr, emitsThrough(contains('Ignoring unknown event'))); - await start(); - await sendEvent(<String, Object>{'type': 'DevtoolsEvent'}); - await warning; - }); -} diff --git a/packages/flutter_tools/test/web.shard/vm_service_web_test.dart b/packages/flutter_tools/test/web.shard/vm_service_web_test.dart index d0f910538f009..d8c8e41a92514 100644 --- a/packages/flutter_tools/test/web.shard/vm_service_web_test.dart +++ b/packages/flutter_tools/test/web.shard/vm_service_web_test.dart @@ -62,7 +62,7 @@ void main() { validateFlutterVersion(client1), validateFlutterVersion(client2)] ); - }); + }, skip: true); // DDS failure: https://github.com/dart-lang/sdk/issues/46696 }); group('Clients of flutter run on web with DDS disabled', () { diff --git a/packages/flutter_tools/tool/global_count.dart b/packages/flutter_tools/tool/global_count.dart index 94ad2461d3ed1..f8b840722ea36 100644 --- a/packages/flutter_tools/tool/global_count.dart +++ b/packages/flutter_tools/tool/global_count.dart @@ -5,32 +5,39 @@ import 'dart:io'; import 'package:path/path.dart' as path; -/// Count the number of libraries that import globals.dart in lib and test. +/// Count the number of libraries that import globals_null_migrated.dart and globals.dart in lib and test. /// /// This must be run from the flutter_tools project root directory. void main() { final Directory sources = Directory(path.join(Directory.current.path, 'lib')); final Directory tests = Directory(path.join(Directory.current.path, 'test')); - final int sourceGlobals = countGlobalImports(sources); - final int testGlobals = countGlobalImports(tests); - print('lib/ contains $sourceGlobals libraries with global usage'); - print('test/ contains $testGlobals libraries with global usage'); + countGlobalImports(sources); + countGlobalImports(tests); } -final RegExp globalImport = RegExp("import.*globals.dart' as globals;"); +final RegExp globalImport = RegExp(r"import.*(?:globals|globals_null_migrated)\.dart' as globals;"); +final RegExp globalNullUnsafeImport = RegExp("import.*globals.dart' as globals;"); -int countGlobalImports(Directory directory) { +void countGlobalImports(Directory directory) { int count = 0; + int nullUnsafeImportCount = 0; for (final FileSystemEntity file in directory.listSync(recursive: true)) { if (!file.path.endsWith('.dart') || file is! File) { continue; } - final bool hasImport = file.readAsLinesSync().any((String line) { + final List<String> fileLines = file.readAsLinesSync(); + final bool hasImport = fileLines.any((String line) { return globalImport.hasMatch(line); }); if (hasImport) { count += 1; } + final bool hasUnsafeImport = fileLines.any((String line) { + return globalNullUnsafeImport.hasMatch(line); + }); + if (hasUnsafeImport) { + nullUnsafeImportCount += 1; + } } - return count; + print('${path.basename(directory.path)} contains $count libraries with global usage ($nullUnsafeImportCount unsafe)'); } diff --git a/packages/flutter_web_plugins/lib/flutter_web_plugins.dart b/packages/flutter_web_plugins/lib/flutter_web_plugins.dart index dda02e2404bcb..97a079d2bd07e 100644 --- a/packages/flutter_web_plugins/lib/flutter_web_plugins.dart +++ b/packages/flutter_web_plugins/lib/flutter_web_plugins.dart @@ -18,6 +18,5 @@ library flutter_web_plugins; export 'src/navigation/js_url_strategy.dart'; export 'src/navigation/url_strategy.dart'; export 'src/navigation/utils.dart'; -export 'src/navigation_common/url_strategy.dart'; export 'src/plugin_event_channel.dart'; export 'src/plugin_registry.dart'; diff --git a/packages/flutter_web_plugins/lib/src/navigation/js_url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation/js_url_strategy.dart index 5e68c310e8bfc..30fba83602dd2 100644 --- a/packages/flutter_web_plugins/lib/src/navigation/js_url_strategy.dart +++ b/packages/flutter_web_plugins/lib/src/navigation/js_url_strategy.dart @@ -16,7 +16,7 @@ import 'dart:ui' as ui; import 'package:js/js.dart'; import 'package:meta/meta.dart'; -import '../navigation_common/url_strategy.dart'; +import 'url_strategy.dart'; typedef _JsSetUrlStrategy = void Function(JsUrlStrategy?); @@ -33,7 +33,7 @@ typedef _PathGetter = String Function(); typedef _StateGetter = Object? Function(); -typedef _AddPopStateListener = ui.VoidCallback Function(EventListener); +typedef _AddPopStateListener = ui.VoidCallback Function(html.EventListener); typedef _StringToString = String Function(String); diff --git a/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart index dbcdd34d67509..27ee4874bac99 100644 --- a/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart +++ b/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart @@ -6,7 +6,6 @@ import 'dart:async'; import 'dart:html' as html; import 'dart:ui' as ui; -import '../navigation_common/url_strategy.dart'; import 'js_url_strategy.dart'; import 'utils.dart'; @@ -41,9 +40,53 @@ void setUrlStrategy(UrlStrategy? strategy) { jsSetUrlStrategy(jsUrlStrategy); } -/// Use the [PathUrlStrategy] to handle the browser URL. -void usePathUrlStrategy() { - setUrlStrategy(PathUrlStrategy()); +/// Represents and reads route state from the browser's URL. +/// +/// By default, the [HashUrlStrategy] subclass is used if the app doesn't +/// specify one. +abstract class UrlStrategy { + /// Abstract const constructor. This constructor enables subclasses to provide + /// const constructors so that they can be used in const expressions. + const UrlStrategy(); + + /// Adds a listener to the `popstate` event and returns a function that, when + /// invoked, removes the listener. + ui.VoidCallback addPopStateListener(html.EventListener fn); + + /// Returns the active path in the browser. + String getPath(); + + /// The state of the current browser history entry. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/state + Object? getState(); + + /// Given a path that's internal to the app, create the external url that + /// will be used in the browser. + String prepareExternalUrl(String internalUrl); + + /// Push a new history entry. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState + void pushState(Object? state, String title, String url); + + /// Replace the currently active history entry. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState + void replaceState(Object? state, String title, String url); + + /// Moves forwards or backwards through the history stack. + /// + /// A negative [count] value causes a backward move in the history stack. And + /// a positive [count] value causes a forward move. + /// + /// Examples: + /// + /// * `go(-2)` moves back 2 steps in history. + /// * `go(3)` moves forward 3 steps in history. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go + Future<void> go(int count); } /// Uses the browser URL's [hash fragments](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) @@ -71,7 +114,7 @@ class HashUrlStrategy extends UrlStrategy { final PlatformLocation _platformLocation; @override - ui.VoidCallback addPopStateListener(EventListener fn) { + ui.VoidCallback addPopStateListener(html.EventListener fn) { _platformLocation.addPopStateListener(fn); return () => _platformLocation.removePopStateListener(fn); } @@ -178,6 +221,76 @@ class PathUrlStrategy extends HashUrlStrategy { } } +/// Encapsulates all calls to DOM apis, which allows the [UrlStrategy] classes +/// to be platform agnostic and testable. +/// +/// For convenience, the [PlatformLocation] class can be used by implementations +/// of [UrlStrategy] to interact with DOM apis like pushState, popState, etc. +abstract class PlatformLocation { + /// Abstract const constructor. This constructor enables subclasses to provide + /// const constructors so that they can be used in const expressions. + const PlatformLocation(); + + /// Registers an event listener for the `popstate` event. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate + void addPopStateListener(html.EventListener fn); + + /// Unregisters the given listener (added by [addPopStateListener]) from the + /// `popstate` event. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate + void removePopStateListener(html.EventListener fn); + + /// The `pathname` part of the URL in the browser address bar. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname + String get pathname; + + /// The `query` part of the URL in the browser address bar. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/Location/search + String get search; + + /// The `hash` part of the URL in the browser address bar. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/Location/hash + String get hash; + + /// The `state` in the current history entry. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/state + Object? get state; + + /// Adds a new entry to the browser history stack. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState + void pushState(Object? state, String title, String url); + + /// Replaces the current entry in the browser history stack. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState + void replaceState(Object? state, String title, String url); + + /// Moves forwards or backwards through the history stack. + /// + /// A negative [count] value causes a backward move in the history stack. And + /// a positive [count] value causes a forward move. + /// + /// Examples: + /// + /// * `go(-2)` moves back 2 steps in history. + /// * `go(3)` moves forward 3 steps in history. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go + void go(int count); + + /// The base href where the Flutter app is being served. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base + String? getBaseHref(); +} + /// Delegates to real browser APIs to provide platform location functionality. class BrowserPlatformLocation extends PlatformLocation { /// Default constructor for [BrowserPlatformLocation]. diff --git a/packages/flutter_web_plugins/lib/src/navigation_common/url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation_common/url_strategy.dart deleted file mode 100644 index 6e5364ab0df59..0000000000000 --- a/packages/flutter_web_plugins/lib/src/navigation_common/url_strategy.dart +++ /dev/null @@ -1,130 +0,0 @@ -// 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:async'; -import 'dart:ui' as ui; - -/// Signature of an html event listener. -/// -/// We have to redefine it because non-web platforms can't import dart:html. -typedef EventListener = dynamic Function(Object event); - -/// Represents and reads route state from the browser's URL. -/// -/// By default, the [HashUrlStrategy] subclass is used if the app doesn't -/// specify one. -abstract class UrlStrategy { - /// Abstract const constructor. This constructor enables subclasses to provide - /// const constructors so that they can be used in const expressions. - const UrlStrategy(); - - /// Adds a listener to the `popstate` event and returns a function that, when - /// invoked, removes the listener. - ui.VoidCallback addPopStateListener(EventListener fn); - - /// Returns the active path in the browser. - String getPath(); - - /// The state of the current browser history entry. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/state - Object? getState(); - - /// Given a path that's internal to the app, create the external url that - /// will be used in the browser. - String prepareExternalUrl(String internalUrl); - - /// Push a new history entry. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState - void pushState(Object? state, String title, String url); - - /// Replace the currently active history entry. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState - void replaceState(Object? state, String title, String url); - - /// Moves forwards or backwards through the history stack. - /// - /// A negative [count] value causes a backward move in the history stack. And - /// a positive [count] value causes a forward move. - /// - /// Examples: - /// - /// * `go(-2)` moves back 2 steps in history. - /// * `go(3)` moves forward 3 steps in history. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go - Future<void> go(int count); -} - -/// Encapsulates all calls to DOM apis, which allows the [UrlStrategy] classes -/// to be platform agnostic and testable. -/// -/// For convenience, the [PlatformLocation] class can be used by implementations -/// of [UrlStrategy] to interact with DOM apis like pushState, popState, etc. -abstract class PlatformLocation { - /// Abstract const constructor. This constructor enables subclasses to provide - /// const constructors so that they can be used in const expressions. - const PlatformLocation(); - - /// Registers an event listener for the `popstate` event. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate - void addPopStateListener(EventListener fn); - - /// Unregisters the given listener (added by [addPopStateListener]) from the - /// `popstate` event. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate - void removePopStateListener(EventListener fn); - - /// The `pathname` part of the URL in the browser address bar. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname - String get pathname; - - /// The `query` part of the URL in the browser address bar. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/Location/search - String get search; - - /// The `hash` part of the URL in the browser address bar. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/Location/hash - String get hash; - - /// The `state` in the current history entry. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/state - Object? get state; - - /// Adds a new entry to the browser history stack. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState - void pushState(Object? state, String title, String url); - - /// Replaces the current entry in the browser history stack. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState - void replaceState(Object? state, String title, String url); - - /// Moves forwards or backwards through the history stack. - /// - /// A negative [count] value causes a backward move in the history stack. And - /// a positive [count] value causes a forward move. - /// - /// Examples: - /// - /// * `go(-2)` moves back 2 steps in history. - /// * `go(3)` moves forward 3 steps in history. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go - void go(int count); - - /// The base href where the Flutter app is being served. - /// - /// See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base - String? getBaseHref(); -} diff --git a/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart deleted file mode 100644 index 76b31baf68f45..0000000000000 --- a/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart +++ /dev/null @@ -1,103 +0,0 @@ -// 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:async'; -import 'dart:ui' as ui; - -import '../navigation_common/url_strategy.dart'; - -/// Returns the present [UrlStrategy] for handling the browser URL. -/// -/// In case null is returned, the browser integration has been manually -/// disabled by [setUrlStrategy]. -UrlStrategy? get urlStrategy => null; - -/// Change the strategy to use for handling browser URL. -/// -/// Setting this to null disables all integration with the browser history. -void setUrlStrategy(UrlStrategy? strategy) { - // No-op in non-web platforms. -} - -/// Use the [PathUrlStrategy] to handle the browser URL. -void usePathUrlStrategy() { - // No-op in non-web platforms. -} - -/// Uses the browser URL's [hash fragments](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) -/// to represent its state. -/// -/// By default, this class is used as the URL strategy for the app. However, -/// this class is still useful for apps that want to extend it. -/// -/// In order to use [HashUrlStrategy] for an app, it needs to be set like this: -/// -/// ```dart -/// import 'package:flutter_web_plugins/flutter_web_plugins.dart'; -/// -/// // Somewhere before calling `runApp()` do: -/// setUrlStrategy(const HashUrlStrategy()); -/// ``` -class HashUrlStrategy extends UrlStrategy { - /// Creates an instance of [HashUrlStrategy]. - /// - /// The [PlatformLocation] parameter is useful for testing to mock out browser - /// interations. - const HashUrlStrategy([PlatformLocation? _]); - - @override - ui.VoidCallback addPopStateListener(EventListener fn) { - // No-op. - return () {}; - } - - @override - String getPath() => ''; - - @override - Object? getState() => null; - - @override - String prepareExternalUrl(String internalUrl) => ''; - - @override - void pushState(Object? state, String title, String url) { - // No-op. - } - - @override - void replaceState(Object? state, String title, String url) { - // No-op. - } - - @override - Future<void> go(int count) async { - // No-op. - } -} - -/// Uses the browser URL's pathname to represent Flutter's route name. -/// -/// In order to use [PathUrlStrategy] for an app, it needs to be set like this: -/// -/// ```dart -/// import 'package:flutter_web_plugins/flutter_web_plugins.dart'; -/// -/// // Somewhere before calling `runApp()` do: -/// setUrlStrategy(PathUrlStrategy()); -/// ``` -class PathUrlStrategy extends HashUrlStrategy { - /// Creates an instance of [PathUrlStrategy]. - /// - /// The [PlatformLocation] parameter is useful for testing to mock out browser - /// interations. - PathUrlStrategy([PlatformLocation? _platformLocation]) - : super(_platformLocation); - - @override - String getPath() => ''; - - @override - String prepareExternalUrl(String internalUrl) => ''; -} diff --git a/packages/flutter_web_plugins/lib/url_strategy.dart b/packages/flutter_web_plugins/lib/url_strategy.dart deleted file mode 100644 index c40b9a2bafc73..0000000000000 --- a/packages/flutter_web_plugins/lib/url_strategy.dart +++ /dev/null @@ -1,8 +0,0 @@ -// 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. - -export 'src/navigation_common/url_strategy.dart'; - -export 'src/navigation_non_web/url_strategy.dart' - if (dart.library.html) 'src/navigation/url_strategy.dart'; diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index 8a0eff8bc9517..dbdd9b45feb52 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_web_plugins description: Library to register Flutter Web plugins -homepage: https://flutter.dev +homepage: http://flutter.dev environment: sdk: ">=2.12.0-0 <3.0.0" @@ -9,11 +9,10 @@ dependencies: flutter: sdk: flutter - js: 0.6.4 + js: 0.6.3 characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,12 +27,12 @@ dev_dependencies: clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: d6ad +# PUBSPEC CHECKSUM: a548 diff --git a/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart b/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart index d5d1022a54ecb..aa919d48cbadb 100644 --- a/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart +++ b/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:html'; + @TestOn('chrome') // Uses web-only Flutter SDK import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 5449a9084f4f5..1af1b21d93b9a 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -1,25 +1,25 @@ name: fuchsia_remote_debug_protocol publish_to: none description: Provides an API to test/debug Flutter applications on remote Fuchsia devices and emulators. -homepage: https://flutter.dev +homepage: http://flutter.dev environment: sdk: '>=2.12.0-0 <3.0.0' dependencies: process: 4.2.4 - vm_service: 7.5.0 + vm_service: 7.3.0 file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.20.1 + test: 1.17.12 - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,12 +34,13 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,8 +54,8 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +66,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: a4e5 +# PUBSPEC CHECKSUM: 7bad diff --git a/packages/fuchsia_remote_debug_protocol/test/src/runners/ssh_command_runner_test.dart b/packages/fuchsia_remote_debug_protocol/test/src/runners/ssh_command_runner_test.dart index c8de26eceeef4..e217b5feb8765 100644 --- a/packages/fuchsia_remote_debug_protocol/test/src/runners/ssh_command_runner_test.dart +++ b/packages/fuchsia_remote_debug_protocol/test/src/runners/ssh_command_runner_test.dart @@ -136,8 +136,8 @@ class FakeProcessManager extends Fake implements ProcessManager { Map<String, String>? environment, bool includeParentEnvironment = true, bool runInShell = false, - Encoding? stdoutEncoding = systemEncoding, - Encoding? stderrEncoding = systemEncoding, + Encoding stdoutEncoding = systemEncoding, + Encoding stderrEncoding = systemEncoding, }) async { runCommands.add(command); return fakeResult!; diff --git a/packages/integration_test/android/build.gradle b/packages/integration_test/android/build.gradle index f617e1229662d..3f358c00cb584 100644 --- a/packages/integration_test/android/build.gradle +++ b/packages/integration_test/android/build.gradle @@ -26,7 +26,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { - compileSdkVersion 31 + compileSdkVersion 30 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/packages/integration_test/example/android/app/src/main/AndroidManifest.xml b/packages/integration_test/example/android/app/src/main/AndroidManifest.xml index be166c6476845..32833b71c97ed 100644 --- a/packages/integration_test/example/android/app/src/main/AndroidManifest.xml +++ b/packages/integration_test/example/android/app/src/main/AndroidManifest.xml @@ -5,13 +5,13 @@ found in the LICENSE file. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.integration_test_example"> - <!-- ${applicationName} is used by the Flutter tool to select the Application - class to use. For most apps, this is the default Android application. + <!-- io.flutter.app.FlutterApplication is an android.app.Application that + calls FlutterMain.startInitialization(this); in its onCreate method. In most cases you can leave this as-is, but you if you want to provide additional functionality it is fine to subclass or reimplement - Application and put your custom class here. --> + FlutterApplication and put your custom class here. --> <application - android:name="${applicationName}" + android:name="io.flutter.app.FlutterApplication" android:label="integration_test_example" android:icon="@mipmap/ic_launcher"> <activity diff --git a/packages/integration_test/example/android/project-app.lockfile b/packages/integration_test/example/android/project-app.lockfile index 20d03d2d63b60..6b9673b6683c8 100644 --- a/packages/integration_test/example/android/project-app.lockfile +++ b/packages/integration_test/example/android/project-app.lockfile @@ -26,8 +26,6 @@ androidx.test:runner:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRunt androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -101,18 +99,11 @@ org.hamcrest:hamcrest-integration:1.3=debugAndroidTestCompileClasspath,debugAndr org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/packages/integration_test/example/android/project-integration_test.lockfile b/packages/integration_test/example/android/project-integration_test.lockfile index ca99c9e81b5be..4311264526585 100644 --- a/packages/integration_test/example/android/project-integration_test.lockfile +++ b/packages/integration_test/example/android/project-integration_test.lockfile @@ -26,8 +26,6 @@ androidx.test:runner:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRunt androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window-java:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.window:window:1.0.0-beta03=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.android.tools.analytics-library:protos:27.1.3=lintClassPath com.android.tools.analytics-library:shared:27.1.3=lintClassPath com.android.tools.analytics-library:tracker:27.1.3=lintClassPath @@ -101,18 +99,11 @@ org.hamcrest:hamcrest-integration:1.3=debugAndroidTestCompileClasspath,debugAndr org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlin:kotlin-stdlib:1.3.72=lintClassPath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.trove4j:trove4j:20160824=lintClassPath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=lintClassPath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-commons:7.0=lintClassPath diff --git a/packages/integration_test/example/integration_test/_extended_test_io.dart b/packages/integration_test/example/integration_test/_extended_test_io.dart index 8c2456ac414e1..377aa42995a5d 100644 --- a/packages/integration_test/example/integration_test/_extended_test_io.dart +++ b/packages/integration_test/example/integration_test/_extended_test_io.dart @@ -25,24 +25,6 @@ void main() { // Build our app. app.main(); - // Pump a frame. - await tester.pumpAndSettle(); - - // Verify that platform version is retrieved. - expect( - find.byWidgetPredicate( - (Widget widget) => - widget is Text && - widget.data!.startsWith('Platform: ${Platform.operatingSystem}'), - ), - findsOneWidget, - ); - }); - - testWidgets('verify screenshot', (WidgetTester tester) async { - // Build our app. - app.main(); - // On Android, this is required prior to taking the screenshot. await binding.convertFlutterSurfaceToImage(); @@ -57,5 +39,15 @@ void main() { expect(secondPng.isNotEmpty, isTrue); expect(listEquals(firstPng, secondPng), isTrue); + + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => + widget is Text && + widget.data!.startsWith('Platform: ${Platform.operatingSystem}'), + ), + findsOneWidget, + ); }); } diff --git a/packages/integration_test/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/integration_test/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index bfcb53e32946a..1e6676d02b023 100644 --- a/packages/integration_test/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/integration_test/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -20,20 +20,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> </BuildableReference> </BuildActionEntry> - <BuildActionEntry - buildForTesting = "YES" - buildForRunning = "NO" - buildForProfiling = "NO" - buildForArchiving = "NO" - buildForAnalyzing = "YES"> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "769541C723A0351900E5C350" - BuildableName = "RunnerTests.xctest" - BlueprintName = "RunnerTests" - ReferencedContainer = "container:Runner.xcodeproj"> - </BuildableReference> - </BuildActionEntry> </BuildActionEntries> </BuildAction> <TestAction diff --git a/packages/integration_test/example/ios/RunnerTests/RunnerTests.m b/packages/integration_test/example/ios/RunnerTests/RunnerTests.m index d3bdcc6604dd0..edd7f102c7b17 100644 --- a/packages/integration_test/example/ios/RunnerTests/RunnerTests.m +++ b/packages/integration_test/example/ios/RunnerTests/RunnerTests.m @@ -5,89 +5,4 @@ @import XCTest; @import integration_test; -#pragma mark - Dynamic tests - INTEGRATION_TEST_IOS_RUNNER(RunnerTests) - -@interface RunnerTests (DynamicTests) -@end - -@implementation RunnerTests (DynamicTests) - -- (void)setUp { - // Verify tests have been dynamically added from FLUTTER_TARGET=integration_test/extended_test.dart - XCTAssertTrue([self respondsToSelector:NSSelectorFromString(@"testVerifyScreenshot")]); - XCTAssertTrue([self respondsToSelector:NSSelectorFromString(@"testVerifyText")]); - XCTAssertTrue([self respondsToSelector:NSSelectorFromString(@"screenshotPlaceholder")]); -} - -@end - -#pragma mark - Fake test results - -@interface IntegrationTestPlugin () -- (instancetype)initForRegistration; -@end - -@interface FLTIntegrationTestRunner () -@property IntegrationTestPlugin *integrationTestPlugin; -@end - -@interface FakeIntegrationTestPlugin : IntegrationTestPlugin -@property(nonatomic, nullable) NSDictionary<NSString *, NSString *> *testResults; -@end - -@implementation FakeIntegrationTestPlugin -@synthesize testResults; - -- (void)setupChannels:(id<FlutterBinaryMessenger>)binaryMessenger { -} - -@end - -#pragma mark - Behavior tests - -@interface IntegrationTestTests : XCTestCase -@end - -@implementation IntegrationTestTests - -- (void)testDeprecatedIntegrationTest { - NSString *testResult; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - BOOL testPass = [[IntegrationTestIosTest new] testIntegrationTest:&testResult]; -#pragma clang diagnostic pop - XCTAssertTrue(testPass, @"%@", testResult); -} - -- (void)testMethodNamesFromDartTests { - XCTAssertEqualObjects([FLTIntegrationTestRunner - testCaseNameFromDartTestName:@"this is a test"], @"testThisIsATest"); - XCTAssertEqualObjects([FLTIntegrationTestRunner - testCaseNameFromDartTestName:@"VALIDATE multi-point 🚀 UNICODE123: 😁"], @"testValidateMultiPointUnicode123"); - XCTAssertEqualObjects([FLTIntegrationTestRunner - testCaseNameFromDartTestName:@"!UPPERCASE:\\ lower_seperate?"], @"testUppercaseLowerSeperate"); -} - -- (void)testDuplicatedDartTests { - FakeIntegrationTestPlugin *fakePlugin = [[FakeIntegrationTestPlugin alloc] initForRegistration]; - // These are unique test names in dart, but would result in duplicate - // XCTestCase names when the emojis are stripped. - fakePlugin.testResults = @{@"unique": @"dart test failure", @"emoji 🐢": @"success", @"emoji 🐇": @"failure"}; - - FLTIntegrationTestRunner *runner = [[FLTIntegrationTestRunner alloc] init]; - runner.integrationTestPlugin = fakePlugin; - - NSMutableDictionary<NSString *, NSString *> *failuresByTestName = [[NSMutableDictionary alloc] init]; - [runner testIntegrationTestWithResults:^(SEL nativeTestSelector, BOOL success, NSString *failureMessage) { - NSString *testName = NSStringFromSelector(nativeTestSelector); - XCTAssertFalse([failuresByTestName.allKeys containsObject:testName]); - failuresByTestName[testName] = failureMessage; - }]; - XCTAssertEqualObjects(failuresByTestName, - (@{@"testUnique": @"dart test failure", - @"testDuplicateTestNames": @"Cannot test \"emoji 🐇\", duplicate XCTestCase tests named testEmoji"})); -} - -@end diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 5bf0e50bfe798..4810013fa97ed 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -10,11 +10,10 @@ dependencies: flutter: sdk: flutter - cupertino_icons: 1.0.4 + cupertino_icons: 1.0.3 characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,15 +27,15 @@ dev_dependencies: sdk: flutter integration_test_macos: path: ../integration_test_macos - test: 1.20.1 + test: 1.17.12 pedantic: 1.11.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - _fe_analyzer_shared: 33.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 30.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,13 +52,13 @@ dev_dependencies: http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,9 +73,9 @@ dev_dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 7.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 7.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -86,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 7638 +# PUBSPEC CHECKSUM: 03d7 diff --git a/packages/integration_test/integration_test_macos/ios/integration_test_macos.podspec b/packages/integration_test/integration_test_macos/ios/integration_test_macos.podspec index 6034ec28510d0..8e39e51228459 100644 --- a/packages/integration_test/integration_test_macos/ios/integration_test_macos.podspec +++ b/packages/integration_test/integration_test_macos/ios/integration_test_macos.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |s| No-op implementation of integration to avoid build issues on iOS. See https://github.com/flutter/flutter/issues/39659 DESC - s.homepage = 'https://github.com/flutter/flutter/tree/master/packages/integration_test/integration_test_macos' + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/integration_test/integration_test_macos' s.license = { :file => '../LICENSE' } s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } s.source = { :path => '.' } diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml index 851b24c48483f..8b2c3b5ab1f88 100644 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ b/packages/integration_test/integration_test_macos/pubspec.yaml @@ -1,7 +1,7 @@ name: integration_test_macos description: Desktop implementation of integration_test plugin version: 0.0.1+1 -homepage: https://github.com/flutter/flutter/tree/master/packages/integration_test/integration_test_macos +homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test/integration_test_macos flutter: plugin: @@ -18,7 +18,6 @@ dependencies: characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,4 +25,4 @@ dependencies: dev_dependencies: pedantic: 1.11.1 -# PUBSPEC CHECKSUM: d493 +# PUBSPEC CHECKSUM: c036 diff --git a/packages/integration_test/ios/Classes/FLTIntegrationTestRunner.h b/packages/integration_test/ios/Classes/FLTIntegrationTestRunner.h deleted file mode 100644 index 65568fc71173d..0000000000000 --- a/packages/integration_test/ios/Classes/FLTIntegrationTestRunner.h +++ /dev/null @@ -1,36 +0,0 @@ -// 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 Foundation; - -@class UIImage; - -NS_ASSUME_NONNULL_BEGIN - -typedef void (^FLTIntegrationTestResults)(SEL nativeTestSelector, BOOL success, NSString *_Nullable failureMessage); - -@interface FLTIntegrationTestRunner : NSObject - -/** - * Any screenshots captured by the plugin. - */ -@property (copy, readonly) NSDictionary<NSString *, UIImage *> *capturedScreenshotsByName; - -/** - * Starts dart tests and waits for results. - * - * @param testResult Will be called once per every completed dart test. - */ -- (void)testIntegrationTestWithResults:(NS_NOESCAPE FLTIntegrationTestResults)testResult; - -/** - * An appropriate XCTest method name based on the dart test name. - * - * Example: dart test "verify widget-ABC123" becomes "testVerifyWidgetABC123" - */ -+ (NSString *)testCaseNameFromDartTestName:(NSString *)dartTestName; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/integration_test/ios/Classes/FLTIntegrationTestRunner.m b/packages/integration_test/ios/Classes/FLTIntegrationTestRunner.m deleted file mode 100644 index 286465c53c003..0000000000000 --- a/packages/integration_test/ios/Classes/FLTIntegrationTestRunner.m +++ /dev/null @@ -1,77 +0,0 @@ -// 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 "FLTIntegrationTestRunner.h" - -#import "IntegrationTestPlugin.h" - -@import ObjectiveC.runtime; -@import UIKit; - -@interface FLTIntegrationTestRunner () - -@property IntegrationTestPlugin *integrationTestPlugin; - -@end - -@implementation FLTIntegrationTestRunner - -- (instancetype)init { - self = [super init]; - _integrationTestPlugin = [IntegrationTestPlugin instance]; - - return self; -} - -- (void)testIntegrationTestWithResults:(NS_NOESCAPE FLTIntegrationTestResults)testResult { - IntegrationTestPlugin *integrationTestPlugin = self.integrationTestPlugin; - UIViewController *rootViewController = UIApplication.sharedApplication.delegate.window.rootViewController; - if (![rootViewController isKindOfClass:[FlutterViewController class]]) { - testResult(NSSelectorFromString(@"testSetup"), NO, @"rootViewController was not expected FlutterViewController"); - } - FlutterViewController *flutterViewController = (FlutterViewController *)rootViewController; - [integrationTestPlugin setupChannels:flutterViewController.engine.binaryMessenger]; - - // Spin the runloop. - while (!integrationTestPlugin.testResults) { - [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; - } - - NSMutableSet<NSString *> *testCaseNames = [[NSMutableSet alloc] init]; - - [integrationTestPlugin.testResults enumerateKeysAndObjectsUsingBlock:^(NSString *test, NSString *result, BOOL *stop) { - NSString *testSelectorName = [[self class] testCaseNameFromDartTestName:test]; - - // Validate Objective-C test names are unique after sanitization. - if ([testCaseNames containsObject:testSelectorName]) { - NSString *reason = [NSString stringWithFormat:@"Cannot test \"%@\", duplicate XCTestCase tests named %@", test, testSelectorName]; - testResult(NSSelectorFromString(@"testDuplicateTestNames"), NO, reason); - *stop = YES; - return; - } - [testCaseNames addObject:testSelectorName]; - SEL testSelector = NSSelectorFromString(testSelectorName); - - if ([result isEqualToString:@"success"]) { - testResult(testSelector, YES, nil); - } else { - testResult(testSelector, NO, result); - } - }]; -} - -- (NSDictionary<NSString *,UIImage *> *)capturedScreenshotsByName { - return self.integrationTestPlugin.capturedScreenshotsByName; -} - -+ (NSString *)testCaseNameFromDartTestName:(NSString *)dartTestName { - NSString *capitalizedString = dartTestName.localizedCapitalizedString; - // Objective-C method names must be alphanumeric. - NSCharacterSet *disallowedCharacters = NSCharacterSet.alphanumericCharacterSet.invertedSet; - // Remove disallowed characters. - NSString *upperCamelTestName = [[capitalizedString componentsSeparatedByCharactersInSet:disallowedCharacters] componentsJoinedByString:@""]; - return [NSString stringWithFormat:@"test%@", upperCamelTestName]; -} - -@end diff --git a/packages/integration_test/ios/Classes/IntegrationTestIosTest.h b/packages/integration_test/ios/Classes/IntegrationTestIosTest.h index 33aaea52a10ce..cac3be43fd5c8 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestIosTest.h +++ b/packages/integration_test/ios/Classes/IntegrationTestIosTest.h @@ -2,14 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import Foundation; -@import ObjectiveC.runtime; +#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN -DEPRECATED_MSG_ATTRIBUTE("Use FLTIntegrationTestRunner instead.") +@protocol FLTIntegrationTestScreenshotDelegate; + @interface IntegrationTestIosTest : NSObject +- (instancetype)initWithScreenshotDelegate:(nullable id<FLTIntegrationTestScreenshotDelegate>)delegate NS_DESIGNATED_INITIALIZER; + /** * Initiate dart tests and wait for results. @c testResult will be set to a string describing the results. * @@ -19,48 +21,26 @@ DEPRECATED_MSG_ATTRIBUTE("Use FLTIntegrationTestRunner instead.") @end -// For every Flutter dart test, dynamically generate an Objective-C method mirroring the test results -// so it is reported as a native XCTest run result. -// If the Flutter dart tests have captured screenshots, add them to the XCTest bundle. #define INTEGRATION_TEST_IOS_RUNNER(__test_class) \ - @interface __test_class : XCTestCase \ + @interface __test_class : XCTestCase<FLTIntegrationTestScreenshotDelegate> \ @end \ \ @implementation __test_class \ \ - + (NSArray<NSInvocation *> *)testInvocations { \ - FLTIntegrationTestRunner *integrationTestRunner = [[FLTIntegrationTestRunner alloc] init]; \ - NSMutableArray<NSInvocation *> *testInvocations = [[NSMutableArray alloc] init]; \ - [integrationTestRunner testIntegrationTestWithResults:^(SEL testSelector, BOOL success, NSString *failureMessage) { \ - IMP assertImplementation = imp_implementationWithBlock(^(id _self) { \ - XCTAssertTrue(success, @"%@", failureMessage); \ - }); \ - class_addMethod(self, testSelector, assertImplementation, "v@:"); \ - NSMethodSignature *signature = [self instanceMethodSignatureForSelector:testSelector]; \ - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; \ - invocation.selector = testSelector; \ - [testInvocations addObject:invocation]; \ - }]; \ - NSDictionary<NSString *, UIImage *> *capturedScreenshotsByName = integrationTestRunner.capturedScreenshotsByName; \ - if (capturedScreenshotsByName.count > 0) { \ - IMP screenshotImplementation = imp_implementationWithBlock(^(id _self) { \ - [capturedScreenshotsByName enumerateKeysAndObjectsUsingBlock:^(NSString *name, UIImage *screenshot, BOOL *stop) { \ - XCTAttachment *attachment = [XCTAttachment attachmentWithImage:screenshot]; \ - attachment.lifetime = XCTAttachmentLifetimeKeepAlways; \ - if (name != nil) { \ - attachment.name = name; \ - } \ - [_self addAttachment:attachment]; \ - }]; \ - }); \ - SEL attachmentSelector = NSSelectorFromString(@"screenshotPlaceholder"); \ - class_addMethod(self, attachmentSelector, screenshotImplementation, "v@:"); \ - NSMethodSignature *attachmentSignature = [self instanceMethodSignatureForSelector:attachmentSelector]; \ - NSInvocation *attachmentInvocation = [NSInvocation invocationWithMethodSignature:attachmentSignature]; \ - attachmentInvocation.selector = attachmentSelector; \ - [testInvocations addObject:attachmentInvocation]; \ + - (void)testIntegrationTest { \ + NSString *testResult; \ + IntegrationTestIosTest *integrationTestIosTest = integrationTestIosTest = [[IntegrationTestIosTest alloc] initWithScreenshotDelegate:self]; \ + BOOL testPass = [integrationTestIosTest testIntegrationTest:&testResult]; \ + XCTAssertTrue(testPass, @"%@", testResult); \ + } \ + \ + - (void)didTakeScreenshot:(UIImage *)screenshot attachmentName:(NSString *)name { \ + XCTAttachment *attachment = [XCTAttachment attachmentWithImage:screenshot]; \ + attachment.lifetime = XCTAttachmentLifetimeKeepAlways; \ + if (name != nil) { \ + attachment.name = name; \ } \ - return testInvocations; \ + [self addAttachment:attachment]; \ } \ \ @end diff --git a/packages/integration_test/ios/Classes/IntegrationTestIosTest.m b/packages/integration_test/ios/Classes/IntegrationTestIosTest.m index 808fa94eac0f2..6a54ed2c77dc5 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestIosTest.m +++ b/packages/integration_test/ios/Classes/IntegrationTestIosTest.m @@ -3,40 +3,61 @@ // found in the LICENSE file. #import "IntegrationTestIosTest.h" - #import "IntegrationTestPlugin.h" -#import "FLTIntegrationTestRunner.h" - -#pragma mark - Deprecated -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" +@interface IntegrationTestIosTest() +@property (nonatomic) IntegrationTestPlugin *integrationTestPlugin; +@end @implementation IntegrationTestIosTest +- (instancetype)initWithScreenshotDelegate:(id<FLTIntegrationTestScreenshotDelegate>)delegate { + self = [super init]; + _integrationTestPlugin = [IntegrationTestPlugin instance]; + _integrationTestPlugin.screenshotDelegate = delegate; + return self; +} + +- (instancetype)init { + return [self initWithScreenshotDelegate:nil]; +} + - (BOOL)testIntegrationTest:(NSString **)testResult { - NSLog(@"==================== Test Results ====================="); + IntegrationTestPlugin *integrationTestPlugin = self.integrationTestPlugin; + + UIViewController *rootViewController = + [[[[UIApplication sharedApplication] delegate] window] rootViewController]; + if (![rootViewController isKindOfClass:[FlutterViewController class]]) { + NSLog(@"expected FlutterViewController as rootViewController."); + return NO; + } + FlutterViewController *flutterViewController = (FlutterViewController *)rootViewController; + [integrationTestPlugin setupChannels:flutterViewController.engine.binaryMessenger]; + while (!integrationTestPlugin.testResults) { + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.f, NO); + } + NSDictionary<NSString *, NSString *> *testResults = integrationTestPlugin.testResults; + NSMutableArray<NSString *> *passedTests = [NSMutableArray array]; NSMutableArray<NSString *> *failedTests = [NSMutableArray array]; - NSMutableArray<NSString *> *testNames = [NSMutableArray array]; - [[FLTIntegrationTestRunner new] testIntegrationTestWithResults:^(SEL testSelector, BOOL success, NSString *message) { - NSString *testName = NSStringFromSelector(testSelector); - [testNames addObject:testName]; - if (success) { - NSLog(@"%@ passed.", testName); + NSLog(@"==================== Test Results ====================="); + for (NSString *test in testResults.allKeys) { + NSString *result = testResults[test]; + if ([result isEqualToString:@"success"]) { + NSLog(@"%@ passed.", test); + [passedTests addObject:test]; } else { - NSLog(@"%@ failed: %@", testName, message); - [failedTests addObject:testName]; + NSLog(@"%@ failed: %@", test, result); + [failedTests addObject:test]; } - }]; + } NSLog(@"================== Test Results End ===================="); BOOL testPass = failedTests.count == 0; - if (!testPass && testResult != NULL) { + if (!testPass && testResult) { *testResult = [NSString stringWithFormat:@"Detected failed integration test(s) %@ among %@", - failedTests.description, testNames.description]; + failedTests.description, testResults.allKeys.description]; } return testPass; } @end -#pragma clang diagnostic pop diff --git a/packages/integration_test/ios/Classes/IntegrationTestPlugin.h b/packages/integration_test/ios/Classes/IntegrationTestPlugin.h index 4836339a5fdf3..9684835acf1b9 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestPlugin.h +++ b/packages/integration_test/ios/Classes/IntegrationTestPlugin.h @@ -6,6 +6,13 @@ NS_ASSUME_NONNULL_BEGIN +@protocol FLTIntegrationTestScreenshotDelegate + +/** This will be called when a dart integration test triggers a window screenshot with @c takeScreenshot. */ +- (void)didTakeScreenshot:(UIImage *)screenshot attachmentName:(nullable NSString *)name; + +@end + /** A Flutter plugin that's responsible for communicating the test results back * to iOS XCTest. */ @interface IntegrationTestPlugin : NSObject <FlutterPlugin> @@ -16,11 +23,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, readonly, nullable) NSDictionary<NSString *, NSString *> *testResults; -/** - * Mapping of screenshot images by suggested names, captured by the dart tests. - */ -@property (copy, readonly) NSDictionary<NSString *, UIImage *> *capturedScreenshotsByName; - /** Fetches the singleton instance of the plugin. */ + (IntegrationTestPlugin *)instance; @@ -28,6 +30,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; +@property(weak, nonatomic) id<FLTIntegrationTestScreenshotDelegate> screenshotDelegate; + @end NS_ASSUME_NONNULL_END diff --git a/packages/integration_test/ios/Classes/IntegrationTestPlugin.m b/packages/integration_test/ios/Classes/IntegrationTestPlugin.m index a8a80b6785b66..82d263595ea0e 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestPlugin.m +++ b/packages/integration_test/ios/Classes/IntegrationTestPlugin.m @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "IntegrationTestPlugin.h" - @import UIKit; +#import "IntegrationTestPlugin.h" + static NSString *const kIntegrationTestPluginChannel = @"plugins.flutter.io/integration_test"; static NSString *const kMethodTestFinished = @"allTestsFinished"; static NSString *const kMethodScreenshot = @"captureScreenshot"; @@ -16,13 +16,10 @@ @interface IntegrationTestPlugin () @property(nonatomic, readwrite) NSDictionary<NSString *, NSString *> *testResults; -- (instancetype)init NS_DESIGNATED_INITIALIZER; - @end @implementation IntegrationTestPlugin { NSDictionary<NSString *, NSString *> *_testResults; - NSMutableDictionary<NSString *, UIImage *> *_capturedScreenshotsByName; } + (IntegrationTestPlugin *)instance { @@ -35,13 +32,7 @@ + (IntegrationTestPlugin *)instance { } - (instancetype)initForRegistration { - return [self init]; -} - -- (instancetype)init { - self = [super init]; - _capturedScreenshotsByName = [NSMutableDictionary new]; - return self; + return [super init]; } + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar { @@ -68,7 +59,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result // If running as a native Xcode test, attach to test. UIImage *screenshot = [self capturePngScreenshot]; NSString *name = call.arguments[@"name"]; - _capturedScreenshotsByName[name] = screenshot; + [self.screenshotDelegate didTakeScreenshot:screenshot attachmentName:name]; // Also pass back along the channel for the driver to handle. NSData *pngData = UIImagePNGRepresentation(screenshot); diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index e2961a28f9dc9..5315e801ff130 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -12,10 +12,10 @@ dependencies: sdk: flutter flutter_test: sdk: flutter - path: 1.8.1 - vm_service: 7.5.0 + path: 1.8.0 + vm_service: 7.3.0 - archive: 3.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,7 +26,6 @@ dependencies: fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,7 +33,7 @@ dependencies: string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,4 +47,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: e964 +# PUBSPEC CHECKSUM: b8fb From af52d4f6e938388be3072f4ed629cfd8be044d83 Mon Sep 17 00:00:00 2001 From: Zach Shames <zlshames@users.noreply.github.com> Date: Sun, 16 Jan 2022 10:33:19 -0500 Subject: [PATCH 21/41] Revert "Zach/commit mimes" --- .ci.yaml | 17 ++--- .cirrus.yml | 2 +- bin/internal/engine.version | 2 +- .../flutter/lib/src/cupertino/text_field.dart | 46 ------------ .../flutter/lib/src/material/text_field.dart | 44 ------------ .../flutter/lib/src/services/text_input.dart | 46 ------------ .../lib/src/widgets/editable_text.dart | 45 ------------ packages/flutter_tools/bin/podhelper.rb | 11 +-- .../ios_content_validation_test.dart | 70 +++---------------- 9 files changed, 24 insertions(+), 259 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 8b6f69430c567..3be70a9db8e67 100755 --- a/.ci.yaml +++ b/.ci.yaml @@ -9,7 +9,9 @@ enabled_branches: - flutter-2.8-candidate.3 - main - master - - flutter-\d+\.\d+-candidate\.\d+ + - dev + - beta + - stable platform_properties: linux: @@ -86,7 +88,7 @@ platform_properties: {"dependency": "chrome_and_driver", "version": "version:84"}, {"dependency": "open_jdk"} ] - os: Mac-12.0 + os: Mac-10.15 device_os: N mac_ios: properties: @@ -107,9 +109,9 @@ platform_properties: {"dependency": "gems"}, {"dependency": "ios_signing"} ] - os: Mac-12.0 - device_os: iOS-15.1 - xcode: 13a233 + os: Mac-10.15 + device_os: iOS-14.4.2 + xcode: 12c33 mac_ios32: properties: caches: >- @@ -129,9 +131,9 @@ platform_properties: {"dependency": "gems"}, {"dependency": "ios_signing"} ] - os: Mac-12.0 + os: Mac-10.15 device_os: iOS-9.3.6 - xcode: 13a233 + xcode: 12c33 windows: properties: caches: >- @@ -2264,7 +2266,6 @@ targets: - name: Mac module_test_ios recipe: devicelab/devicelab_drone - bringup: true # Flaky https://github.com/flutter/flutter/issues/93517 timeout: 60 properties: caches: >- diff --git a/.cirrus.yml b/.cirrus.yml index 1da3b938cbaf7..f73e1dcb2d546 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -12,7 +12,7 @@ environment: # dependency on precisely how Cirrus is detected by our tools. BOT: "true" -gcp_credentials: ENCRYPTED[!cc769765170bebc37e0556e2da5915ca64ee37f4ec8c966ec147e2f59578b476c99e457eafce4e2f8b1a4e305f7096b8!] +gcp_credentials: ENCRYPTED[!48cff44dd32e9cc412d4d381c7fe68d373ca04cf2639f8192d21cb1a9ab5e21129651423a1cf88f3fd7fe2125c1cabd9!] # LINUX SHARDS task: diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e4d51ed7cc425..19bc71393b394 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -890a5fca2e34db413be624fc83aeea8e61d42ce6 +40a99c595137e4b2f5b2efa8ff343ea23c1e16b8 diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index 2631716cf3f67..353bf936dd1ad 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -294,7 +294,6 @@ class CupertinoTextField extends StatefulWidget { this.scrollController, this.scrollPhysics, this.autofillHints = const <String>[], - this.contentCommitMimeTypes = const <String>[], this.clipBehavior = Clip.hardEdge, this.restorationId, this.enableIMEPersonalizedLearning = true, @@ -340,7 +339,6 @@ class CupertinoTextField extends StatefulWidget { 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', ), assert(enableIMEPersonalizedLearning != null), - assert(contentCommitMimeTypes != null), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), toolbarOptions = toolbarOptions ?? (obscureText ? const ToolbarOptions( @@ -457,7 +455,6 @@ class CupertinoTextField extends StatefulWidget { this.clipBehavior = Clip.hardEdge, this.restorationId, this.enableIMEPersonalizedLearning = true, - this.contentCommitMimeTypes = const <String> [], }) : assert(textAlign != null), assert(readOnly != null), assert(autofocus != null), @@ -501,7 +498,6 @@ class CupertinoTextField extends StatefulWidget { ), assert(clipBehavior != null), assert(enableIMEPersonalizedLearning != null), - assert(contentCommitMimeTypes!= null), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), toolbarOptions = toolbarOptions ?? (obscureText ? const ToolbarOptions( @@ -854,47 +850,6 @@ class CupertinoTextField extends StatefulWidget { /// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning} final bool enableIMEPersonalizedLearning; - /// Used when a user inserts image-based content through the device keyboard - /// on Android only. - /// - /// The passed list of strings will determine which MIME types are allowed to - /// be inserted via the device keyboard - /// - /// This example shows how to limit your keyboard commits to specific file types - /// `TextField`. - /// - /// ```dart - /// final TextEditingController _controller = TextEditingController(); - /// - /// @override - /// void dispose() { - /// _controller.dispose(); - /// super.dispose(); - /// } - /// - /// @override - /// Widget build(BuildContext context) { - /// return Scaffold( - /// body: Column( - /// mainAxisAlignment: MainAxisAlignment.center, - /// children: <Widget>[ - /// const Text('Here's a text field that supports inserting gif content:'), - /// TextField( - /// controller: _controller, - /// contentCommitMimeTypes: ['image/gif', 'image/png'], - /// onContentCommitted: (CommittedContent data) async { - /// ... - /// }, - /// ), - /// ], - /// ), - /// ); - /// } - /// ``` - /// {@end-tool} - /// {@endtemplate} - final List<String> contentCommitMimeTypes; - @override State<CupertinoTextField> createState() => _CupertinoTextFieldState(); @@ -938,7 +893,6 @@ class CupertinoTextField extends StatefulWidget { properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior, defaultValue: Clip.hardEdge)); properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true)); - properties.add(DiagnosticsProperty<List<String>>('contentCommitMimeTypes', contentCommitMimeTypes, defaultValue: null)); } } diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 102ecb28d1761..e4ccf319a2f5f 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -350,7 +350,6 @@ class TextField extends StatefulWidget { this.clipBehavior = Clip.hardEdge, this.restorationId, this.enableIMEPersonalizedLearning = true, - this.contentCommitMimeTypes = const <String> [], }) : assert(textAlign != null), assert(readOnly != null), assert(autofocus != null), @@ -392,7 +391,6 @@ class TextField extends StatefulWidget { ), assert(clipBehavior != null), assert(enableIMEPersonalizedLearning != null), - assert(contentCommitMimeTypes != null), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), toolbarOptions = toolbarOptions ?? (obscureText ? const ToolbarOptions( @@ -842,47 +840,6 @@ class TextField extends StatefulWidget { /// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning} final bool enableIMEPersonalizedLearning; - /// Used when a user inserts image-based content through the device keyboard - /// on Android only. - /// - /// The passed list of strings will determine which MIME types are allowed to - /// be inserted via the device keyboard - /// - /// This example shows how to limit your keyboard commits to specific file types - /// `TextField`. - /// - /// ```dart - /// final TextEditingController _controller = TextEditingController(); - /// - /// @override - /// void dispose() { - /// _controller.dispose(); - /// super.dispose(); - /// } - /// - /// @override - /// Widget build(BuildContext context) { - /// return Scaffold( - /// body: Column( - /// mainAxisAlignment: MainAxisAlignment.center, - /// children: <Widget>[ - /// const Text('Here's a text field that supports inserting gif content:'), - /// TextField( - /// controller: _controller, - /// contentCommitMimeTypes: ['image/gif', 'image/png'], - /// onContentCommitted: (CommittedContent data) async { - /// ... - /// }, - /// ), - /// ], - /// ), - /// ); - /// } - /// ``` - /// {@end-tool} - /// {@endtemplate} - final List<String> contentCommitMimeTypes; - @override State<TextField> createState() => _TextFieldState(); @@ -925,7 +882,6 @@ class TextField extends StatefulWidget { properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null)); properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior, defaultValue: Clip.hardEdge)); properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true)); - properties.add(DiagnosticsProperty<List<String>>('contentCommitMimeTypes', contentCommitMimeTypes, defaultValue: null)); } } diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index 038f3d9c60d96..6f0736c723c74 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -468,7 +468,6 @@ class TextInputConfiguration { this.textCapitalization = TextCapitalization.none, this.autofillConfiguration = AutofillConfiguration.disabled, this.enableIMEPersonalizedLearning = true, - this.contentCommitMimeTypes = const <String>[], this.enableDeltaModel = false, }) : assert(inputType != null), assert(obscureText != null), @@ -480,7 +479,6 @@ class TextInputConfiguration { assert(inputAction != null), assert(textCapitalization != null), assert(enableIMEPersonalizedLearning != null), - assert(contentCommitMimeTypes != null), assert(enableDeltaModel != null); /// The type of information for which to optimize the text input control. @@ -611,47 +609,6 @@ class TextInputConfiguration { /// {@endtemplate} final bool enableIMEPersonalizedLearning; - /// Used when a user inserts image-based content through the device keyboard - /// on Android only. - /// - /// The passed list of strings will determine which MIME types are allowed to - /// be inserted via the device keyboard - /// - /// This example shows how to limit your keyboard commits to specific file types - /// `TextField`. - /// - /// ```dart - /// final TextEditingController _controller = TextEditingController(); - /// - /// @override - /// void dispose() { - /// _controller.dispose(); - /// super.dispose(); - /// } - /// - /// @override - /// Widget build(BuildContext context) { - /// return Scaffold( - /// body: Column( - /// mainAxisAlignment: MainAxisAlignment.center, - /// children: <Widget>[ - /// const Text('Here's a text field that supports inserting gif content:'), - /// TextField( - /// controller: _controller, - /// contentCommitMimeTypes: ['image/gif', 'image/png'], - /// onContentCommitted: (CommittedContent data) async { - /// ... - /// }, - /// ), - /// ], - /// ), - /// ); - /// } - /// ``` - /// {@end-tool} - /// {@endtemplate} - final List<String> contentCommitMimeTypes; - /// Creates a copy of this [TextInputConfiguration] with the given fields /// replaced with new values. TextInputConfiguration copyWith({ @@ -668,7 +625,6 @@ class TextInputConfiguration { TextCapitalization? textCapitalization, bool? enableIMEPersonalizedLearning, AutofillConfiguration? autofillConfiguration, - List<String>? contentCommitMimeTypes, bool? enableDeltaModel, }) { return TextInputConfiguration( @@ -685,7 +641,6 @@ class TextInputConfiguration { enableIMEPersonalizedLearning: enableIMEPersonalizedLearning?? this.enableIMEPersonalizedLearning, autofillConfiguration: autofillConfiguration ?? this.autofillConfiguration, enableDeltaModel: enableDeltaModel ?? this.enableDeltaModel, - contentCommitMimeTypes: contentCommitMimeTypes ?? this.contentCommitMimeTypes ); } @@ -732,7 +687,6 @@ class TextInputConfiguration { 'enableIMEPersonalizedLearning': enableIMEPersonalizedLearning, if (autofill != null) 'autofill': autofill, 'enableDeltaModel' : enableDeltaModel, - 'contentCommitMimeTypes': contentCommitMimeTypes }; } } diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 1231bcfb9fa8c..55611436db40c 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -460,7 +460,6 @@ class EditableText extends StatefulWidget { ), this.autofillHints = const <String>[], this.autofillClient, - this.contentCommitMimeTypes = const <String>[], this.clipBehavior = Clip.hardEdge, this.restorationId, this.scrollBehavior, @@ -504,7 +503,6 @@ class EditableText extends StatefulWidget { assert(toolbarOptions != null), assert(clipBehavior != null), assert(enableIMEPersonalizedLearning != null), - assert(contentCommitMimeTypes != null), _strutStyle = strutStyle, keyboardType = keyboardType ?? _inferKeyboardType(autofillHints: autofillHints, maxLines: maxLines), inputFormatters = maxLines == 1 @@ -1287,47 +1285,6 @@ class EditableText extends StatefulWidget { /// [AutofillClient]. This property may override [autofillHints]. final AutofillClient? autofillClient; - /// Used when a user inserts image-based content through the device keyboard - /// on Android only. - /// - /// The passed list of strings will determine which MIME types are allowed to - /// be inserted via the device keyboard - /// - /// This example shows how to limit your keyboard commits to specific file types - /// `TextField`. - /// - /// ```dart - /// final TextEditingController _controller = TextEditingController(); - /// - /// @override - /// void dispose() { - /// _controller.dispose(); - /// super.dispose(); - /// } - /// - /// @override - /// Widget build(BuildContext context) { - /// return Scaffold( - /// body: Column( - /// mainAxisAlignment: MainAxisAlignment.center, - /// children: <Widget>[ - /// const Text('Here's a text field that supports inserting gif content:'), - /// TextField( - /// controller: _controller, - /// contentCommitMimeTypes: ['image/gif', 'image/png'], - /// onContentCommitted: (CommittedContent data) async { - /// ... - /// }, - /// ), - /// ], - /// ), - /// ); - /// } - /// ``` - /// {@end-tool} - /// {@endtemplate} - final List<String> contentCommitMimeTypes; - /// {@macro flutter.material.Material.clipBehavior} /// /// Defaults to [Clip.hardEdge]. @@ -1543,7 +1500,6 @@ class EditableText extends StatefulWidget { properties.add(DiagnosticsProperty<Iterable<String>>('autofillHints', autofillHints, defaultValue: null)); properties.add(DiagnosticsProperty<TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null)); properties.add(DiagnosticsProperty<bool>('enableIMEPersonalizedLearning', enableIMEPersonalizedLearning, defaultValue: true)); - properties.add(DiagnosticsProperty<List<String>>('contentCommitMimeTypes', contentCommitMimeTypes, defaultValue: null)); } } @@ -2884,7 +2840,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien keyboardAppearance: widget.keyboardAppearance, autofillConfiguration: autofillConfiguration, enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning, - contentCommitMimeTypes: widget.contentCommitMimeTypes ); } diff --git a/packages/flutter_tools/bin/podhelper.rb b/packages/flutter_tools/bin/podhelper.rb index 97e073dd84a63..6a8185e9d3333 100644 --- a/packages/flutter_tools/bin/podhelper.rb +++ b/packages/flutter_tools/bin/podhelper.rb @@ -33,6 +33,9 @@ def flutter_macos_podfile_setup def flutter_additional_ios_build_settings(target) return unless target.platform_name == :ios + # Return if it's not a Flutter plugin (transitive dependency). + return unless target.dependencies.any? { |dependency| dependency.name == 'Flutter' } + # [target.deployment_target] is a [String] formatted as "8.0". inherit_deployment_target = target.deployment_target[/\d+/].to_i < 9 @@ -49,14 +52,6 @@ def flutter_additional_ios_build_settings(target) release_framework_dir = File.expand_path(File.join(artifacts_dir, 'ios-release', 'Flutter.xcframework'), __FILE__) target.build_configurations.each do |build_configuration| - # Build both x86_64 and arm64 simulator archs for all dependencies. If a single plugin does not support arm64 simulators, - # the app and all frameworks will fall back to x86_64. Unfortunately that case is not detectable in this script. - # Therefore all pods must have a x86_64 slice available, or linking a x86_64 app will fail. - build_configuration.build_settings['ONLY_ACTIVE_ARCH'] = 'NO' if build_configuration.type == :debug - - # Skip other updates if it's not a Flutter plugin (transitive dependency). - next unless target.dependencies.any? { |dependency| dependency.name == 'Flutter' } - # Profile can't be derived from the CocoaPods build configuration. Use release framework (for linking only). configuration_engine_dir = build_configuration.type == :debug ? debug_framework_dir : release_framework_dir Dir.new(configuration_engine_dir).each_child do |xcframework_file| diff --git a/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart b/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart index e8cb730f82e23..1d3315683d37c 100644 --- a/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart +++ b/packages/flutter_tools/test/integration.shard/ios_content_validation_test.dart @@ -16,7 +16,6 @@ import 'test_utils.dart'; void main() { group('iOS app validation', () { String flutterRoot; - Directory pluginRoot; String projectRoot; String flutterBin; Directory tempDir; @@ -30,20 +29,18 @@ void main() { 'flutter', ); - // Test a plugin example app to allow plugins validation. processManager.runSync(<String>[ flutterBin, ...getLocalEngineArguments(), 'create', '--verbose', '--platforms=ios', - '-t', - 'plugin', + '-i', + 'objc', 'hello', ], workingDirectory: tempDir.path); - pluginRoot = tempDir.childDirectory('hello'); - projectRoot = pluginRoot.childDirectory('example').path; + projectRoot = tempDir.childDirectory('hello').path; }); tearDownAll(() { @@ -59,7 +56,6 @@ void main() { File outputFlutterFrameworkBinary; Directory outputAppFramework; File outputAppFrameworkBinary; - File outputPluginFrameworkBinary; setUpAll(() { processManager.runSync(<String>[ @@ -89,13 +85,11 @@ void main() { outputAppFramework = frameworkDirectory.childDirectory('App.framework'); outputAppFrameworkBinary = outputAppFramework.childFile('App'); - - outputPluginFrameworkBinary = frameworkDirectory.childDirectory('hello.framework').childFile('hello'); }); testWithoutContext('flutter build ios builds a valid app', () { - expect(outputPluginFrameworkBinary, exists); - + // Should only contain Flutter.framework and App.framework. + expect(frameworkDirectory.listSync().length, 2); expect(outputAppFrameworkBinary, exists); expect(outputAppFramework.childFile('Info.plist'), exists); @@ -208,61 +202,17 @@ void main() { }, skip: !platform.isMacOS || buildMode != BuildMode.release); // [intended] only makes sense on macos. testWithoutContext('validate obfuscation', () { - // HelloPlugin class is present in project. - ProcessResult grepResult = processManager.runSync(<String>[ - 'grep', - '-r', - 'HelloPlugin', - pluginRoot.path, - ]); - // Matches exits 0. - expect(grepResult.exitCode, 0); - - // Not present in binary. - grepResult = processManager.runSync(<String>[ + final ProcessResult grepResult = processManager.runSync(<String>[ 'grep', - 'HelloPlugin', + '-i', + 'hello', outputAppFrameworkBinary.path, ]); - // Does not match exits 1. - expect(grepResult.exitCode, 1); + expect(grepResult.stdout, isNot(contains('matches'))); }); }); } - testWithoutContext('builds all plugin architectures for simulator', () { - final ProcessResult buildSimulator = processManager.runSync( - <String>[ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--simulator', - '--verbose', - '--no-codesign', - ], - workingDirectory: projectRoot, - ); - expect(buildSimulator.exitCode, 0); - - final File pluginFrameworkBinary = fileSystem.file(fileSystem.path.join( - projectRoot, - 'build', - 'ios', - 'iphonesimulator', - 'Runner.app', - 'Frameworks', - 'hello.framework', - 'hello', - )); - expect(pluginFrameworkBinary, exists); - final ProcessResult archs = processManager.runSync( - <String>['file', pluginFrameworkBinary.path], - ); - expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library x86_64')); - expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64')); - }); - testWithoutContext('build for simulator with all available architectures', () { final ProcessResult buildSimulator = processManager.runSync( <String>[ @@ -300,6 +250,6 @@ void main() { expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64')); }); }, skip: !platform.isMacOS, // [intended] only makes sense for macos platform. - timeout: const Timeout(Duration(minutes: 7)) + timeout: const Timeout(Duration(minutes: 5)) ); } From d67e6adfacd2b5ac6435717e46ca8f425bcbcf22 Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Thu, 7 Apr 2022 12:24:09 -0700 Subject: [PATCH 22/41] [Cherrypick] Partial revert of super params in tools (#101436) (#101527) Co-authored-by: Michael Goderbauer <goderbauer@google.com> --- .../src/debug_adapters/flutter_adapter.dart | 18 ++++++++++++------ .../debug_adapters/flutter_test_adapter.dart | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart index b9a182d8f2402..68baed68224bd 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart @@ -21,14 +21,20 @@ import 'mixins.dart'; class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments, FlutterAttachRequestArguments> with PidTracker { FlutterDebugAdapter( - super.channel, { + ByteStreamServerChannel channel, { required this.fileSystem, required this.platform, - super.ipv6, - super.enableDds, - super.enableAuthCodes, - super.logger, - }); + bool ipv6 = false, + bool enableDds = true, + bool enableAuthCodes = true, + Logger? logger, + }) : super( + channel, + ipv6: ipv6, + enableDds: enableDds, + enableAuthCodes: enableAuthCodes, + logger: logger, + ); FileSystem fileSystem; Platform platform; diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart index 2c8955ba63ee7..7daa9efb73829 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart @@ -21,14 +21,20 @@ import 'mixins.dart'; class FlutterTestDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments, FlutterAttachRequestArguments> with PidTracker, TestAdapter { FlutterTestDebugAdapter( - super.channel, { + ByteStreamServerChannel channel, { required this.fileSystem, required this.platform, - super.ipv6, - super.enableDds, - super.enableAuthCodes, - super.logger, - }); + bool ipv6 = false, + bool enableDds = true, + bool enableAuthCodes = true, + Logger? logger, + }) : super( + channel, + ipv6: ipv6, + enableDds: enableDds, + enableAuthCodes: enableAuthCodes, + logger: logger, + ); FileSystem fileSystem; Platform platform; From 02d44bb771d2544ef21952e151dfc1aea2d16f8e Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Thu, 7 Apr 2022 14:08:53 -0700 Subject: [PATCH 23/41] Revert "Refactor `ToggleButtons` (remove `RawMaterialButton`) (#99493)" (#101538) This reverts commit 0b216f7a2884c78c4cc3fcdbc220e6387ffea4fe. --- .../lib/src/material/toggle_buttons.dart | 573 +++++++++++++----- .../test/material/toggle_buttons_test.dart | 88 +-- .../material/toggle_buttons_theme_test.dart | 30 +- 3 files changed, 460 insertions(+), 231 deletions(-) diff --git a/packages/flutter/lib/src/material/toggle_buttons.dart b/packages/flutter/lib/src/material/toggle_buttons.dart index 7c4beda71e2d0..ed6c81b0d4015 100644 --- a/packages/flutter/lib/src/material/toggle_buttons.dart +++ b/packages/flutter/lib/src/material/toggle_buttons.dart @@ -8,12 +8,11 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; -import 'button_style.dart'; +import 'button.dart'; import 'color_scheme.dart'; import 'constants.dart'; -import 'ink_ripple.dart'; +import 'debug.dart'; import 'material_state.dart'; -import 'text_button.dart'; import 'theme.dart'; import 'theme_data.dart'; import 'toggle_buttons_theme.dart'; @@ -193,21 +192,10 @@ class ToggleButtons extends StatelessWidget { this.borderWidth, this.direction = Axis.horizontal, this.verticalDirection = VerticalDirection.down, - this.style, }) : assert(children != null), assert(isSelected != null), assert(children.length == isSelected.length), - assert( - !(style != null - && (mouseCursor != null - || textStyle != null - || fillColor != null - || focusColor != null - || highlightColor != null - || hoverColor != null - || splashColor != null)), - 'You can only pass [style] or textStyle, fillColor, splashColor properties, not both.'), assert(direction != null), assert(direction == Axis.horizontal || verticalDirection != null), super(key: key); @@ -429,14 +417,6 @@ class ToggleButtons extends StatelessWidget { /// the buttons starting from the first or last child from top to bottom. final VerticalDirection verticalDirection; - /// Customizes this toggle button's appearance. - /// - /// When implemented this overrides the individual customizable properties - /// of toggle buttons such as [selectedColor], [disabledColor], [hoverColor]. - /// - /// Null by default. - final ButtonStyle? style; - // Determines if this is the first child that is being laid out // by the render object, _not_ the order of the children in its list. bool _isFirstButton(int index, int length, TextDirection textDirection) { @@ -688,87 +668,33 @@ class ToggleButtons extends StatelessWidget { final BorderSide borderSide = _getBorderSide(index, theme, toggleButtonsTheme); final BorderSide trailingBorderSide = _getTrailingBorderSide(index, theme, toggleButtonsTheme); - final Set<MaterialState> states = <MaterialState>{ - if (isSelected[index] && onPressed != null) MaterialState.selected, - if (onPressed == null) MaterialState.disabled, - }; - final Color effectiveFillColor = _ResolveFillColor(fillColor - ?? toggleButtonsTheme.fillColor).resolve(states) - ?? _DefaultFillColor(theme.colorScheme).resolve(states); - final Color currentColor; - if (onPressed != null && isSelected[index]) { - currentColor = selectedColor - ?? toggleButtonsTheme.selectedColor - ?? theme.colorScheme.primary; - } else if (onPressed != null && !isSelected[index]) { - currentColor = color - ?? toggleButtonsTheme.color - ?? theme.colorScheme.onSurface.withOpacity(0.87); - } else { - currentColor = disabledColor - ?? toggleButtonsTheme.disabledColor - ?? theme.colorScheme.onSurface.withOpacity(0.38); - } - final TextStyle currentTextStyle = textStyle - ?? toggleButtonsTheme.textStyle - ?? theme.textTheme.bodyText2!; - final BoxConstraints currentConstraints = constraints - ?? toggleButtonsTheme.constraints - ?? const BoxConstraints( - minWidth: kMinInteractiveDimension, - minHeight: kMinInteractiveDimension, - ); - - return _SelectToggleButton( + return _ToggleButton( + selected: isSelected[index], + textStyle: textStyle, + constraints: constraints, + color: color, + selectedColor: selectedColor, + disabledColor: disabledColor, + fillColor: fillColor, + focusColor: focusColor ?? toggleButtonsTheme.focusColor, + highlightColor: highlightColor ?? toggleButtonsTheme.highlightColor, + hoverColor: hoverColor ?? toggleButtonsTheme.hoverColor, + splashColor: splashColor ?? toggleButtonsTheme.splashColor, + focusNode: focusNodes != null ? focusNodes![index] : null, + onPressed: onPressed != null + ? () {onPressed!(index);} + : null, + mouseCursor: mouseCursor, leadingBorderSide: leadingBorderSide, borderSide: borderSide, trailingBorderSide: trailingBorderSide, borderRadius: edgeBorderRadius, + clipRadius: clipBorderRadius, isFirstButton: index == 0, isLastButton: index == children.length - 1, direction: direction, verticalDirection: verticalDirection, - child: ClipRRect( - borderRadius: clipBorderRadius, - child: TextButton( - focusNode: focusNodes != null ? focusNodes![index] : null, - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all<Color?>(effectiveFillColor), - foregroundColor: MaterialStateProperty.all<Color?>(currentColor), - overlayColor: _ToggleButtonDefaultOverlay( - selected: onPressed != null && isSelected[index], - unselected: onPressed != null && !isSelected[index], - colorScheme: theme.colorScheme, - disabledColor: disabledColor ?? toggleButtonsTheme.disabledColor, - focusColor: focusColor ?? toggleButtonsTheme.focusColor, - highlightColor: highlightColor ?? toggleButtonsTheme.highlightColor, - hoverColor: hoverColor ?? toggleButtonsTheme.hoverColor, - splashColor: splashColor ?? toggleButtonsTheme.splashColor, - ), - elevation: MaterialStateProperty.all<double>(0), - textStyle: MaterialStateProperty.all<TextStyle?>(currentTextStyle.copyWith( - color: currentColor, - )), - padding: MaterialStateProperty.all<EdgeInsetsGeometry>(EdgeInsets.zero), - minimumSize: MaterialStateProperty.all<Size?>( - Size(currentConstraints.minWidth, currentConstraints.minHeight)), - maximumSize: MaterialStateProperty.all<Size?>( - Size(currentConstraints.maxWidth, currentConstraints.maxHeight)), - shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder()), - mouseCursor: MaterialStateProperty.all<MouseCursor?>(mouseCursor), - visualDensity: VisualDensity.adaptivePlatformDensity, - tapTargetSize: tapTargetSize ?? theme.materialTapTargetSize, - animationDuration: kThemeChangeDuration, - enableFeedback: true, - alignment: Alignment.center, - splashFactory: InkRipple.splashFactory, - ), - onPressed: onPressed != null - ? () {onPressed!(index);} - : null, - child: children[index], - ), - ), + child: children[index], ); }); @@ -789,7 +715,17 @@ class ToggleButtons extends StatelessWidget { ), ); - return result; + final MaterialTapTargetSize resolvedTapTargetSize = tapTargetSize ?? theme.materialTapTargetSize; + switch (resolvedTapTargetSize) { + case MaterialTapTargetSize.padded: + return _InputPadding( + minSize: const Size(kMinInteractiveDimension, kMinInteractiveDimension), + direction: direction, + child: result, + ); + case MaterialTapTargetSize.shrinkWrap: + return result; + } } @override @@ -819,6 +755,251 @@ class ToggleButtons extends StatelessWidget { } } +/// An individual toggle button, otherwise known as a segmented button. +/// +/// This button is used by [ToggleButtons] to implement a set of segmented controls. +class _ToggleButton extends StatelessWidget { + /// Creates a toggle button based on [RawMaterialButton]. + /// + /// This class adds some logic to distinguish between enabled, active, and + /// disabled states, to determine the appropriate colors to use. + /// + /// It takes in a [shape] property to modify the borders of the button, + /// which is used by [ToggleButtons] to customize borders based on the + /// order in which this button appears in the list. + const _ToggleButton({ + Key? key, + this.selected = false, + this.textStyle, + this.constraints, + this.color, + this.selectedColor, + this.disabledColor, + required this.fillColor, + required this.focusColor, + required this.highlightColor, + required this.hoverColor, + required this.splashColor, + this.focusNode, + this.onPressed, + this.mouseCursor, + required this.leadingBorderSide, + required this.borderSide, + required this.trailingBorderSide, + required this.borderRadius, + required this.clipRadius, + required this.isFirstButton, + required this.isLastButton, + required this.direction, + required this.verticalDirection, + required this.child, + }) : super(key: key); + + /// Determines if the button is displayed as active/selected or enabled. + final bool selected; + + /// The [TextStyle] to apply to any text that appears in this button. + final TextStyle? textStyle; + + /// Defines the button's size. + /// + /// Typically used to constrain the button's minimum size. + final BoxConstraints? constraints; + + /// The color for [Text] and [Icon] widgets if the button is enabled. + /// + /// If [selected] is false and [onPressed] is not null, this color will be used. + final Color? color; + + /// The color for [Text] and [Icon] widgets if the button is selected. + /// + /// If [selected] is true and [onPressed] is not null, this color will be used. + final Color? selectedColor; + + /// The color for [Text] and [Icon] widgets if the button is disabled. + /// + /// If [onPressed] is null, this color will be used. + final Color? disabledColor; + + /// The color of the button's [Material]. + final Color? fillColor; + + /// The color for the button's [Material] when it has the input focus. + final Color? focusColor; + + /// The color for the button's [Material] when a pointer is hovering over it. + final Color? hoverColor; + + /// The highlight color for the button's [InkWell]. + final Color? highlightColor; + + /// The splash color for the button's [InkWell]. + final Color? splashColor; + + /// {@macro flutter.widgets.Focus.focusNode} + final FocusNode? focusNode; + + /// Called when the button is tapped or otherwise activated. + /// + /// If this is null, the button will be disabled, see [enabled]. + final VoidCallback? onPressed; + + /// {@macro flutter.material.RawMaterialButton.mouseCursor} + /// + /// If this property is null, [MaterialStateMouseCursor.clickable] will be used. + final MouseCursor? mouseCursor; + + /// The width and color of the button's leading side border. + final BorderSide leadingBorderSide; + + /// If [direction] is [Axis.horizontal], this corresponds the width and color + /// of the button's top and bottom side borders. + /// + /// If [direction] is [Axis.vertical], this corresponds the width and color + /// of the button's left and right side borders. + final BorderSide borderSide; + + /// The width and color of the button's trailing side border. + final BorderSide trailingBorderSide; + + /// The border radii of each corner of the button. + final BorderRadius borderRadius; + + /// The corner radii used to clip the button's contents. + /// + /// This is used to have the button's contents be properly clipped taking + /// the [borderRadius] and the border's width into account. + final BorderRadius clipRadius; + + /// Whether or not this toggle button is the first button in the list. + final bool isFirstButton; + + /// Whether or not this toggle button is the last button in the list. + final bool isLastButton; + + /// The direction along which the buttons are rendered. + final Axis direction; + + /// If [direction] is [Axis.vertical], this property defines whether or not this button in its list + /// of buttons is laid out starting from top to bottom or from bottom to top. + final VerticalDirection verticalDirection; + + /// The button's label, which is usually an [Icon] or a [Text] widget. + final Widget child; + + Color _resolveColor(Set<MaterialState> states, MaterialStateProperty<Color?> widgetColor, + MaterialStateProperty<Color?> themeColor, MaterialStateProperty<Color> defaultColor) { + return widgetColor.resolve(states) + ?? themeColor.resolve(states) + ?? defaultColor.resolve(states); + } + + @override + Widget build(BuildContext context) { + assert(debugCheckHasMaterial(context)); + final Color currentColor; + Color? currentFocusColor; + Color? currentHoverColor; + Color? currentSplashColor; + final ThemeData theme = Theme.of(context); + final ToggleButtonsThemeData toggleButtonsTheme = ToggleButtonsTheme.of(context); + + final Set<MaterialState> states = <MaterialState>{ + if (selected && onPressed != null) MaterialState.selected, + if (onPressed == null) MaterialState.disabled, + }; + + final Color currentFillColor = _resolveColor( + states, + _ResolveFillColor(fillColor), + _ResolveFillColor(toggleButtonsTheme.fillColor), + _DefaultFillColor(theme.colorScheme), + ); + + if (onPressed != null && selected) { + currentColor = selectedColor + ?? toggleButtonsTheme.selectedColor + ?? theme.colorScheme.primary; + currentFocusColor = focusColor + ?? toggleButtonsTheme.focusColor + ?? theme.colorScheme.primary.withOpacity(0.12); + currentHoverColor = hoverColor + ?? toggleButtonsTheme.hoverColor + ?? theme.colorScheme.primary.withOpacity(0.04); + currentSplashColor = splashColor + ?? toggleButtonsTheme.splashColor + ?? theme.colorScheme.primary.withOpacity(0.16); + } else if (onPressed != null && !selected) { + currentColor = color + ?? toggleButtonsTheme.color + ?? theme.colorScheme.onSurface.withOpacity(0.87); + currentFocusColor = focusColor + ?? toggleButtonsTheme.focusColor + ?? theme.colorScheme.onSurface.withOpacity(0.12); + currentHoverColor = hoverColor + ?? toggleButtonsTheme.hoverColor + ?? theme.colorScheme.onSurface.withOpacity(0.04); + currentSplashColor = splashColor + ?? toggleButtonsTheme.splashColor + ?? theme.colorScheme.onSurface.withOpacity(0.16); + } else { + currentColor = disabledColor + ?? toggleButtonsTheme.disabledColor + ?? theme.colorScheme.onSurface.withOpacity(0.38); + } + + final TextStyle currentTextStyle = textStyle ?? toggleButtonsTheme.textStyle ?? theme.textTheme.bodyText2!; + final BoxConstraints currentConstraints = constraints ?? toggleButtonsTheme.constraints ?? const BoxConstraints(minWidth: kMinInteractiveDimension, minHeight: kMinInteractiveDimension); + + final Widget result = ClipRRect( + borderRadius: clipRadius, + child: RawMaterialButton( + textStyle: currentTextStyle.copyWith( + color: currentColor, + ), + constraints: currentConstraints, + elevation: 0.0, + fillColor: currentFillColor, + focusColor: currentFocusColor, + focusElevation: 0, + highlightColor: highlightColor ?? theme.colorScheme.surface.withOpacity(0.0), + highlightElevation: 0.0, + hoverColor: currentHoverColor, + hoverElevation: 0, + splashColor: currentSplashColor, + focusNode: focusNode, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + onPressed: onPressed, + mouseCursor: mouseCursor, + child: child, + ), + ); + + return _SelectToggleButton( + key: key, + leadingBorderSide: leadingBorderSide, + borderSide: borderSide, + trailingBorderSide: trailingBorderSide, + borderRadius: borderRadius, + isFirstButton: isFirstButton, + isLastButton: isLastButton, + direction: direction, + verticalDirection: verticalDirection, + child: result, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(FlagProperty('selected', + value: selected, + ifTrue: 'Button is selected', + ifFalse: 'Button is unselected', + )); + } +} + @immutable class _ResolveFillColor extends MaterialStateProperty<Color?> with Diagnosticable { _ResolveFillColor(this.primary); @@ -849,68 +1030,6 @@ class _DefaultFillColor extends MaterialStateProperty<Color> with Diagnosticable } } -@immutable -class _ToggleButtonDefaultOverlay extends MaterialStateProperty<Color?> { - _ToggleButtonDefaultOverlay({ - required this.selected, - required this.unselected, - this.colorScheme, - this.focusColor, - this.highlightColor, - this.hoverColor, - this.splashColor, - this.disabledColor, - }); - - final bool selected; - final bool unselected; - final ColorScheme? colorScheme; - final Color? focusColor; - final Color? highlightColor; - final Color? hoverColor; - final Color? splashColor; - final Color? disabledColor; - - @override - Color? resolve(Set<MaterialState> states) { - if (selected) { - if (states.contains(MaterialState.hovered)) { - return hoverColor ?? colorScheme?.primary.withOpacity(0.04); - } else if (states.contains(MaterialState.focused)) { - return focusColor ?? colorScheme?.primary.withOpacity(0.12); - } else if (states.contains(MaterialState.pressed)) { - return splashColor ?? colorScheme?.primary.withOpacity(0.16); - } - } else if (unselected) { - if (states.contains(MaterialState.hovered)) { - return hoverColor ?? colorScheme?.onSurface.withOpacity(0.04); - } else if (states.contains(MaterialState.focused)) { - return focusColor ?? colorScheme?.onSurface.withOpacity(0.12); - } else if (states.contains(MaterialState.pressed)) { - return splashColor ?? highlightColor ?? colorScheme?.onSurface.withOpacity(0.16); - } - } - return null; - } - - @override - String toString() { - return ''' - { - selected: - hovered: $hoverColor, otherwise: ${colorScheme?.primary.withOpacity(0.04)}, - focused: $focusColor, otherwise: ${colorScheme?.primary.withOpacity(0.12)}, - pressed: $splashColor, otherwise: ${colorScheme?.primary.withOpacity(0.16)}, - unselected: - hovered: $hoverColor, otherwise: ${colorScheme?.onSurface.withOpacity(0.04)}, - focused: $focusColor, otherwise: ${colorScheme?.onSurface.withOpacity(0.12)}, - pressed: $splashColor, otherwise: ${colorScheme?.onSurface.withOpacity(0.16)}, - otherwise: null, - } - '''; - } -} - class _SelectToggleButton extends SingleChildRenderObjectWidget { const _SelectToggleButton({ Key? key, @@ -1457,3 +1576,141 @@ class _SelectToggleButtonRenderObject extends RenderShiftedBox { } } } + +/// A widget to pad the area around a [ToggleButtons]'s children. +/// +/// This widget is based on a similar one used in [ButtonStyleButton] but it +/// only redirects taps along one axis to ensure the correct button is tapped +/// within the [ToggleButtons]. +/// +/// This ensures that a widget takes up at least as much space as the minSize +/// parameter to ensure adequate tap target size, while keeping the widget +/// visually smaller to the user. +class _InputPadding extends SingleChildRenderObjectWidget { + const _InputPadding({ + Key? key, + Widget? child, + required this.minSize, + required this.direction, + }) : super(key: key, child: child); + + final Size minSize; + final Axis direction; + + @override + RenderObject createRenderObject(BuildContext context) { + return _RenderInputPadding(minSize, direction); + } + + @override + void updateRenderObject(BuildContext context, covariant _RenderInputPadding renderObject) { + renderObject.minSize = minSize; + renderObject.direction = direction; + } +} + +class _RenderInputPadding extends RenderShiftedBox { + _RenderInputPadding(this._minSize, this._direction, [RenderBox? child]) : super(child); + + Size get minSize => _minSize; + Size _minSize; + set minSize(Size value) { + if (_minSize == value) + return; + _minSize = value; + markNeedsLayout(); + } + + Axis get direction => _direction; + Axis _direction; + set direction(Axis value) { + if (_direction == value) + return; + _direction = value; + markNeedsLayout(); + } + + @override + double computeMinIntrinsicWidth(double height) { + if (child != null) + return math.max(child!.getMinIntrinsicWidth(height), minSize.width); + return 0.0; + } + + @override + double computeMinIntrinsicHeight(double width) { + if (child != null) + return math.max(child!.getMinIntrinsicHeight(width), minSize.height); + return 0.0; + } + + @override + double computeMaxIntrinsicWidth(double height) { + if (child != null) + return math.max(child!.getMaxIntrinsicWidth(height), minSize.width); + return 0.0; + } + + @override + double computeMaxIntrinsicHeight(double width) { + if (child != null) + return math.max(child!.getMaxIntrinsicHeight(width), minSize.height); + return 0.0; + } + + Size _computeSize({required BoxConstraints constraints, required ChildLayouter layoutChild}) { + if (child != null) { + final Size childSize = layoutChild(child!, constraints); + final double height = math.max(childSize.width, minSize.width); + final double width = math.max(childSize.height, minSize.height); + return constraints.constrain(Size(height, width)); + } + return Size.zero; + } + + @override + Size computeDryLayout(BoxConstraints constraints) { + return _computeSize( + constraints: constraints, + layoutChild: ChildLayoutHelper.dryLayoutChild, + ); + } + + @override + void performLayout() { + size = _computeSize( + constraints: constraints, + layoutChild: ChildLayoutHelper.layoutChild, + ); + if (child != null) { + final BoxParentData childParentData = child!.parentData! as BoxParentData; + childParentData.offset = Alignment.center.alongOffset(size - child!.size as Offset); + } + } + + @override + bool hitTest(BoxHitTestResult result, { required Offset position }) { + // The super.hitTest() method also checks hitTestChildren(). We don't + // want that in this case because we've padded around the children per + // tapTargetSize. + if (!size.contains(position)) { + return false; + } + + // Only adjust one axis to ensure the correct button is tapped. + Offset center; + if (direction == Axis.horizontal) { + center = Offset(position.dx, child!.size.height / 2); + } else { + center = Offset(child!.size.width / 2, position.dy); + } + return result.addWithRawTransform( + transform: MatrixUtils.forceToPoint(center), + position: center, + hitTest: (BoxHitTestResult result, Offset position) { + assert(position == center); + return child!.hitTest(result, position: center); + }, + ); + } +} diff --git a/packages/flutter/test/material/toggle_buttons_test.dart b/packages/flutter/test/material/toggle_buttons_test.dart index 2f43127d8587f..7937117d917a9 100644 --- a/packages/flutter/test/material/toggle_buttons_test.dart +++ b/packages/flutter/test/material/toggle_buttons_test.dart @@ -26,7 +26,7 @@ void main() { testWidgets('Initial toggle state is reflected', (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { return tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, text), + of: find.widgetWithText(RawMaterialButton, text), matching: find.byType(DefaultTextStyle), )).style; } @@ -61,10 +61,11 @@ void main() { (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { return tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, text), + of: find.widgetWithText(RawMaterialButton, text), matching: find.byType(DefaultTextStyle), )).style; } + final List<bool> isSelected = <bool>[false, true]; final ThemeData theme = ThemeData(); await tester.pumpWidget( @@ -122,7 +123,7 @@ void main() { (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { return tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, text), + of: find.widgetWithText(RawMaterialButton, text), matching: find.byType(DefaultTextStyle), )).style; } @@ -219,14 +220,14 @@ void main() { TextStyle textStyle; textStyle = tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, 'First child'), + of: find.widgetWithText(RawMaterialButton, 'First child'), matching: find.byType(DefaultTextStyle), )).style; expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily); expect(textStyle.decoration, theme.textTheme.bodyText2!.decoration); textStyle = tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, 'Second child'), + of: find.widgetWithText(RawMaterialButton, 'Second child'), matching: find.byType(DefaultTextStyle), )).style; expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily); @@ -256,7 +257,7 @@ void main() { TextStyle textStyle; textStyle = tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, 'First child'), + of: find.widgetWithText(RawMaterialButton, 'First child'), matching: find.byType(DefaultTextStyle), )).style; expect(textStyle.textBaseline, TextBaseline.ideographic); @@ -264,7 +265,7 @@ void main() { expect(textStyle.color, isNot(Colors.orange)); textStyle = tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, 'Second child'), + of: find.widgetWithText(RawMaterialButton, 'Second child'), matching: find.byType(DefaultTextStyle), )).style; expect(textStyle.textBaseline, TextBaseline.ideographic); @@ -289,13 +290,13 @@ void main() { ), ); - final Rect firstRect = tester.getRect(find.byType(TextButton).at(0)); + final Rect firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); expect(firstRect.width, 48.0); expect(firstRect.height, 48.0); - final Rect secondRect = tester.getRect(find.byType(TextButton).at(1)); + final Rect secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); expect(secondRect.width, 48.0); expect(secondRect.height, 48.0); - final Rect thirdRect = tester.getRect(find.byType(TextButton).at(2)); + final Rect thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); expect(thirdRect.width, 48.0); expect(thirdRect.height, 48.0); }); @@ -306,7 +307,6 @@ void main() { Material( child: boilerplate( child: ToggleButtons( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, constraints: const BoxConstraints( minWidth: 50.0, minHeight: 60.0, @@ -323,13 +323,13 @@ void main() { ), ); - Rect firstRect = tester.getRect(find.byType(TextButton).at(0)); + Rect firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); expect(firstRect.width, 50.0); expect(firstRect.height, 60.0); - Rect secondRect = tester.getRect(find.byType(TextButton).at(1)); + Rect secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); expect(secondRect.width, 50.0); expect(secondRect.height, 60.0); - Rect thirdRect = tester.getRect(find.byType(TextButton).at(2)); + Rect thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); expect(thirdRect.width, 50.0); expect(thirdRect.height, 60.0); @@ -338,7 +338,6 @@ void main() { Material( child: boilerplate( child: ToggleButtons( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, constraints: const BoxConstraints( maxWidth: 20.0, maxHeight: 10.0, @@ -355,13 +354,13 @@ void main() { ), ); - firstRect = tester.getRect(find.byType(TextButton).at(0)); + firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); expect(firstRect.width, 20.0); expect(firstRect.height, 10.0); - secondRect = tester.getRect(find.byType(TextButton).at(1)); + secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); expect(secondRect.width, 20.0); expect(secondRect.height, 10.0); - thirdRect = tester.getRect(find.byType(TextButton).at(2)); + thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); expect(thirdRect.width, 20.0); expect(thirdRect.height, 10.0); }); @@ -371,13 +370,13 @@ void main() { (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { return tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, text), + of: find.widgetWithText(RawMaterialButton, text), matching: find.byType(DefaultTextStyle), )).style; } IconTheme iconTheme(IconData icon) { return tester.widget(find.descendant( - of: find.widgetWithIcon(TextButton, icon), + of: find.widgetWithIcon(RawMaterialButton, icon), matching: find.byType(IconTheme), )); } @@ -469,13 +468,13 @@ void main() { (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { return tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, text), + of: find.widgetWithText(RawMaterialButton, text), matching: find.byType(DefaultTextStyle), )).style; } IconTheme iconTheme(IconData icon) { return tester.widget(find.descendant( - of: find.widgetWithIcon(TextButton, icon), + of: find.widgetWithIcon(RawMaterialButton, icon), matching: find.byType(IconTheme), )); } @@ -575,7 +574,7 @@ void main() { ); final Material material = tester.widget<Material>(find.descendant( - of: find.byType(TextButton), + of: find.byType(RawMaterialButton), matching: find.byType(Material), )); expect( @@ -604,7 +603,7 @@ void main() { ); final Material material = tester.widget<Material>(find.descendant( - of: find.byType(TextButton), + of: find.byType(RawMaterialButton), matching: find.byType(Material), )); expect( @@ -632,7 +631,7 @@ void main() { ); final Material material = tester.widget<Material>(find.descendant( - of: find.byType(TextButton), + of: find.byType(RawMaterialButton), matching: find.byType(Material), )); expect( @@ -662,7 +661,7 @@ void main() { ); final Material material = tester.widget<Material>(find.descendant( - of: find.byType(TextButton), + of: find.byType(RawMaterialButton), matching: find.byType(Material), )); expect(material.color, customFillColor); @@ -673,7 +672,7 @@ void main() { Material buttonColor(String text) { return tester.widget<Material>( find.descendant( - of: find.byType(TextButton), + of: find.byType(RawMaterialButton), matching: find.widgetWithText(Material, text), ), ); @@ -728,7 +727,7 @@ void main() { Material buttonColor(String text) { return tester.widget<Material>( find.descendant( - of: find.byType(TextButton), + of: find.byType(RawMaterialButton), matching: find.widgetWithText(Material, text), ), ); @@ -1616,7 +1615,7 @@ void main() { final Key key1 = UniqueKey(); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); - expect(tester.getSize(find.byKey(key1)), const Size(228.0, 50.0)); + expect(tester.getSize(find.byKey(key1)), const Size(228.0, 48.0)); final Key key2 = UniqueKey(); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); @@ -1645,7 +1644,7 @@ void main() { final Key key1 = UniqueKey(); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); - expect(tester.getSize(find.byKey(key1)), const Size(228.0, 50.0)); + expect(tester.getSize(find.byKey(key1)), const Size(228.0, 48.0)); final Key key2 = UniqueKey(); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); @@ -1675,7 +1674,7 @@ void main() { final Key key1 = UniqueKey(); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); - expect(tester.getSize(find.byKey(key1)), const Size(50.0, 148.0)); + expect(tester.getSize(find.byKey(key1)), const Size(48.0, 100.0)); final Key key2 = UniqueKey(); await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); @@ -1911,31 +1910,4 @@ void main() { await hoverGesture.removePointer(); }); - - testWidgets('Toggle buttons height matches MaterialTapTargetSize.padded height', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/97302 - await tester.pumpWidget( - Material( - child: boilerplate( - child: ToggleButtons( - tapTargetSize: MaterialTapTargetSize.padded, - isSelected: const <bool>[false, false, false], - onPressed: (int index) {}, - children: const <Widget>[ - Icon(Icons.check), - Icon(Icons.access_alarm), - Icon(Icons.cake), - ], - ), - ), - ), - ); - - final Rect firstRect = tester.getRect(find.byType(TextButton).at(0)); - expect(firstRect.height, 48.0); - final Rect secondRect = tester.getRect(find.byType(TextButton).at(1)); - expect(secondRect.height, 48.0); - final Rect thirdRect = tester.getRect(find.byType(TextButton).at(2)); - expect(thirdRect.height, 48.0); - }); } diff --git a/packages/flutter/test/material/toggle_buttons_theme_test.dart b/packages/flutter/test/material/toggle_buttons_theme_test.dart index 6dfa4918d4265..cd8246ec5ddf7 100644 --- a/packages/flutter/test/material/toggle_buttons_theme_test.dart +++ b/packages/flutter/test/material/toggle_buttons_theme_test.dart @@ -142,15 +142,15 @@ void main() { TextStyle textStyle; textStyle = tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, 'First child'), - matching: find.byType(DefaultTextStyle), + of: find.widgetWithText(RawMaterialButton, 'First child'), + matching: find.byType(DefaultTextStyle), )).style; expect(textStyle.textBaseline, TextBaseline.ideographic); expect(textStyle.fontSize, 20.0); expect(textStyle.color, isNot(Colors.orange)); textStyle = tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, 'Second child'), + of: find.widgetWithText(RawMaterialButton, 'Second child'), matching: find.byType(DefaultTextStyle), )).style; expect(textStyle.textBaseline, TextBaseline.ideographic); @@ -171,7 +171,6 @@ void main() { ), ), child: ToggleButtons( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, isSelected: const <bool>[false, false, false], onPressed: (int index) {}, children: const <Widget>[ @@ -185,13 +184,13 @@ void main() { ), ); - Rect firstRect = tester.getRect(find.byType(TextButton).at(0)); + Rect firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); expect(firstRect.width, 50.0); expect(firstRect.height, 60.0); - Rect secondRect = tester.getRect(find.byType(TextButton).at(1)); + Rect secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); expect(secondRect.width, 50.0); expect(secondRect.height, 60.0); - Rect thirdRect = tester.getRect(find.byType(TextButton).at(2)); + Rect thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); expect(thirdRect.width, 50.0); expect(thirdRect.height, 60.0); @@ -207,7 +206,6 @@ void main() { ), ), child: ToggleButtons( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, isSelected: const <bool>[false, false, false], onPressed: (int index) {}, children: const <Widget>[ @@ -221,13 +219,13 @@ void main() { ), ); - firstRect = tester.getRect(find.byType(TextButton).at(0)); + firstRect = tester.getRect(find.byType(RawMaterialButton).at(0)); expect(firstRect.width, 20.0); expect(firstRect.height, 10.0); - secondRect = tester.getRect(find.byType(TextButton).at(1)); + secondRect = tester.getRect(find.byType(RawMaterialButton).at(1)); expect(secondRect.width, 20.0); expect(secondRect.height, 10.0); - thirdRect = tester.getRect(find.byType(TextButton).at(2)); + thirdRect = tester.getRect(find.byType(RawMaterialButton).at(2)); expect(thirdRect.width, 20.0); expect(thirdRect.height, 10.0); }); @@ -237,13 +235,13 @@ void main() { (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { return tester.widget<DefaultTextStyle>(find.descendant( - of: find.widgetWithText(TextButton, text), + of: find.widgetWithText(RawMaterialButton, text), matching: find.byType(DefaultTextStyle), )).style; } IconTheme iconTheme(IconData icon) { return tester.widget(find.descendant( - of: find.widgetWithIcon(TextButton, icon), + of: find.widgetWithIcon(RawMaterialButton, icon), matching: find.byType(IconTheme), )); } @@ -358,7 +356,7 @@ void main() { ); final Material material = tester.widget<Material>(find.descendant( - of: find.byType(TextButton), + of: find.byType(RawMaterialButton), matching: find.byType(Material), )); expect(material.color, customFillColor); @@ -369,7 +367,7 @@ void main() { Material buttonColor(String text) { return tester.widget<Material>( find.descendant( - of: find.byType(TextButton), + of: find.byType(RawMaterialButton), matching: find.widgetWithText(Material, text), ), ); @@ -478,6 +476,7 @@ void main() { inkFeatures, paints ..circle(color: splashColor) + ..rect(color: highlightColor), ); await touchGesture.up(); @@ -508,6 +507,7 @@ void main() { await hoverGesture.removePointer(); }); + testWidgets( 'Theme border width and border colors for enabled, selected and disabled states', (WidgetTester tester) async { From d15570e89b4a82f65ca0f39a5a40ce34e3cdcef5 Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Fri, 8 Apr 2022 15:34:48 -0700 Subject: [PATCH 24/41] [flutter_releases] Cherrypick engine to c341645 (#101608) --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 11049198223f9..7a0d49e979db4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b48d65e88cfa5b1a56ca84464bb680422ac6b6cb +c34164517800e8c352df350d10da494f34c302de From 13a2fb10b838971ce211230f8ffdd094c14af02c Mon Sep 17 00:00:00 2001 From: Kevin Chisholm <kevinjchisholm@google.com> Date: Tue, 12 Apr 2022 15:34:25 -0500 Subject: [PATCH 25/41] [flutter_releases] Flutter beta 2.12.0-4.1.pre Framework Cherrypicks (#101771) * 'Create candidate branch version flutter-2.13-candidate.0 for beta' * 'Update Engine revision to 499984f99cfe01e3b69d962ec4847f70c4317694 for beta release 2.12.0-4.1.pre' * update candidate version --- bin/internal/engine.version | 2 +- bin/internal/release-candidate-branch.version | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 bin/internal/release-candidate-branch.version diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7a0d49e979db4..4bb41dd4de1e2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c34164517800e8c352df350d10da494f34c302de +499984f99cfe01e3b69d962ec4847f70c4317694 diff --git a/bin/internal/release-candidate-branch.version b/bin/internal/release-candidate-branch.version new file mode 100644 index 0000000000000..91ca740dca227 --- /dev/null +++ b/bin/internal/release-candidate-branch.version @@ -0,0 +1 @@ +flutter-2.13-candidate.0 From 8cb02aab70130e5d38bc48d06a69de828332fba8 Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Wed, 20 Apr 2022 07:44:35 -0700 Subject: [PATCH 26/41] [flutter_releases] Flutter beta 2.13.0-0.2.pre Framework Cherrypicks (#102193) * Ensure that the engine frame callbacks are installed if the first scheduled frame is a forced frame (#101544) See https://github.com/flutter/flutter/issues/98419 * Migrate common buttons to Material 3 (#100794) * Always finish the timeline event logged by Element.inflateWidget (#101794) * 'Create candidate branch version flutter-2.13-candidate.0 for beta' * 'Update Engine revision to 24a02fa5ee681840cdc842c22f4cb4bdd5ec3115 for beta release 2.13.0-0.2.pre' * Update release-candidate-branch.version Co-authored-by: Jason Simmons <jason-simmons@users.noreply.github.com> Co-authored-by: Darren Austin <darrenaustin@google.com> --- bin/internal/engine.version | 2 +- dev/tools/gen_defaults/bin/gen_defaults.dart | 4 + .../gen_defaults/lib/button_template.dart | 153 ++++++++++++ dev/tools/gen_defaults/lib/template.dart | 28 ++- .../test/inflate_widget_update_test.dart | 77 +++++++ .../material/button_style/button_style.0.dart | 95 ++++++++ .../lib/src/material/button_style.dart | 34 +++ .../lib/src/material/button_style_button.dart | 2 + .../lib/src/material/elevated_button.dart | 218 +++++++++++++++--- .../lib/src/material/outlined_button.dart | 207 ++++++++++++++--- .../flutter/lib/src/material/text_button.dart | 193 +++++++++++++--- .../flutter/lib/src/material/theme_data.dart | 21 +- .../flutter/lib/src/scheduler/binding.dart | 1 + .../flutter/lib/src/widgets/framework.dart | 52 +++-- .../test/material/button_style_test.dart | 16 +- .../test/material/elevated_button_test.dart | 85 ++++--- .../test/material/outlined_button_test.dart | 174 ++++++++------ .../test/material/text_button_test.dart | 119 ++++++---- .../flutter/test/scheduler/binding_test.dart | 16 ++ 19 files changed, 1235 insertions(+), 262 deletions(-) create mode 100644 dev/tools/gen_defaults/lib/button_template.dart create mode 100644 dev/tracing_tests/test/inflate_widget_update_test.dart create mode 100644 examples/api/lib/material/button_style/button_style.0.dart create mode 100644 packages/flutter/test/scheduler/binding_test.dart diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4bb41dd4de1e2..98289243010fb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -499984f99cfe01e3b69d962ec4847f70c4317694 +24a02fa5ee681840cdc842c22f4cb4bdd5ec3115 diff --git a/dev/tools/gen_defaults/bin/gen_defaults.dart b/dev/tools/gen_defaults/bin/gen_defaults.dart index 187e0f757c703..0694020d09d94 100644 --- a/dev/tools/gen_defaults/bin/gen_defaults.dart +++ b/dev/tools/gen_defaults/bin/gen_defaults.dart @@ -17,6 +17,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:gen_defaults/button_template.dart'; import 'package:gen_defaults/card_template.dart'; import 'package:gen_defaults/dialog_template.dart'; import 'package:gen_defaults/fab_template.dart'; @@ -77,6 +78,9 @@ Future<void> main(List<String> args) async { tokens['colorsLight'] = _readTokenFile('color_light.json'); tokens['colorsDark'] = _readTokenFile('color_dark.json'); + ButtonTemplate('md.comp.elevated-button', '$materialLib/elevated_button.dart', tokens).updateFile(); + ButtonTemplate('md.comp.outlined-button', '$materialLib/outlined_button.dart', tokens).updateFile(); + ButtonTemplate('md.comp.text-button', '$materialLib/text_button.dart', tokens).updateFile(); CardTemplate('$materialLib/card.dart', tokens).updateFile(); DialogTemplate('$materialLib/dialog.dart', tokens).updateFile(); FABTemplate('$materialLib/floating_action_button.dart', tokens).updateFile(); diff --git a/dev/tools/gen_defaults/lib/button_template.dart b/dev/tools/gen_defaults/lib/button_template.dart new file mode 100644 index 0000000000000..381087194a650 --- /dev/null +++ b/dev/tools/gen_defaults/lib/button_template.dart @@ -0,0 +1,153 @@ +// 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 'template.dart'; + +class ButtonTemplate extends TokenTemplate { + const ButtonTemplate(this.tokenGroup, String fileName, Map<String, dynamic> tokens) + : super(fileName, tokens, + colorSchemePrefix: '_colors.', + ); + + final String tokenGroup; + + String _backgroundColor() { + if (tokens.containsKey('$tokenGroup.container.color')) { + return ''' + + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return ${componentColor('$tokenGroup.disabled.container')}; + return ${componentColor('$tokenGroup.container')}; + })'''; + } + return ''' + + ButtonStyleButton.allOrNull<Color>(Colors.transparent)'''; + } + + String _elevation() { + if (tokens.containsKey('$tokenGroup.container.elevation')) { + return ''' + + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return ${elevation("$tokenGroup.disabled.container")}; + if (states.contains(MaterialState.hovered)) + return ${elevation("$tokenGroup.hover.container")}; + if (states.contains(MaterialState.focused)) + return ${elevation("$tokenGroup.focus.container")}; + if (states.contains(MaterialState.pressed)) + return ${elevation("$tokenGroup.pressed.container")}; + return ${elevation("$tokenGroup.container")}; + })'''; + } + return ''' + + ButtonStyleButton.allOrNull<double>(0.0)'''; + } + + @override + String generate() => ''' +// Generated version ${tokens["version"]} +class _TokenDefaultsM3 extends ButtonStyle { + _TokenDefaultsM3(this.context) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + MaterialStateProperty<TextStyle?> get textStyle => + MaterialStateProperty.all<TextStyle?>(${textStyle("$tokenGroup.label-text")}); + + @override + MaterialStateProperty<Color?>? get backgroundColor =>${_backgroundColor()}; + + @override + MaterialStateProperty<Color?>? get foregroundColor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return ${componentColor('$tokenGroup.disabled.label-text')}; + return ${componentColor('$tokenGroup.label-text')}; + }); + + @override + MaterialStateProperty<Color?>? get overlayColor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.hovered)) + return ${componentColor('$tokenGroup.hover.state-layer')}; + if (states.contains(MaterialState.focused)) + return ${componentColor('$tokenGroup.focus.state-layer')}; + if (states.contains(MaterialState.pressed)) + return ${componentColor('$tokenGroup.pressed.state-layer')}; + return null; + }); + +${tokens.containsKey("$tokenGroup.container.shadow-color") ? ''' + @override + MaterialStateProperty<Color>? get shadowColor => + ButtonStyleButton.allOrNull<Color>(${color("$tokenGroup.container.shadow-color")});''' : ''' + // No default shadow color'''} + +${tokens.containsKey("$tokenGroup.container.surface-tint-layer.color") ? ''' + @override + MaterialStateProperty<Color>? get surfaceTintColor => + ButtonStyleButton.allOrNull<Color>(${color("$tokenGroup.container.surface-tint-layer.color")});''' : ''' + // No default surface tint color'''} + + @override + MaterialStateProperty<double>? get elevation =>${_elevation()}; + + @override + MaterialStateProperty<EdgeInsetsGeometry>? get padding => + ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(_scaledPadding(context)); + + @override + MaterialStateProperty<Size>? get minimumSize => + ButtonStyleButton.allOrNull<Size>(const Size(64.0, ${tokens["$tokenGroup.container.height"]})); + + // No default fixedSize + + @override + MaterialStateProperty<Size>? get maximumSize => + ButtonStyleButton.allOrNull<Size>(Size.infinite); + +${tokens.containsKey("$tokenGroup.outline.color") ? ''' + @override + MaterialStateProperty<BorderSide>? get side => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return ${border("$tokenGroup.disabled.outline")}; + return ${border("$tokenGroup.outline")}; + });''' : ''' + // No default side'''} + + @override + MaterialStateProperty<OutlinedBorder>? get shape => + ButtonStyleButton.allOrNull<OutlinedBorder>(${shape("$tokenGroup.container")}); + + @override + MaterialStateProperty<MouseCursor?>? get mouseCursor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return SystemMouseCursors.basic; + return SystemMouseCursors.click; + }); + + @override + VisualDensity? get visualDensity => Theme.of(context).visualDensity; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} +'''; +} diff --git a/dev/tools/gen_defaults/lib/template.dart b/dev/tools/gen_defaults/lib/template.dart index f63bea0e35ba2..ff378377af2ae 100644 --- a/dev/tools/gen_defaults/lib/template.dart +++ b/dev/tools/gen_defaults/lib/template.dart @@ -70,8 +70,8 @@ abstract class TokenTemplate { /// * [componentColor], that provides support for an optional opacity. String color(String colorToken) { return tokens.containsKey(colorToken) - ? '$colorSchemePrefix${tokens[colorToken]}' - : 'null'; + ? '$colorSchemePrefix${tokens[colorToken]}' + : 'null'; } /// Generate a [ColorScheme] color name for the given component's color @@ -91,17 +91,25 @@ abstract class TokenTemplate { if (!tokens.containsKey(colorToken)) return 'null'; String value = color(colorToken); - final String tokenOpacity = '$componentToken.opacity'; - if (tokens.containsKey(tokenOpacity)) { - final dynamic opacityValue = tokens[tokenOpacity]; - final String opacity = opacityValue is double - ? opacityValue.toString() - : tokens[tokens[tokenOpacity]!]!.toString(); - value += '.withOpacity($opacity)'; + final String opacityToken = '$componentToken.opacity'; + if (tokens.containsKey(opacityToken)) { + value += '.withOpacity(${opacity(opacityToken)})'; } return value; } + /// Generate the opacity value for the given token. + String? opacity(String token) { + final dynamic value = tokens[token]; + if (value == null) { + return null; + } + if (value is double) { + return value.toString(); + } + return tokens[value].toString(); + } + /// Generate an elevation value for the given component token. String elevation(String componentToken) { return tokens[tokens['$componentToken.elevation']!]!.toString(); @@ -135,7 +143,7 @@ abstract class TokenTemplate { return 'null'; } final String borderColor = componentColor(componentToken); - final double width = tokens['$componentToken.width'] as double; + final double width = (tokens['$componentToken.width'] ?? 1.0) as double; return 'BorderSide(color: $borderColor${width != 1.0 ? ", width: $width" : ""})'; } diff --git a/dev/tracing_tests/test/inflate_widget_update_test.dart b/dev/tracing_tests/test/inflate_widget_update_test.dart new file mode 100644 index 0000000000000..acfd014082f30 --- /dev/null +++ b/dev/tracing_tests/test/inflate_widget_update_test.dart @@ -0,0 +1,77 @@ +// 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 'package:flutter/scheduler.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'common.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + initTimelineTests(); + test('Widgets with updated keys produce well formed timelines', () async { + await runFrame(() { runApp(const TestRoot()); }); + await SchedulerBinding.instance.endOfFrame; + + debugProfileBuildsEnabled = true; + + await runFrame(() { + TestRoot.state.updateKey(); + }); + + int buildCount = 0; + for (final TimelineEvent event in await fetchTimelineEvents()) { + if (event.json!['name'] == 'BUILD') { + final String ph = event.json!['ph'] as String; + if (ph == 'B') { + buildCount++; + } else if (ph == 'E') { + buildCount--; + } + } + } + expect(buildCount, 0); + + debugProfileBuildsEnabled = false; + }, skip: isBrowser); // [intended] uses dart:isolate and io. +} + +class TestRoot extends StatefulWidget { + const TestRoot({super.key}); + + static late TestRootState state; + + @override + State<TestRoot> createState() => TestRootState(); +} + +class TestRootState extends State<TestRoot> { + final Key _globalKey = GlobalKey(); + Key _localKey = UniqueKey(); + + @override + void initState() { + super.initState(); + TestRoot.state = this; + } + + void updateKey() { + setState(() { + _localKey = UniqueKey(); + }); + } + + @override + Widget build(BuildContext context) { + return Center( + key: _localKey, + child: SizedBox( + key: _globalKey, + width: 100, + height: 100, + ), + ); + } +} diff --git a/examples/api/lib/material/button_style/button_style.0.dart b/examples/api/lib/material/button_style/button_style.0.dart new file mode 100644 index 0000000000000..bff8602c6a0af --- /dev/null +++ b/examples/api/lib/material/button_style/button_style.0.dart @@ -0,0 +1,95 @@ +// 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. + +// Flutter code sample for ElevatedButton + +import 'package:flutter/material.dart'; + +void main() { + runApp(const ButtonApp()); +} + +class ButtonApp extends StatelessWidget { + const ButtonApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true), + title: 'Button Types', + home: const Scaffold( + body: ButtonTypesExample(), + ), + ); + } +} + +class ButtonTypesExample extends StatelessWidget { + const ButtonTypesExample({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(4.0), + child: Row( + children: const <Widget>[ + Spacer(), + ButtonTypesGroup(enabled: true), + ButtonTypesGroup(enabled: false), + Spacer(), + ], + ), + ); + } +} + +class ButtonTypesGroup extends StatelessWidget { + const ButtonTypesGroup({ Key? key, required this.enabled }) : super(key: key); + + final bool enabled; + + @override + Widget build(BuildContext context) { + final VoidCallback? onPressed = enabled ? () {} : null; + return Padding( + padding: const EdgeInsets.all(4.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: <Widget>[ + ElevatedButton(onPressed: onPressed, child: const Text('Elevated')), + + // Use an ElevatedButton with specific style to implement the + // 'Filled' type. + ElevatedButton( + style: ElevatedButton.styleFrom( + // Foreground color + onPrimary: Theme.of(context).colorScheme.onPrimary, + // Background color + primary: Theme.of(context).colorScheme.primary, + ).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)), + onPressed: onPressed, + child: const Text('Filled'), + ), + + // Use an ElevatedButton with specific style to implement the + // 'Filled Tonal' type. + ElevatedButton( + style: ElevatedButton.styleFrom( + // Foreground color + onPrimary: Theme.of(context).colorScheme.onSecondaryContainer, + // Background color + primary: Theme.of(context).colorScheme.secondaryContainer, + ).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)), + onPressed: onPressed, + child: const Text('Filled Tonal'), + ), + + OutlinedButton(onPressed: onPressed, child: const Text('Outlined')), + + TextButton(onPressed: onPressed, child: const Text('Text')), + ], + ), + ); + } +} diff --git a/packages/flutter/lib/src/material/button_style.dart b/packages/flutter/lib/src/material/button_style.dart index 3d1ad80a5901a..4026fd7ed61d5 100644 --- a/packages/flutter/lib/src/material/button_style.dart +++ b/packages/flutter/lib/src/material/button_style.dart @@ -91,6 +91,27 @@ import 'theme_data.dart'; /// home: MyAppHome(), /// ) /// ``` +/// +/// ## Material 3 button types +/// +/// Material Design 3 specifies five types of common buttons. Flutter provides +/// support for these using the following button classes: +/// <style>table,td,th { border-collapse: collapse; padding: 0.45em; } td { border: 1px solid }</style> +/// +/// | Type | Flutter implementation | +/// | :----------- | :---------------------- | +/// | Elevated | [ElevatedButton] | +/// | Filled | Styled [ElevatedButton] | +/// | Filled Tonal | Styled [ElevatedButton] | +/// | Outlined | [OutlinedButton] | +/// | Text | [TextButton] | +/// +/// {@tool dartpad} +/// This sample shows how to create each of the Material 3 button types with Flutter. +/// +/// ** See code in examples/api/lib/material/button_style/button_style.0.dart ** +/// {@end-tool} +/// /// See also: /// /// * [TextButtonTheme], the theme for [TextButton]s. @@ -105,6 +126,7 @@ class ButtonStyle with Diagnosticable { this.foregroundColor, this.overlayColor, this.shadowColor, + this.surfaceTintColor, this.elevation, this.padding, this.minimumSize, @@ -150,6 +172,11 @@ class ButtonStyle with Diagnosticable { /// [ThemeData.applyElevationOverlayColor]. final MaterialStateProperty<Color?>? shadowColor; + /// The surface tint color of the button's [Material]. + /// + /// See [Material.surfaceTintColor] for more details. + final MaterialStateProperty<Color?>? surfaceTintColor; + /// The elevation of the button's [Material]. final MaterialStateProperty<double?>? elevation; @@ -267,6 +294,7 @@ class ButtonStyle with Diagnosticable { MaterialStateProperty<Color?>? foregroundColor, MaterialStateProperty<Color?>? overlayColor, MaterialStateProperty<Color?>? shadowColor, + MaterialStateProperty<Color?>? surfaceTintColor, MaterialStateProperty<double?>? elevation, MaterialStateProperty<EdgeInsetsGeometry?>? padding, MaterialStateProperty<Size?>? minimumSize, @@ -288,6 +316,7 @@ class ButtonStyle with Diagnosticable { foregroundColor: foregroundColor ?? this.foregroundColor, overlayColor: overlayColor ?? this.overlayColor, shadowColor: shadowColor ?? this.shadowColor, + surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, elevation: elevation ?? this.elevation, padding: padding ?? this.padding, minimumSize: minimumSize ?? this.minimumSize, @@ -319,6 +348,7 @@ class ButtonStyle with Diagnosticable { foregroundColor: foregroundColor ?? style.foregroundColor, overlayColor: overlayColor ?? style.overlayColor, shadowColor: shadowColor ?? style.shadowColor, + surfaceTintColor: surfaceTintColor ?? style.surfaceTintColor, elevation: elevation ?? style.elevation, padding: padding ?? style.padding, minimumSize: minimumSize ?? style.minimumSize, @@ -343,6 +373,7 @@ class ButtonStyle with Diagnosticable { foregroundColor, overlayColor, shadowColor, + surfaceTintColor, elevation, padding, minimumSize, @@ -371,6 +402,7 @@ class ButtonStyle with Diagnosticable { && other.foregroundColor == foregroundColor && other.overlayColor == overlayColor && other.shadowColor == shadowColor + && other.surfaceTintColor == surfaceTintColor && other.elevation == elevation && other.padding == padding && other.minimumSize == minimumSize @@ -395,6 +427,7 @@ class ButtonStyle with Diagnosticable { properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('foregroundColor', foregroundColor, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('overlayColor', overlayColor, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('shadowColor', shadowColor, defaultValue: null)); + properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('surfaceTintColor', surfaceTintColor, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<double?>>('elevation', elevation, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<EdgeInsetsGeometry?>>('padding', padding, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('minimumSize', minimumSize, defaultValue: null)); @@ -421,6 +454,7 @@ class ButtonStyle with Diagnosticable { foregroundColor: _lerpProperties<Color?>(a?.foregroundColor, b?.foregroundColor, t, Color.lerp), overlayColor: _lerpProperties<Color?>(a?.overlayColor, b?.overlayColor, t, Color.lerp), shadowColor: _lerpProperties<Color?>(a?.shadowColor, b?.shadowColor, t, Color.lerp), + surfaceTintColor: _lerpProperties<Color?>(a?.surfaceTintColor, b?.surfaceTintColor, t, Color.lerp), elevation: _lerpProperties<double?>(a?.elevation, b?.elevation, t, lerpDouble), padding: _lerpProperties<EdgeInsetsGeometry?>(a?.padding, b?.padding, t, EdgeInsetsGeometry.lerp), minimumSize: _lerpProperties<Size?>(a?.minimumSize, b?.minimumSize, t, Size.lerp), diff --git a/packages/flutter/lib/src/material/button_style_button.dart b/packages/flutter/lib/src/material/button_style_button.dart index 385fd228962e5..c30480b32cf95 100644 --- a/packages/flutter/lib/src/material/button_style_button.dart +++ b/packages/flutter/lib/src/material/button_style_button.dart @@ -247,6 +247,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with MaterialStateMixin Color? resolvedBackgroundColor = resolve<Color?>((ButtonStyle? style) => style?.backgroundColor); final Color? resolvedForegroundColor = resolve<Color?>((ButtonStyle? style) => style?.foregroundColor); final Color? resolvedShadowColor = resolve<Color?>((ButtonStyle? style) => style?.shadowColor); + final Color? resolvedSurfaceTintColor = resolve<Color?>((ButtonStyle? style) => style?.surfaceTintColor); final EdgeInsetsGeometry? resolvedPadding = resolve<EdgeInsetsGeometry?>((ButtonStyle? style) => style?.padding); final Size? resolvedMinimumSize = resolve<Size?>((ButtonStyle? style) => style?.minimumSize); final Size? resolvedFixedSize = resolve<Size?>((ButtonStyle? style) => style?.fixedSize); @@ -343,6 +344,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with MaterialStateMixin shape: resolvedShape!.copyWith(side: resolvedSide), color: resolvedBackgroundColor, shadowColor: resolvedShadowColor, + surfaceTintColor: resolvedSurfaceTintColor, type: resolvedBackgroundColor == null ? MaterialType.transparency : MaterialType.button, animationDuration: resolvedAnimationDuration, clipBehavior: widget.clipBehavior, diff --git a/packages/flutter/lib/src/material/elevated_button.dart b/packages/flutter/lib/src/material/elevated_button.dart index dbb3285199815..b01c3d68282e1 100644 --- a/packages/flutter/lib/src/material/elevated_button.dart +++ b/packages/flutter/lib/src/material/elevated_button.dart @@ -148,6 +148,7 @@ class ElevatedButton extends ButtonStyleButton { Color? onPrimary, Color? onSurface, Color? shadowColor, + Color? surfaceTintColor, double? elevation, TextStyle? textStyle, EdgeInsetsGeometry? padding, @@ -187,6 +188,7 @@ class ElevatedButton extends ButtonStyleButton { foregroundColor: foregroundColor, overlayColor: overlayColor, shadowColor: ButtonStyleButton.allOrNull<Color>(shadowColor), + surfaceTintColor: ButtonStyleButton.allOrNull<Color>(surfaceTintColor), elevation: elevationValue, padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding), minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize), @@ -228,6 +230,8 @@ class ElevatedButton extends ButtonStyleButton { /// The color of the [ButtonStyle.textStyle] is not used, the /// [ButtonStyle.foregroundColor] color is used instead. /// + /// ## Material 2 defaults + /// /// * `textStyle` - Theme.textTheme.button /// * `backgroundColor` /// * disabled - Theme.colorScheme.onSurface(0.12) @@ -245,7 +249,7 @@ class ElevatedButton extends ButtonStyleButton { /// * hovered or focused - 4 /// * pressed - 8 /// * `padding` - /// * textScaleFactor <= 1 - horizontal(16) + /// * `textScaleFactor <= 1` - horizontal(16) /// * `1 < textScaleFactor <= 2` - lerp(horizontal(16), horizontal(8)) /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4)) /// * `3 < textScaleFactor` - horizontal(4) @@ -276,38 +280,75 @@ class ElevatedButton extends ButtonStyleButton { /// outline, is null. That means that the outline is defined by the button /// shape's [OutlinedBorder.side]. Typically the default value of an /// [OutlinedBorder]'s side is [BorderSide.none], so an outline is not drawn. + /// + /// ## Material 3 defaults + /// + /// If [ThemeData.useMaterial3] is set to true the following defaults will + /// be used: + /// + /// * `textStyle` - Theme.textTheme.labelLarge + /// * `backgroundColor` + /// * disabled - Theme.colorScheme.onSurface(0.12) + /// * others - Theme.colorScheme.surface + /// * `foregroundColor` + /// * disabled - Theme.colorScheme.onSurface(0.38) + /// * others - Theme.colorScheme.primary + /// * `overlayColor` + /// * hovered - Theme.colorScheme.primary(0.08) + /// * focused or pressed - Theme.colorScheme.primary(0.12) + /// * `shadowColor` - Theme.colorScheme.shadow + /// * `surfaceTintColor` - Theme.colorScheme.surfaceTint + /// * `elevation` + /// * disabled - 0 + /// * default - 1 + /// * hovered - 3 + /// * focused or pressed - 1 + /// * `padding` + /// * `textScaleFactor <= 1` - horizontal(16) + /// * `1 < textScaleFactor <= 2` - lerp(horizontal(16), horizontal(8)) + /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4)) + /// * `3 < textScaleFactor` - horizontal(4) + /// * `minimumSize` - Size(64, 40) + /// * `fixedSize` - null + /// * `maximumSize` - Size.infinite + /// * `side` - null + /// * `shape` - StadiumBorder() + /// * `mouseCursor` + /// * disabled - SystemMouseCursors.basic + /// * others - SystemMouseCursors.click + /// * `visualDensity` - Theme.visualDensity + /// * `tapTargetSize` - Theme.materialTapTargetSize + /// * `animationDuration` - kThemeChangeDuration + /// * `enableFeedback` - true + /// * `alignment` - Alignment.center + /// * `splashFactory` - Theme.splashFactory @override ButtonStyle defaultStyleOf(BuildContext context) { final ThemeData theme = Theme.of(context); final ColorScheme colorScheme = theme.colorScheme; - final EdgeInsetsGeometry scaledPadding = ButtonStyleButton.scaledPadding( - const EdgeInsets.symmetric(horizontal: 16), - const EdgeInsets.symmetric(horizontal: 8), - const EdgeInsets.symmetric(horizontal: 4), - MediaQuery.maybeOf(context)?.textScaleFactor ?? 1, - ); - - return styleFrom( - primary: colorScheme.primary, - onPrimary: colorScheme.onPrimary, - onSurface: colorScheme.onSurface, - shadowColor: theme.shadowColor, - elevation: 2, - textStyle: theme.textTheme.button, - padding: scaledPadding, - minimumSize: const Size(64, 36), - maximumSize: Size.infinite, - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), - enabledMouseCursor: SystemMouseCursors.click, - disabledMouseCursor: SystemMouseCursors.basic, - visualDensity: theme.visualDensity, - tapTargetSize: theme.materialTapTargetSize, - animationDuration: kThemeChangeDuration, - enableFeedback: true, - alignment: Alignment.center, - splashFactory: theme.useMaterial3 ? theme.splashFactory : InkRipple.splashFactory, - ); + return Theme.of(context).useMaterial3 + ? _TokenDefaultsM3(context) + : styleFrom( + primary: colorScheme.primary, + onPrimary: colorScheme.onPrimary, + onSurface: colorScheme.onSurface, + shadowColor: theme.shadowColor, + elevation: 2, + textStyle: theme.textTheme.button, + padding: _scaledPadding(context), + minimumSize: const Size(64, 36), + maximumSize: Size.infinite, + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), + enabledMouseCursor: SystemMouseCursors.click, + disabledMouseCursor: SystemMouseCursors.basic, + visualDensity: theme.visualDensity, + tapTargetSize: theme.materialTapTargetSize, + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + splashFactory: InkRipple.splashFactory, + ); } /// Returns the [ElevatedButtonThemeData.style] of the closest @@ -318,6 +359,15 @@ class ElevatedButton extends ButtonStyleButton { } } +EdgeInsetsGeometry _scaledPadding(BuildContext context) { + return ButtonStyleButton.scaledPadding( + const EdgeInsets.symmetric(horizontal: 16), + const EdgeInsets.symmetric(horizontal: 8), + const EdgeInsets.symmetric(horizontal: 4), + MediaQuery.maybeOf(context)?.textScaleFactor ?? 1, + ); +} + @immutable class _ElevatedButtonDefaultBackground extends MaterialStateProperty<Color?> with Diagnosticable { _ElevatedButtonDefaultBackground(this.primary, this.onSurface); @@ -457,3 +507,115 @@ class _ElevatedButtonWithIconChild extends StatelessWidget { ); } } + +// BEGIN GENERATED TOKEN PROPERTIES + +// Generated code to the end of this file. Do not edit by hand. +// These defaults are generated from the Material Design Token +// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart. + +// Generated version v0_92 +class _TokenDefaultsM3 extends ButtonStyle { + _TokenDefaultsM3(this.context) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + MaterialStateProperty<TextStyle?> get textStyle => + MaterialStateProperty.all<TextStyle?>(Theme.of(context).textTheme.labelLarge); + + @override + MaterialStateProperty<Color?>? get backgroundColor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return _colors.onSurface.withOpacity(0.12); + return _colors.surface; + }); + + @override + MaterialStateProperty<Color?>? get foregroundColor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return _colors.onSurface.withOpacity(0.38); + return _colors.primary; + }); + + @override + MaterialStateProperty<Color?>? get overlayColor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.hovered)) + return _colors.primary.withOpacity(0.08); + if (states.contains(MaterialState.focused)) + return _colors.primary.withOpacity(0.12); + if (states.contains(MaterialState.pressed)) + return _colors.primary.withOpacity(0.12); + return null; + }); + + @override + MaterialStateProperty<Color>? get shadowColor => + ButtonStyleButton.allOrNull<Color>(_colors.shadow); + + @override + MaterialStateProperty<Color>? get surfaceTintColor => + ButtonStyleButton.allOrNull<Color>(_colors.surfaceTint); + + @override + MaterialStateProperty<double>? get elevation => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return 0.0; + if (states.contains(MaterialState.hovered)) + return 3.0; + if (states.contains(MaterialState.focused)) + return 1.0; + if (states.contains(MaterialState.pressed)) + return 1.0; + return 1.0; + }); + + @override + MaterialStateProperty<EdgeInsetsGeometry>? get padding => + ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(_scaledPadding(context)); + + @override + MaterialStateProperty<Size>? get minimumSize => + ButtonStyleButton.allOrNull<Size>(const Size(64.0, 40.0)); + + // No default fixedSize + + @override + MaterialStateProperty<Size>? get maximumSize => + ButtonStyleButton.allOrNull<Size>(Size.infinite); + + // No default side + + @override + MaterialStateProperty<OutlinedBorder>? get shape => + ButtonStyleButton.allOrNull<OutlinedBorder>(const StadiumBorder()); + + @override + MaterialStateProperty<MouseCursor?>? get mouseCursor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return SystemMouseCursors.basic; + return SystemMouseCursors.click; + }); + + @override + VisualDensity? get visualDensity => Theme.of(context).visualDensity; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} + +// END GENERATED TOKEN PROPERTIES diff --git a/packages/flutter/lib/src/material/outlined_button.dart b/packages/flutter/lib/src/material/outlined_button.dart index 0e233e618e3aa..e6fbdcd795f2f 100644 --- a/packages/flutter/lib/src/material/outlined_button.dart +++ b/packages/flutter/lib/src/material/outlined_button.dart @@ -146,6 +146,7 @@ class OutlinedButton extends ButtonStyleButton { Color? onSurface, Color? backgroundColor, Color? shadowColor, + Color? surfaceTintColor, double? elevation, TextStyle? textStyle, EdgeInsetsGeometry? padding, @@ -179,6 +180,7 @@ class OutlinedButton extends ButtonStyleButton { backgroundColor: ButtonStyleButton.allOrNull<Color>(backgroundColor), overlayColor: overlayColor, shadowColor: ButtonStyleButton.allOrNull<Color>(shadowColor), + surfaceTintColor: ButtonStyleButton.allOrNull<Color>(surfaceTintColor), elevation: ButtonStyleButton.allOrNull<double>(elevation), padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding), minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize), @@ -219,6 +221,8 @@ class OutlinedButton extends ButtonStyleButton { /// The color of the [ButtonStyle.textStyle] is not used, the /// [ButtonStyle.foregroundColor] is used instead. /// + /// ## Material 2 defaults + /// /// * `textStyle` - Theme.textTheme.button /// * `backgroundColor` - transparent /// * `foregroundColor` @@ -248,41 +252,75 @@ class OutlinedButton extends ButtonStyleButton { /// * `enableFeedback` - true /// * `alignment` - Alignment.center /// * `splashFactory` - InkRipple.splashFactory + /// + /// ## Material 3 defaults + /// + /// If [ThemeData.useMaterial3] is set to true the following defaults will + /// be used: + /// + /// * `textStyle` - Theme.textTheme.labelLarge + /// * `backgroundColor` - transparent + /// * `foregroundColor` + /// * disabled - Theme.colorScheme.onSurface(0.38) + /// * others - Theme.colorScheme.primary + /// * `overlayColor` + /// * hovered - Theme.colorScheme.primary(0.08) + /// * focused or pressed - Theme.colorScheme.primary(0.12) + /// * others - null + /// * `shadowColor` - null + /// * `surfaceTintColor` - null + /// * `elevation` - 0 + /// * `padding` + /// * `textScaleFactor <= 1` - horizontal(16) + /// * `1 < textScaleFactor <= 2` - lerp(horizontal(16), horizontal(8)) + /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4)) + /// * `3 < textScaleFactor` - horizontal(4) + /// * `minimumSize` - Size(64, 40) + /// * `fixedSize` - null + /// * `maximumSize` - Size.infinite + /// * `side` + /// * disabled - BorderSide(color: Theme.colorScheme.onSurface(0.12)) + /// * others - BorderSide(color: Theme.colorScheme.outline) + /// * `shape` - StadiumBorder() + /// * `mouseCursor` + /// * disabled - SystemMouseCursors.basic + /// * others - SystemMouseCursors.click + /// * `visualDensity` - theme.visualDensity + /// * `tapTargetSize` - theme.materialTapTargetSize + /// * `animationDuration` - kThemeChangeDuration + /// * `enableFeedback` - true + /// * `alignment` - Alignment.center + /// * `splashFactory` - Theme.splashFactory @override ButtonStyle defaultStyleOf(BuildContext context) { final ThemeData theme = Theme.of(context); final ColorScheme colorScheme = theme.colorScheme; - final EdgeInsetsGeometry scaledPadding = ButtonStyleButton.scaledPadding( - const EdgeInsets.symmetric(horizontal: 16), - const EdgeInsets.symmetric(horizontal: 8), - const EdgeInsets.symmetric(horizontal: 4), - MediaQuery.maybeOf(context)?.textScaleFactor ?? 1, - ); - - return styleFrom( - primary: colorScheme.primary, - onSurface: colorScheme.onSurface, - backgroundColor: Colors.transparent, - shadowColor: theme.shadowColor, - elevation: 0, - textStyle: theme.textTheme.button, - padding: scaledPadding, - minimumSize: const Size(64, 36), - maximumSize: Size.infinite, - side: BorderSide( - color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12), - ), - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), - enabledMouseCursor: SystemMouseCursors.click, - disabledMouseCursor: SystemMouseCursors.basic, - visualDensity: theme.visualDensity, - tapTargetSize: theme.materialTapTargetSize, - animationDuration: kThemeChangeDuration, - enableFeedback: true, - alignment: Alignment.center, - splashFactory: theme.useMaterial3 ? theme.splashFactory : InkRipple.splashFactory, - ); + return Theme.of(context).useMaterial3 + ? _TokenDefaultsM3(context) + : styleFrom( + primary: colorScheme.primary, + onSurface: colorScheme.onSurface, + backgroundColor: Colors.transparent, + shadowColor: theme.shadowColor, + elevation: 0, + textStyle: theme.textTheme.button, + padding: _scaledPadding(context), + minimumSize: const Size(64, 36), + maximumSize: Size.infinite, + side: BorderSide( + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12), + ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), + enabledMouseCursor: SystemMouseCursors.click, + disabledMouseCursor: SystemMouseCursors.basic, + visualDensity: theme.visualDensity, + tapTargetSize: theme.materialTapTargetSize, + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + splashFactory: InkRipple.splashFactory, + ); } @override @@ -291,6 +329,15 @@ class OutlinedButton extends ButtonStyleButton { } } +EdgeInsetsGeometry _scaledPadding(BuildContext context) { + return ButtonStyleButton.scaledPadding( + const EdgeInsets.symmetric(horizontal: 16), + const EdgeInsets.symmetric(horizontal: 8), + const EdgeInsets.symmetric(horizontal: 4), + MediaQuery.maybeOf(context)?.textScaleFactor ?? 1, + ); +} + @immutable class _OutlinedButtonDefaultForeground extends MaterialStateProperty<Color?> with Diagnosticable { _OutlinedButtonDefaultForeground(this.primary, this.onSurface); @@ -382,3 +429,103 @@ class _OutlinedButtonWithIconChild extends StatelessWidget { ); } } + +// BEGIN GENERATED TOKEN PROPERTIES + +// Generated code to the end of this file. Do not edit by hand. +// These defaults are generated from the Material Design Token +// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart. + +// Generated version v0_92 +class _TokenDefaultsM3 extends ButtonStyle { + _TokenDefaultsM3(this.context) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + MaterialStateProperty<TextStyle?> get textStyle => + MaterialStateProperty.all<TextStyle?>(Theme.of(context).textTheme.labelLarge); + + @override + MaterialStateProperty<Color?>? get backgroundColor => + ButtonStyleButton.allOrNull<Color>(Colors.transparent); + + @override + MaterialStateProperty<Color?>? get foregroundColor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return _colors.onSurface.withOpacity(0.38); + return _colors.primary; + }); + + @override + MaterialStateProperty<Color?>? get overlayColor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.hovered)) + return _colors.primary.withOpacity(0.08); + if (states.contains(MaterialState.focused)) + return _colors.primary.withOpacity(0.12); + if (states.contains(MaterialState.pressed)) + return _colors.primary.withOpacity(0.12); + return null; + }); + + // No default shadow color + + // No default surface tint color + + @override + MaterialStateProperty<double>? get elevation => + ButtonStyleButton.allOrNull<double>(0.0); + + @override + MaterialStateProperty<EdgeInsetsGeometry>? get padding => + ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(_scaledPadding(context)); + + @override + MaterialStateProperty<Size>? get minimumSize => + ButtonStyleButton.allOrNull<Size>(const Size(64.0, 40.0)); + + // No default fixedSize + + @override + MaterialStateProperty<Size>? get maximumSize => + ButtonStyleButton.allOrNull<Size>(Size.infinite); + + @override + MaterialStateProperty<BorderSide>? get side => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return BorderSide(color: _colors.onSurface.withOpacity(0.12)); + return BorderSide(color: _colors.outline); + }); + + @override + MaterialStateProperty<OutlinedBorder>? get shape => + ButtonStyleButton.allOrNull<OutlinedBorder>(const StadiumBorder()); + + @override + MaterialStateProperty<MouseCursor?>? get mouseCursor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return SystemMouseCursors.basic; + return SystemMouseCursors.click; + }); + + @override + VisualDensity? get visualDensity => Theme.of(context).visualDensity; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} + +// END GENERATED TOKEN PROPERTIES diff --git a/packages/flutter/lib/src/material/text_button.dart b/packages/flutter/lib/src/material/text_button.dart index 92fac91523607..2caa127f5b855 100644 --- a/packages/flutter/lib/src/material/text_button.dart +++ b/packages/flutter/lib/src/material/text_button.dart @@ -147,6 +147,7 @@ class TextButton extends ButtonStyleButton { Color? onSurface, Color? backgroundColor, Color? shadowColor, + Color? surfaceTintColor, double? elevation, TextStyle? textStyle, EdgeInsetsGeometry? padding, @@ -180,6 +181,7 @@ class TextButton extends ButtonStyleButton { foregroundColor: foregroundColor, overlayColor: overlayColor, shadowColor: ButtonStyleButton.allOrNull<Color>(shadowColor), + surfaceTintColor: ButtonStyleButton.allOrNull<Color>(surfaceTintColor), elevation: ButtonStyleButton.allOrNull<double>(elevation), padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding), minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize), @@ -223,6 +225,8 @@ class TextButton extends ButtonStyleButton { /// The color of the [ButtonStyle.textStyle] is not used, the /// [ButtonStyle.foregroundColor] color is used instead. /// + /// ## Material 2 defaults + /// /// * `textStyle` - Theme.textTheme.button /// * `backgroundColor` - transparent /// * `foregroundColor` @@ -264,38 +268,70 @@ class TextButton extends ButtonStyleButton { /// outline, is null. That means that the outline is defined by the button /// shape's [OutlinedBorder.side]. Typically the default value of an /// [OutlinedBorder]'s side is [BorderSide.none], so an outline is not drawn. + /// + /// ## Material 3 defaults + /// + /// If [ThemeData.useMaterial3] is set to true the following defaults will + /// be used: + /// + /// * `textStyle` - Theme.textTheme.labelLarge + /// * `backgroundColor` - transparent + /// * `foregroundColor` + /// * disabled - Theme.colorScheme.onSurface(0.38) + /// * others - Theme.colorScheme.primary + /// * `overlayColor` + /// * hovered - Theme.colorScheme.primary(0.08) + /// * focused or pressed - Theme.colorScheme.primary(0.12) + /// * others - null + /// * `shadowColor` - null + /// * `surfaceTintColor` - null + /// * `elevation` - 0 + /// * `padding` + /// * `textScaleFactor <= 1` - all(8) + /// * `1 < textScaleFactor <= 2` - lerp(all(8), horizontal(8)) + /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4)) + /// * `3 < textScaleFactor` - horizontal(4) + /// * `minimumSize` - Size(64, 40) + /// * `fixedSize` - null + /// * `maximumSize` - Size.infinite + /// * `side` - null + /// * `shape` - StadiumBorder() + /// * `mouseCursor` + /// * disabled - SystemMouseCursors.basic + /// * others - SystemMouseCursors.click + /// * `visualDensity` - theme.visualDensity + /// * `tapTargetSize` - theme.materialTapTargetSize + /// * `animationDuration` - kThemeChangeDuration + /// * `enableFeedback` - true + /// * `alignment` - Alignment.center + /// * `splashFactory` - Theme.splashFactory @override ButtonStyle defaultStyleOf(BuildContext context) { final ThemeData theme = Theme.of(context); final ColorScheme colorScheme = theme.colorScheme; - final EdgeInsetsGeometry scaledPadding = ButtonStyleButton.scaledPadding( - const EdgeInsets.all(8), - const EdgeInsets.symmetric(horizontal: 8), - const EdgeInsets.symmetric(horizontal: 4), - MediaQuery.maybeOf(context)?.textScaleFactor ?? 1, - ); - - return styleFrom( - primary: colorScheme.primary, - onSurface: colorScheme.onSurface, - backgroundColor: Colors.transparent, - shadowColor: theme.shadowColor, - elevation: 0, - textStyle: theme.textTheme.button, - padding: scaledPadding, - minimumSize: const Size(64, 36), - maximumSize: Size.infinite, - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), - enabledMouseCursor: SystemMouseCursors.click, - disabledMouseCursor: SystemMouseCursors.basic, - visualDensity: theme.visualDensity, - tapTargetSize: theme.materialTapTargetSize, - animationDuration: kThemeChangeDuration, - enableFeedback: true, - alignment: Alignment.center, - splashFactory: theme.useMaterial3 ? theme.splashFactory : InkRipple.splashFactory, - ); + return Theme.of(context).useMaterial3 + ? _TokenDefaultsM3(context) + : styleFrom( + primary: colorScheme.primary, + onSurface: colorScheme.onSurface, + backgroundColor: Colors.transparent, + shadowColor: theme.shadowColor, + elevation: 0, + textStyle: theme.textTheme.button, + padding: _scaledPadding(context), + minimumSize: const Size(64, 36), + maximumSize: Size.infinite, + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))), + enabledMouseCursor: SystemMouseCursors.click, + disabledMouseCursor: SystemMouseCursors.basic, + visualDensity: theme.visualDensity, + tapTargetSize: theme.materialTapTargetSize, + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + splashFactory: InkRipple.splashFactory, + ); } /// Returns the [TextButtonThemeData.style] of the closest @@ -306,6 +342,15 @@ class TextButton extends ButtonStyleButton { } } +EdgeInsetsGeometry _scaledPadding(BuildContext context) { + return ButtonStyleButton.scaledPadding( + const EdgeInsets.all(8), + const EdgeInsets.symmetric(horizontal: 8), + const EdgeInsets.symmetric(horizontal: 4), + MediaQuery.maybeOf(context)?.textScaleFactor ?? 1, + ); +} + @immutable class _TextButtonDefaultForeground extends MaterialStateProperty<Color?> { _TextButtonDefaultForeground(this.primary, this.onSurface); @@ -424,3 +469,97 @@ class _TextButtonWithIconChild extends StatelessWidget { ); } } + +// BEGIN GENERATED TOKEN PROPERTIES + +// Generated code to the end of this file. Do not edit by hand. +// These defaults are generated from the Material Design Token +// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart. + +// Generated version v0_92 +class _TokenDefaultsM3 extends ButtonStyle { + _TokenDefaultsM3(this.context) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + MaterialStateProperty<TextStyle?> get textStyle => + MaterialStateProperty.all<TextStyle?>(Theme.of(context).textTheme.labelLarge); + + @override + MaterialStateProperty<Color?>? get backgroundColor => + ButtonStyleButton.allOrNull<Color>(Colors.transparent); + + @override + MaterialStateProperty<Color?>? get foregroundColor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return _colors.onSurface.withOpacity(0.38); + return _colors.primary; + }); + + @override + MaterialStateProperty<Color?>? get overlayColor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.hovered)) + return _colors.primary.withOpacity(0.08); + if (states.contains(MaterialState.focused)) + return _colors.primary.withOpacity(0.12); + if (states.contains(MaterialState.pressed)) + return _colors.primary.withOpacity(0.12); + return null; + }); + + // No default shadow color + + // No default surface tint color + + @override + MaterialStateProperty<double>? get elevation => + ButtonStyleButton.allOrNull<double>(0.0); + + @override + MaterialStateProperty<EdgeInsetsGeometry>? get padding => + ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(_scaledPadding(context)); + + @override + MaterialStateProperty<Size>? get minimumSize => + ButtonStyleButton.allOrNull<Size>(const Size(64.0, 40.0)); + + // No default fixedSize + + @override + MaterialStateProperty<Size>? get maximumSize => + ButtonStyleButton.allOrNull<Size>(Size.infinite); + + // No default side + + @override + MaterialStateProperty<OutlinedBorder>? get shape => + ButtonStyleButton.allOrNull<OutlinedBorder>(const StadiumBorder()); + + @override + MaterialStateProperty<MouseCursor?>? get mouseCursor => + MaterialStateProperty.resolveWith((Set<MaterialState> states) { + if (states.contains(MaterialState.disabled)) + return SystemMouseCursors.basic; + return SystemMouseCursors.click; + }); + + @override + VisualDensity? get visualDensity => Theme.of(context).visualDensity; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} + +// END GENERATED TOKEN PROPERTIES diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index b7f79df85af11..95b445a88c303 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -1224,21 +1224,25 @@ class ThemeData with Diagnosticable { /// {@endtemplate} final VisualDensity visualDensity; - /// A temporary flag used to opt-in to new Material 3 features. + /// A temporary flag used to opt-in to Material 3 features. /// /// If true, then components that have been migrated to Material 3 will - /// start using new colors, typography and other features of Material 3. + /// use new colors, typography and other features of Material 3. /// If false, they will use the Material 2 look and feel. /// /// If a [ThemeData] is constructed with [useMaterial3] set to true, then /// some properties will get special defaults. However, just copying a [ThemeData] /// with [useMaterial3] set to true will not change any of these properties in the /// resulting [ThemeData]. These properties are: - /// | Property | [useMaterial3] default | fallback default | - /// |:---|:---|:---| - /// | [typography] | [Typography.material2021] | [Typography.material2014] | - /// | [splashFactory] | [InkSparkle]* | [InkSplash] | - /// *if and only if the target platform is Android and the app is not running on the web. + /// <style>table,td,th { border-collapse: collapse; padding: 0.45em; } td { border: 1px solid }</style> + /// + /// | Property | Material 3 default | Fallback default | + /// | :-------------- | :--------------------------- | :------------------------ | + /// | [typography] | [Typography.material2021] | [Typography.material2014] | + /// | [splashFactory] | [InkSparkle]* or [InkRipple] | [InkSplash] | + /// + /// \* if and only if the target platform is Android and the app is not + /// running on the web, otherwise it will fallback to [InkRipple]. /// /// During the migration to Material 3, turning this on may yield /// inconsistent look and feel in your app. Some components will be migrated @@ -1255,12 +1259,15 @@ class ThemeData with Diagnosticable { /// * [AlertDialog] /// * [Card] /// * [Dialog] + /// * [ElevatedButton] /// * [FloatingActionButton] /// * [Material] /// * [NavigationBar] /// * [NavigationRail] + /// * [OutlinedButton] /// * [StretchingOverscrollIndicator], replacing the /// [GlowingOverscrollIndicator] + /// * [TextButton] /// /// See also: /// diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart index eb1eb762bfea3..1be5607dcad83 100644 --- a/packages/flutter/lib/src/scheduler/binding.dart +++ b/packages/flutter/lib/src/scheduler/binding.dart @@ -825,6 +825,7 @@ mixin SchedulerBinding on BindingBase { debugPrintStack(label: 'scheduleForcedFrame() called. Current phase is $schedulerPhase.'); return true; }()); + ensureFrameCallbacksRegistered(); platformDispatcher.scheduleFrame(); _hasScheduledFrame = true; } diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index ac3673efe4d20..c6382b9d21ec7 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -3793,33 +3793,35 @@ abstract class Element extends DiagnosticableTree implements BuildContext { ); } - final Key? key = newWidget.key; - if (key is GlobalKey) { - final Element? newChild = _retakeInactiveElement(key, newWidget); - if (newChild != null) { - assert(newChild._parent == null); - assert(() { - _debugCheckForCycles(newChild); - return true; - }()); - newChild._activateWithParent(this, newSlot); - final Element? updatedChild = updateChild(newChild, newWidget, newSlot); - assert(newChild == updatedChild); - return updatedChild!; + try { + final Key? key = newWidget.key; + if (key is GlobalKey) { + final Element? newChild = _retakeInactiveElement(key, newWidget); + if (newChild != null) { + assert(newChild._parent == null); + assert(() { + _debugCheckForCycles(newChild); + return true; + }()); + newChild._activateWithParent(this, newSlot); + final Element? updatedChild = updateChild(newChild, newWidget, newSlot); + assert(newChild == updatedChild); + return updatedChild!; + } } - } - final Element newChild = newWidget.createElement(); - assert(() { - _debugCheckForCycles(newChild); - return true; - }()); - newChild.mount(this, newSlot); - assert(newChild._lifecycleState == _ElementLifecycle.active); - - if (isTimelineTracked) - Timeline.finishSync(); + final Element newChild = newWidget.createElement(); + assert(() { + _debugCheckForCycles(newChild); + return true; + }()); + newChild.mount(this, newSlot); + assert(newChild._lifecycleState == _ElementLifecycle.active); - return newChild; + return newChild; + } finally { + if (isTimelineTracked) + Timeline.finishSync(); + } } void _debugCheckForCycles(Element newChild) { diff --git a/packages/flutter/test/material/button_style_test.dart b/packages/flutter/test/material/button_style_test.dart index b9a2640429bc0..32afc9bb4fe3d 100644 --- a/packages/flutter/test/material/button_style_test.dart +++ b/packages/flutter/test/material/button_style_test.dart @@ -20,6 +20,8 @@ void main() { expect(style.backgroundColor, null); expect(style.foregroundColor, null); expect(style.overlayColor, null); + expect(style.shadowColor, null); + expect(style.surfaceTintColor, null); expect(style.elevation, null); expect(style.padding, null); expect(style.minimumSize, null); @@ -53,10 +55,12 @@ void main() { backgroundColor: MaterialStateProperty.all<Color>(const Color(0xfffffff1)), foregroundColor: MaterialStateProperty.all<Color>(const Color(0xfffffff2)), overlayColor: MaterialStateProperty.all<Color>(const Color(0xfffffff3)), + shadowColor: MaterialStateProperty.all<Color>(const Color(0xfffffff4)), + surfaceTintColor: MaterialStateProperty.all<Color>(const Color(0xfffffff5)), elevation: MaterialStateProperty.all<double>(1.5), padding: MaterialStateProperty.all<EdgeInsets>(const EdgeInsets.all(1.0)), minimumSize: MaterialStateProperty.all<Size>(const Size(1.0, 2.0)), - side: MaterialStateProperty.all<BorderSide>(const BorderSide(width: 4.0, color: Color(0xfffffff4))), + side: MaterialStateProperty.all<BorderSide>(const BorderSide(width: 4.0, color: Color(0xfffffff6))), maximumSize: MaterialStateProperty.all<Size>(const Size(100.0, 200.0)), shape: MaterialStateProperty.all<OutlinedBorder>(const StadiumBorder()), mouseCursor: MaterialStateProperty.all<MouseCursor>(SystemMouseCursors.forbidden), @@ -75,11 +79,13 @@ void main() { 'backgroundColor: MaterialStateProperty.all(Color(0xfffffff1))', 'foregroundColor: MaterialStateProperty.all(Color(0xfffffff2))', 'overlayColor: MaterialStateProperty.all(Color(0xfffffff3))', + 'shadowColor: MaterialStateProperty.all(Color(0xfffffff4))', + 'surfaceTintColor: MaterialStateProperty.all(Color(0xfffffff5))', 'elevation: MaterialStateProperty.all(1.5)', 'padding: MaterialStateProperty.all(EdgeInsets.all(1.0))', 'minimumSize: MaterialStateProperty.all(Size(1.0, 2.0))', 'maximumSize: MaterialStateProperty.all(Size(100.0, 200.0))', - 'side: MaterialStateProperty.all(BorderSide(Color(0xfffffff4), 4.0, BorderStyle.solid))', + 'side: MaterialStateProperty.all(BorderSide(Color(0xfffffff6), 4.0, BorderStyle.solid))', 'shape: MaterialStateProperty.all(StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none)))', 'mouseCursor: MaterialStateProperty.all(SystemMouseCursor(forbidden))', 'tapTargetSize: shrinkWrap', @@ -93,6 +99,8 @@ void main() { final MaterialStateProperty<Color> backgroundColor = MaterialStateProperty.all<Color>(const Color(0xfffffff1)); final MaterialStateProperty<Color> foregroundColor = MaterialStateProperty.all<Color>(const Color(0xfffffff2)); final MaterialStateProperty<Color> overlayColor = MaterialStateProperty.all<Color>(const Color(0xfffffff3)); + final MaterialStateProperty<Color> shadowColor = MaterialStateProperty.all<Color>(const Color(0xfffffff4)); + final MaterialStateProperty<Color> surfaceTintColor = MaterialStateProperty.all<Color>(const Color(0xfffffff5)); final MaterialStateProperty<double> elevation = MaterialStateProperty.all<double>(1); final MaterialStateProperty<EdgeInsets> padding = MaterialStateProperty.all<EdgeInsets>(const EdgeInsets.all(1)); final MaterialStateProperty<Size> minimumSize = MaterialStateProperty.all<Size>(const Size(1, 2)); @@ -111,6 +119,8 @@ void main() { backgroundColor: backgroundColor, foregroundColor: foregroundColor, overlayColor: overlayColor, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, elevation: elevation, padding: padding, minimumSize: minimumSize, @@ -132,6 +142,8 @@ void main() { backgroundColor: backgroundColor, foregroundColor: foregroundColor, overlayColor: overlayColor, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, elevation: elevation, padding: padding, minimumSize: minimumSize, diff --git a/packages/flutter/test/material/elevated_button_test.dart b/packages/flutter/test/material/elevated_button_test.dart index 12afdebd802b1..3478826985597 100644 --- a/packages/flutter/test/material/elevated_button_test.dart +++ b/packages/flutter/test/material/elevated_button_test.dart @@ -14,11 +14,13 @@ import '../widgets/semantics_tester.dart'; void main() { testWidgets('ElevatedButton, ElevatedButton.icon defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); + final ThemeData theme = ThemeData.from(colorScheme: colorScheme); + final bool material3 = theme.useMaterial3; // Enabled ElevatedButton await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: theme, home: Center( child: ElevatedButton( onPressed: () { }, @@ -39,11 +41,13 @@ void main() { expect(material.borderOnForeground, true); expect(material.borderRadius, null); expect(material.clipBehavior, Clip.none); - expect(material.color, colorScheme.primary); - expect(material.elevation, 2); + expect(material.color, material3 ? colorScheme.onPrimary : colorScheme.primary); + expect(material.elevation, material3 ? 1: 2); expect(material.shadowColor, const Color(0xff000000)); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); - expect(material.textStyle!.color, colorScheme.onPrimary); + expect(material.shape, material3 + ? const StadiumBorder() + : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); + expect(material.textStyle!.color, material3 ? colorScheme.primary : colorScheme.onPrimary); expect(material.textStyle!.fontFamily, 'Roboto'); expect(material.textStyle!.fontSize, 14); expect(material.textStyle!.fontWeight, FontWeight.w500); @@ -56,8 +60,13 @@ void main() { final TestGesture gesture = await tester.startGesture(center); await tester.pump(); // start the splash animation await tester.pump(const Duration(milliseconds: 100)); // splash is underway - final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); - expect(inkFeatures, paints..circle(color: colorScheme.onPrimary.withAlpha(0x3d))); // splash color is onPrimary(0.24) + + // Material 3 uses the InkSparkle which uses a shader, so we can't capture + // the effect with paint methods. + if (!material3) { + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + expect(inkFeatures, paints..circle(color: colorScheme.onPrimary.withOpacity(0.24))); + } // Only elevation changes when enabled and pressed. material = tester.widget<Material>(buttonMaterial); @@ -65,11 +74,13 @@ void main() { expect(material.borderOnForeground, true); expect(material.borderRadius, null); expect(material.clipBehavior, Clip.none); - expect(material.color, colorScheme.primary); - expect(material.elevation, 8); + expect(material.color, material3 ? colorScheme.onPrimary : colorScheme.primary); + expect(material.elevation, material3 ? 1 : 8); expect(material.shadowColor, const Color(0xff000000)); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); - expect(material.textStyle!.color, colorScheme.onPrimary); + expect(material.shape, material3 + ? const StadiumBorder() + : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); + expect(material.textStyle!.color, material3 ? colorScheme.primary : colorScheme.onPrimary); expect(material.textStyle!.fontFamily, 'Roboto'); expect(material.textStyle!.fontSize, 14); expect(material.textStyle!.fontWeight, FontWeight.w500); @@ -82,7 +93,7 @@ void main() { final Key iconButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: theme, home: Center( child: ElevatedButton.icon( key: iconButtonKey, @@ -104,11 +115,13 @@ void main() { expect(material.borderOnForeground, true); expect(material.borderRadius, null); expect(material.clipBehavior, Clip.none); - expect(material.color, colorScheme.primary); - expect(material.elevation, 2); + expect(material.color, material3 ? colorScheme.onPrimary : colorScheme.primary); + expect(material.elevation, material3? 1 : 2); expect(material.shadowColor, const Color(0xff000000)); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); - expect(material.textStyle!.color, colorScheme.onPrimary); + expect(material.shape, material3 + ? const StadiumBorder() + : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); + expect(material.textStyle!.color, material3 ? colorScheme.primary : colorScheme.onPrimary); expect(material.textStyle!.fontFamily, 'Roboto'); expect(material.textStyle!.fontSize, 14); expect(material.textStyle!.fontWeight, FontWeight.w500); @@ -117,7 +130,7 @@ void main() { // Disabled ElevatedButton await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: theme, home: const Center( child: ElevatedButton( onPressed: null, @@ -138,7 +151,9 @@ void main() { expect(material.color, colorScheme.onSurface.withOpacity(0.12)); expect(material.elevation, 0.0); expect(material.shadowColor, const Color(0xff000000)); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); + expect(material.shape, material3 + ? const StadiumBorder() + : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); expect(material.textStyle!.color, colorScheme.onSurface.withOpacity(0.38)); expect(material.textStyle!.fontFamily, 'Roboto'); expect(material.textStyle!.fontSize, 14); @@ -770,6 +785,9 @@ void main() { Future<void> buildTest(VisualDensity visualDensity, {bool useText = false}) async { return tester.pumpWidget( MaterialApp( + // Test was setup using fonts from Material 2, so make sure we always + // test against englishLike2014. + theme: ThemeData(textTheme: Typography.englishLike2014), home: Directionality( textDirection: TextDirection.rtl, child: Center( @@ -961,7 +979,15 @@ void main() { testWidgets(testName, (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light()), + theme: ThemeData( + colorScheme: const ColorScheme.light(), + // Force Material 2 defaults for the typography and size + // default values as the test was designed against these settings. + textTheme: Typography.englishLike2014, + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom(minimumSize: const Size(64, 36)), + ), + ), home: Builder( builder: (BuildContext context) { return MediaQuery( @@ -1137,7 +1163,7 @@ void main() { Widget buildFrame({ required bool enabled }) { return MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: ThemeData.from(colorScheme: colorScheme, useMaterial3: false), home: Center( child: ElevatedButton( onPressed: enabled ? () { } : null, @@ -1181,23 +1207,29 @@ void main() { const Color borderColor = Color(0xff4caf50); await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light()), + theme: ThemeData(colorScheme: const ColorScheme.light(), textTheme: Typography.englishLike2014, useMaterial3: false), home: Center( child: ElevatedButton( style: ElevatedButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16)), - side: BorderSide(width: 4, color: borderColor), + side: BorderSide(width: 10, color: borderColor), ), + minimumSize: const Size(64, 36), ), - onPressed: () { }, + onPressed: () {}, child: const Text('button'), ), ), ), ); - expect(find.byType(ElevatedButton), paints ..path(strokeWidth: 4) ..drrect(color: borderColor)); + expect(find.byType(ElevatedButton), paints ..drrect( + // Outer and inner rect that give the outline a width of 10. + outer: RRect.fromLTRBR(0.0, 0.0, 116.0, 36.0, const Radius.circular(16)), + inner: RRect.fromLTRBR(10.0, 10.0, 106.0, 26.0, const Radius.circular(16 - 10)), + color: borderColor) + ); }); testWidgets('Fixed size ElevatedButtons', (WidgetTester tester) async { @@ -1261,8 +1293,8 @@ void main() { await tester.pumpAndSettle(); } - // Default splashFactory (from Theme.of().splashFactory), one splash circle drawn. - await tester.pumpWidget(buildFrame()); + // InkRipple.splashFactory, one splash circle drawn. + await tester.pumpWidget(buildFrame(splashFactory: InkRipple.splashFactory)); { final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test'))); final MaterialInkController material = Material.of(tester.element(find.text('test')))!; @@ -1386,6 +1418,7 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData(textTheme: Typography.englishLike2014), home: Scaffold( body: Center( child: Column( diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index bcdbeb47f45e5..ecbf00c3cd514 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -14,11 +14,13 @@ import '../widgets/semantics_tester.dart'; void main() { testWidgets('OutlinedButton, OutlinedButton.icon defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); + final ThemeData theme = ThemeData.from(colorScheme: colorScheme); + final bool material3 = theme.useMaterial3; // Enabled OutlinedButton await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: theme, home: Center( child: OutlinedButton( onPressed: () { }, @@ -40,12 +42,14 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, const Color(0xff000000)); + expect(material.shadowColor, material3 ? null : const Color(0xff000000)); - expect(material.shape, isInstanceOf<RoundedRectangleBorder>()); - RoundedRectangleBorder materialShape = material.shape! as RoundedRectangleBorder; - expect(materialShape.side, BorderSide(color: colorScheme.onSurface.withOpacity(0.12))); - expect(materialShape.borderRadius, const BorderRadius.all(Radius.circular(4.0))); + expect(material.shape, material3 + ? StadiumBorder(side: BorderSide(color: colorScheme.outline)) + : RoundedRectangleBorder( + side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12)), + borderRadius: const BorderRadius.all(Radius.circular(4)) + )); expect(material.textStyle!.color, colorScheme.primary); expect(material.textStyle!.fontFamily, 'Roboto'); @@ -60,8 +64,13 @@ void main() { final TestGesture gesture = await tester.startGesture(center); await tester.pump(); // start the splash animation await tester.pump(const Duration(milliseconds: 100)); // splash is underway - final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); - expect(inkFeatures, paints..circle(color: colorScheme.primary.withAlpha(0x1f))); // splash color is primary(0.12) + + // Material 3 uses the InkSparkle which uses a shader, so we can't capture + // the effect with paint methods. + if (!material3) { + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + expect(inkFeatures, paints..circle(color: colorScheme.primary.withOpacity(0.12))); + } await gesture.up(); await tester.pumpAndSettle(); @@ -73,12 +82,14 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, const Color(0xff000000)); + expect(material.shadowColor, material3 ? null : const Color(0xff000000)); - expect(material.shape, isInstanceOf<RoundedRectangleBorder>()); - materialShape = material.shape! as RoundedRectangleBorder; - expect(materialShape.side, BorderSide(color: colorScheme.onSurface.withOpacity(0.12))); - expect(materialShape.borderRadius, const BorderRadius.all(Radius.circular(4.0))); + expect(material.shape, material3 + ? StadiumBorder(side: BorderSide(color: colorScheme.outline)) + : RoundedRectangleBorder( + side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12)), + borderRadius: const BorderRadius.all(Radius.circular(4)) + )); expect(material.textStyle!.color, colorScheme.primary); expect(material.textStyle!.fontFamily, 'Roboto'); @@ -90,7 +101,7 @@ void main() { final Key iconButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: theme, home: Center( child: OutlinedButton.icon( key: iconButtonKey, @@ -114,12 +125,14 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, const Color(0xff000000)); + expect(material.shadowColor, material3 ? null : const Color(0xff000000)); - expect(material.shape, isInstanceOf<RoundedRectangleBorder>()); - materialShape = material.shape! as RoundedRectangleBorder; - expect(materialShape.side, BorderSide(color: colorScheme.onSurface.withOpacity(0.12))); - expect(materialShape.borderRadius, const BorderRadius.all(Radius.circular(4.0))); + expect(material.shape, material3 + ? StadiumBorder(side: BorderSide(color: colorScheme.outline)) + : RoundedRectangleBorder( + side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12)), + borderRadius: const BorderRadius.all(Radius.circular(4)) + )); expect(material.textStyle!.color, colorScheme.primary); expect(material.textStyle!.fontFamily, 'Roboto'); @@ -130,7 +143,7 @@ void main() { // Disabled OutlinedButton await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: theme, home: const Center( child: OutlinedButton( onPressed: null, @@ -147,12 +160,14 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, const Color(0xff000000)); + expect(material.shadowColor, material3 ? null : const Color(0xff000000)); - expect(material.shape, isInstanceOf<RoundedRectangleBorder>()); - materialShape = material.shape! as RoundedRectangleBorder; - expect(materialShape.side, BorderSide(color: colorScheme.onSurface.withOpacity(0.12))); - expect(materialShape.borderRadius, const BorderRadius.all(Radius.circular(4.0))); + expect(material.shape, material3 + ? StadiumBorder(side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12))) + : RoundedRectangleBorder( + side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12)), + borderRadius: const BorderRadius.all(Radius.circular(4)) + )); expect(material.textStyle!.color, colorScheme.onSurface.withOpacity(0.38)); expect(material.textStyle!.fontFamily, 'Roboto'); @@ -531,6 +546,10 @@ void main() { child: OutlinedButton( style: ButtonStyle( side: MaterialStateProperty.resolveWith<BorderSide>(getBorderSide), + // Test assumes a rounded rect for the shape + shape: ButtonStyleButton.allOrNull( + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))) + ), ), onPressed: () {}, focusNode: focusNode, @@ -808,13 +827,14 @@ void main() { return Directionality( textDirection: TextDirection.ltr, child: Theme( - data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap), + data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, textTheme: Typography.englishLike2014), child: Container( alignment: Alignment.topLeft, child: OutlinedButton( style: OutlinedButton.styleFrom( shape: const RoundedRectangleBorder(), // default border radius is 0 backgroundColor: fillColor, + minimumSize: const Size(64, 36), ).copyWith( side: MaterialStateProperty.resolveWith<BorderSide>((Set<MaterialState> states) { if (states.contains(MaterialState.disabled)) @@ -964,20 +984,24 @@ void main() { testWidgets('OutlinedButton scales textScaleFactor', (WidgetTester tester) async { await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(), - child: Center( - child: OutlinedButton( - style: ButtonStyle( - // Specifying minimumSize to mimic the original minimumSize for - // RaisedButton so that the corresponding button size matches - // the original version of this test. - minimumSize: MaterialStateProperty.all<Size>(const Size(88, 36)), + Theme( + // Force Material 2 typography. + data: ThemeData(textTheme: Typography.englishLike2014), + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(), + child: Center( + child: OutlinedButton( + style: ButtonStyle( + // Specifying minimumSize to mimic the original minimumSize for + // RaisedButton so that the corresponding button size matches + // the original version of this test. + minimumSize: MaterialStateProperty.all<Size>(const Size(88, 36)), + ), + onPressed: () {}, + child: const Text('ABC'), ), - onPressed: () {}, - child: const Text('ABC'), ), ), ), @@ -989,20 +1013,24 @@ void main() { // textScaleFactor expands text, but not button. await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 1.3), - child: Center( - child: OutlinedButton( - style: ButtonStyle( - // Specifying minimumSize to mimic the original minimumSize for - // RaisedButton so that the corresponding button size matches - // the original version of this test. - minimumSize: MaterialStateProperty.all<Size>(const Size(88, 36)), + Theme( + // Force Material 2 typography. + data: ThemeData(textTheme: Typography.englishLike2014), + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(textScaleFactor: 1.3), + child: Center( + child: OutlinedButton( + style: ButtonStyle( + // Specifying minimumSize to mimic the original minimumSize for + // RaisedButton so that the corresponding button size matches + // the original version of this test. + minimumSize: MaterialStateProperty.all<Size>(const Size(88, 36)), + ), + onPressed: () {}, + child: const Text('ABC'), ), - onPressed: () {}, - child: const Text('ABC'), ), ), ), @@ -1017,14 +1045,18 @@ void main() { // Set text scale large enough to expand text and button. await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 3.0), - child: Center( - child: OutlinedButton( - onPressed: () {}, - child: const Text('ABC'), + Theme( + // Force Material 2 typography. + data: ThemeData(textTheme: Typography.englishLike2014), + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(textScaleFactor: 3.0), + child: Center( + child: OutlinedButton( + onPressed: () {}, + child: const Text('ABC'), + ), ), ), ), @@ -1039,7 +1071,6 @@ void main() { expect(tester.getSize(find.byType(Text)).height, equals(42.0)); }); - testWidgets('OutlinedButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { bool didPressButton = false; bool didLongPressButton = false; @@ -1078,11 +1109,15 @@ void main() { Future<void> buildTest(VisualDensity visualDensity, {bool useText = false}) async { return tester.pumpWidget( MaterialApp( + theme: ThemeData(textTheme: Typography.englishLike2014), home: Directionality( textDirection: TextDirection.rtl, child: Center( child: OutlinedButton( - style: ButtonStyle(visualDensity: visualDensity), + style: ButtonStyle( + visualDensity: visualDensity, + minimumSize: ButtonStyleButton.allOrNull(const Size(64, 36)), + ), key: key, onPressed: () {}, child: useText @@ -1203,7 +1238,15 @@ void main() { testWidgets(testName, (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light()), + theme: ThemeData( + colorScheme: const ColorScheme.light(), + // Force Material 2 defaults for the typography and size + // default values as the test was designed against these settings. + textTheme: Typography.englishLike2014, + outlinedButtonTheme: OutlinedButtonThemeData( + style: OutlinedButton.styleFrom(minimumSize: const Size(64, 36)), + ), + ), home: Builder( builder: (BuildContext context) { return MediaQuery( @@ -1434,8 +1477,8 @@ void main() { await tester.pumpAndSettle(); } - // Default splashFactory (from Theme.of().splashFactory), one splash circle drawn. - await tester.pumpWidget(buildFrame()); + // InkRipple.splashFactory, one splash circle drawn. + await tester.pumpWidget(buildFrame(splashFactory: InkRipple.splashFactory)); { final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test'))); final MaterialInkController material = Material.of(tester.element(find.text('test')))!; @@ -1559,6 +1602,7 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData(textTheme: Typography.englishLike2014), home: Scaffold( body: Center( child: Column( diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index ba90dc96d1b79..8da1d07bb9a74 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -14,11 +14,13 @@ import '../widgets/semantics_tester.dart'; void main() { testWidgets('TextButton, TextButton.icon defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); + final ThemeData theme = ThemeData.from(colorScheme: colorScheme); + final bool material3 = theme.useMaterial3; // Enabled TextButton await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: theme, home: Center( child: TextButton( onPressed: () { }, @@ -40,8 +42,10 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, const Color(0xff000000)); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0)))); + expect(material.shadowColor, material3 ? null : const Color(0xff000000)); + expect(material.shape, material3 + ? const StadiumBorder() + : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); expect(material.textStyle!.color, colorScheme.primary); expect(material.textStyle!.fontFamily, 'Roboto'); expect(material.textStyle!.fontSize, 14); @@ -55,8 +59,13 @@ void main() { final TestGesture gesture = await tester.startGesture(center); await tester.pump(); // start the splash animation await tester.pump(const Duration(milliseconds: 100)); // splash is underway - final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); - expect(inkFeatures, paints..circle(color: colorScheme.primary.withAlpha(0x1f))); // splash color is primary(0.12) + + // Material 3 uses the InkSparkle which uses a shader, so we can't capture + // the effect with paint methods. + if (!material3) { + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + expect(inkFeatures, paints..circle(color: colorScheme.primary.withOpacity(0.12))); + } await gesture.up(); await tester.pumpAndSettle(); @@ -68,8 +77,10 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, const Color(0xff000000)); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0)))); + expect(material.shadowColor, material3 ? null : const Color(0xff000000)); + expect(material.shape, material3 + ? const StadiumBorder() + : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); expect(material.textStyle!.color, colorScheme.primary); expect(material.textStyle!.fontFamily, 'Roboto'); expect(material.textStyle!.fontSize, 14); @@ -80,7 +91,7 @@ void main() { final Key iconButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: theme, home: Center( child: TextButton.icon( key: iconButtonKey, @@ -104,8 +115,10 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, const Color(0xff000000)); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0)))); + expect(material.shadowColor, material3 ? null : const Color(0xff000000)); + expect(material.shape, material3 + ? const StadiumBorder() + : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); expect(material.textStyle!.color, colorScheme.primary); expect(material.textStyle!.fontFamily, 'Roboto'); expect(material.textStyle!.fontSize, 14); @@ -115,7 +128,7 @@ void main() { // Disabled TextButton await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: colorScheme), + theme: theme, home: const Center( child: TextButton( onPressed: null, @@ -132,8 +145,10 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, const Color(0xff000000)); - expect(material.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0)))); + expect(material.shadowColor, material3 ? null : const Color(0xff000000)); + expect(material.shape, material3 + ? const StadiumBorder() + : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); expect(material.textStyle!.color, colorScheme.onSurface.withOpacity(0.38)); expect(material.textStyle!.fontFamily, 'Roboto'); expect(material.textStyle!.fontSize, 14); @@ -517,14 +532,18 @@ void main() { testWidgets('Does TextButton scale with font scale changes', (WidgetTester tester) async { await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(), - child: Center( - child: TextButton( - onPressed: () { }, - child: const Text('ABC'), + Theme( + // Force Material 2 typography. + data: ThemeData(textTheme: Typography.englishLike2014), + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(), + child: Center( + child: TextButton( + onPressed: () { }, + child: const Text('ABC'), + ), ), ), ), @@ -536,14 +555,18 @@ void main() { // textScaleFactor expands text, but not button. await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 1.3), - child: Center( - child: TextButton( - onPressed: () { }, - child: const Text('ABC'), + Theme( + // Force Material 2 typography. + data: ThemeData(textTheme: Typography.englishLike2014), + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(textScaleFactor: 1.3), + child: Center( + child: TextButton( + onPressed: () { }, + child: const Text('ABC'), + ), ), ), ), @@ -559,14 +582,18 @@ void main() { // Set text scale large enough to expand text and button. await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(textScaleFactor: 3.0), - child: Center( - child: TextButton( - onPressed: () { }, - child: const Text('ABC'), + Theme( + // Force Material 2 typography. + data: ThemeData(textTheme: Typography.englishLike2014), + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(textScaleFactor: 3.0), + child: Center( + child: TextButton( + onPressed: () { }, + child: const Text('ABC'), + ), ), ), ), @@ -581,7 +608,6 @@ void main() { expect(tester.getSize(find.byType(Text)).height, equals(42.0)); }); - testWidgets('TextButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) { return Theme( @@ -591,6 +617,7 @@ void main() { child: Center( child: TextButton( key: key, + style: TextButton.styleFrom(minimumSize: const Size(64, 36)), child: const SizedBox(width: 50.0, height: 8.0), onPressed: () { }, ), @@ -855,6 +882,7 @@ void main() { Future<void> buildTest(VisualDensity visualDensity, { bool useText = false }) async { return tester.pumpWidget( MaterialApp( + theme: ThemeData(textTheme: Typography.englishLike2014), home: Directionality( textDirection: TextDirection.rtl, child: Center( @@ -993,7 +1021,15 @@ void main() { testWidgets(testName, (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light()), + theme: ThemeData( + colorScheme: const ColorScheme.light(), + // Force Material 2 defaults for the typography and size + // default values as the test was designed against these settings. + textTheme: Typography.englishLike2014, + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom(minimumSize: const Size(64, 36)), + ), + ), home: Builder( builder: (BuildContext context) { return MediaQuery( @@ -1227,8 +1263,8 @@ void main() { await tester.pumpAndSettle(); } - // Default splashFactory (from Theme.of().splashFactory), one splash circle drawn. - await tester.pumpWidget(buildFrame()); + // InkRipple.splashFactory, one splash circle drawn. + await tester.pumpWidget(buildFrame(splashFactory: InkRipple.splashFactory)); { final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test'))); final MaterialInkController material = Material.of(tester.element(find.text('test')))!; @@ -1352,6 +1388,7 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData(textTheme: Typography.englishLike2014), home: Scaffold( body: Center( child: Column( diff --git a/packages/flutter/test/scheduler/binding_test.dart b/packages/flutter/test/scheduler/binding_test.dart new file mode 100644 index 0000000000000..d4018ff94ce83 --- /dev/null +++ b/packages/flutter/test/scheduler/binding_test.dart @@ -0,0 +1,16 @@ +// 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 'package:flutter/scheduler.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + + test('scheduleForcedFrame sets up frame callbacks', () async { + SchedulerBinding.instance.scheduleForcedFrame(); + expect(SchedulerBinding.instance.platformDispatcher.onBeginFrame, isNotNull); + }); +} From 8662e22bac54c71bc4fa5a4f37e9ee80bfd08a4e Mon Sep 17 00:00:00 2001 From: Christopher Fujino <christopherfujino@gmail.com> Date: Wed, 20 Apr 2022 08:21:52 -0700 Subject: [PATCH 27/41] [flutter_releases] Upgrade dwds to 12.1.1 (#101546) Co-authored-by: Casey Hillers <chillers@google.com> --- packages/flutter_tools/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 7a6ce76a025f8..831a824f1ffed 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: args: 2.3.0 browser_launcher: 1.1.0 dds: 2.2.0 - dwds: 12.1.0 + dwds: 12.1.1 completion: 1.0.0 coverage: 1.2.0 crypto: 3.0.1 @@ -105,4 +105,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: ba1b +# PUBSPEC CHECKSUM: 0a1c From 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Wed, 27 Apr 2022 12:37:50 -0700 Subject: [PATCH 28/41] [flutter_releases] Flutter beta 2.13.0-0.3.pre Framework Cherrypicks (#102620) * Handle CocoaPods ffi stderr (#102327) * Hide unresolved DartUri log messages (#102338) * 'Create candidate branch version flutter-2.13-candidate.0 for beta' * 'Update Engine revision to 3096903c8923608d3c1ccf8058a29c31a2bfbc53 for beta release 2.13.0-0.3.pre' * Update release-candidate-branch.version * Update packages/flutter_tools/lib/src/macos/cocoapods.dart * Remove skipped test from CP issue Co-authored-by: Jenn Magder <magder@google.com> Co-authored-by: Elliott Brooks (she/her) <21270878+elliette@users.noreply.github.com> --- bin/internal/engine.version | 2 +- .../flutter_tools/lib/src/isolated/devfs_web.dart | 10 ++++++++++ .../flutter_tools/lib/src/macos/cocoapods.dart | 7 ++++--- .../test/general.shard/macos/cocoapods_test.dart | 2 +- .../test/web.shard/output_web_test.dart | 14 ++++++++++++++ 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 98289243010fb..2d92142c3c902 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -24a02fa5ee681840cdc842c22f4cb4bdd5ec3115 +3096903c8923608d3c1ccf8058a29c31a2bfbc53 diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart index b111111ce63aa..a02b588fb3653 100644 --- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart +++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart @@ -1006,6 +1006,16 @@ void _log(logging.LogRecord event) { if (event.level >= logging.Level.SEVERE) { globals.printError('${event.loggerName}: ${event.message}$error', stackTrace: event.stackTrace); } else if (event.level == logging.Level.WARNING) { + // TODO(elliette): Remove the following message suppressions after DWDS is + // >13.1.0, https://github.com/flutter/flutter/issues/101639 + const String dartUri = 'DartUri'; + if (event.loggerName == dartUri) { + const String webSqlWarning = 'Unresolved uri: dart:web_sql'; + const String uiWarning = 'Unresolved uri: dart:ui'; + if (event.message == webSqlWarning || event.message == uiWarning) { + return; + } + } globals.printWarning('${event.loggerName}: ${event.message}$error'); } else { globals.printTrace('${event.loggerName}: ${event.message}$error'); diff --git a/packages/flutter_tools/lib/src/macos/cocoapods.dart b/packages/flutter_tools/lib/src/macos/cocoapods.dart index 7c3689e9bcebe..26365b6a46425 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapods.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapods.dart @@ -349,10 +349,11 @@ class CocoaPods { } void _diagnosePodInstallFailure(ProcessResult result) { - if (result.stdout is! String) { + final Object? stdout = result.stdout; + final Object? stderr = result.stderr; + if (stdout is! String || stderr is! String) { return; } - final String stdout = result.stdout as String; if (stdout.contains('out-of-date source repos')) { _logger.printError( "Error: CocoaPods's specs repository is too out-of-date to satisfy dependencies.\n" @@ -360,7 +361,7 @@ class CocoaPods { ' pod repo update\n', emphasis: true, ); - } else if (stdout.contains('ffi_c.bundle') && stdout.contains('LoadError') && + } else if ((stderr.contains('ffi_c.bundle') || stderr.contains('/ffi/')) && _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm) { // https://github.com/flutter/flutter/issues/70796 UsageEvent( diff --git a/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart b/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart index b49ea1fabccd9..e596bccb52a82 100644 --- a/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/cocoapods_test.dart @@ -513,7 +513,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by 'LANG': 'en_US.UTF-8', }, exitCode: 1, - stdout: cocoaPodsError, + stderr: cocoaPodsError, ), const FakeCommand( command: <String>['which', 'sysctl'], diff --git a/packages/flutter_tools/test/web.shard/output_web_test.dart b/packages/flutter_tools/test/web.shard/output_web_test.dart index b14660ee4a824..7fef5bc544f1d 100644 --- a/packages/flutter_tools/test/web.shard/output_web_test.dart +++ b/packages/flutter_tools/test/web.shard/output_web_test.dart @@ -78,4 +78,18 @@ void main() { await sendEvent(<String, Object>{'type': 'DevtoolsEvent'}); await warning; }); + + testWithoutContext( + 'flutter run output skips DartUri warning messages from dwds', () async { + bool containsDartUriWarning = false; + flutter.stderr.listen((String msg) { + if (msg.contains('DartUri')) { + containsDartUriWarning = true; + } + }); + await start(); + await flutter.stop(); + expect(containsDartUriWarning, isFalse); + // TODO(elliette): Enable for DWDS >13.1.0, https://github.com/flutter/flutter/issues/101639 + }, skip: true); // [intended] enable for DWDS >13.1.0 } From d3d6fbaaead95d9a0e3a2a1b694324200e72200c Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Wed, 27 Apr 2022 17:10:24 -0700 Subject: [PATCH 29/41] Enforce cpu explicitly for Mac devicelab test beds (#101871) (#102685) Co-authored-by: keyonghan <54558023+keyonghan@users.noreply.github.com> --- .ci.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 1bf7e08ea1499..240be0ff75f6c 100755 --- a/.ci.yaml +++ b/.ci.yaml @@ -85,7 +85,7 @@ platform_properties: [] os: Mac-12 device_type: none - mac_model: Macmini8,1 + cpu: x86 xcode: 13a233 mac_android: properties: @@ -106,6 +106,7 @@ platform_properties: {"dependency": "open_jdk", "version": "11"} ] os: Mac-12 + cpu: x86 device_os: N mac_ios: properties: @@ -127,6 +128,7 @@ platform_properties: {"dependency": "ios_signing"} ] os: Mac-12 + cpu: x86 device_os: iOS-15.1 xcode: 13a233 windows: From 25caf1461b8f643092a9f6f5b224453b5c057d10 Mon Sep 17 00:00:00 2001 From: Mudita Tandon <104382518+muditatandon@users.noreply.github.com> Date: Thu, 5 May 2022 14:23:09 -0700 Subject: [PATCH 30/41] [flutter_releases] Flutter beta 2.13.0-0.4.pre Framework Cherrypicks (#103101) * Add the new hash * [flutter.js] Wait for reg.update, then activate sw (if not active yet). (#101464) * Avoid scheduling a forced frame when there is no child to the renderView (#102556) * Migrate AppBar to Material 3 (#101884) * Keeping the super parameters * Fixing semi-colon issue Co-authored-by: David Iglesias <ditman@gmail.com> Co-authored-by: Dan Field <dnfield@google.com> Co-authored-by: Darren Austin <darrenaustin@google.com> --- bin/internal/engine.version | 2 +- dev/bots/service_worker_test.dart | 122 ++++++++- dev/bots/test.dart | 4 +- .../web/web/index_with_flutterjs.html | 39 +++ .../web/web/index_with_flutterjs_short.html | 37 +++ .../web/web/index_without_flutterjs.html | 86 +++++++ dev/tools/gen_defaults/bin/gen_defaults.dart | 2 + .../gen_defaults/lib/app_bar_template.dart | 58 +++++ .../flutter/lib/src/material/app_bar.dart | 217 +++++++++++++--- .../lib/src/material/app_bar_theme.dart | 22 ++ .../flutter/lib/src/material/material.dart | 31 ++- .../flutter/lib/src/material/theme_data.dart | 1 + .../flutter/lib/src/rendering/binding.dart | 5 +- .../flutter/test/material/app_bar_test.dart | 130 +++++++--- .../test/material/app_bar_theme_test.dart | 240 +++++++++++++----- .../flutter/test/rendering/binding_test.dart | 22 ++ .../flutter_tools/lib/src/web/flutter_js.dart | 53 ++-- 17 files changed, 892 insertions(+), 179 deletions(-) create mode 100644 dev/integration_tests/web/web/index_with_flutterjs.html create mode 100644 dev/integration_tests/web/web/index_with_flutterjs_short.html create mode 100644 dev/integration_tests/web/web/index_without_flutterjs.html create mode 100644 dev/tools/gen_defaults/lib/app_bar_template.dart create mode 100644 packages/flutter/test/rendering/binding_test.dart diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2d92142c3c902..9aa00d60d4ddc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3096903c8923608d3c1ccf8058a29c31a2bfbc53 +c5caf749fe75db788dba8def502c46c094435605 diff --git a/dev/bots/service_worker_test.dart b/dev/bots/service_worker_test.dart index 0b30533ff71ea..10432c7a352aa 100644 --- a/dev/bots/service_worker_test.dart +++ b/dev/bots/service_worker_test.dart @@ -17,13 +17,22 @@ final String _bat = Platform.isWindows ? '.bat' : ''; final String _flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); final String _flutter = path.join(_flutterRoot, 'bin', 'flutter$_bat'); final String _testAppDirectory = path.join(_flutterRoot, 'dev', 'integration_tests', 'web'); +final String _testAppWebDirectory = path.join(_testAppDirectory, 'web'); final String _appBuildDirectory = path.join(_testAppDirectory, 'build', 'web'); final String _target = path.join('lib', 'service_worker_test.dart'); final String _targetPath = path.join(_testAppDirectory, _target); +enum ServiceWorkerTestType { + withoutFlutterJs, + withFlutterJs, + withFlutterJsShort, +} + // Run a web service worker test as a standalone Dart program. Future<void> main() async { - await runWebServiceWorkerTest(headless: false); + await runWebServiceWorkerTest(headless: false, testType: ServiceWorkerTestType.withFlutterJs); + await runWebServiceWorkerTest(headless: false, testType: ServiceWorkerTestType.withoutFlutterJs); + await runWebServiceWorkerTest(headless: false, testType: ServiceWorkerTestType.withFlutterJsShort); } Future<void> _setAppVersion(int version) async { @@ -36,13 +45,37 @@ Future<void> _setAppVersion(int version) async { ); } -Future<void> _rebuildApp({ required int version }) async { +String _testTypeToIndexFile(ServiceWorkerTestType type) { + late String indexFile; + switch (type) { + case ServiceWorkerTestType.withFlutterJs: + indexFile = 'index_with_flutterjs.html'; + break; + case ServiceWorkerTestType.withoutFlutterJs: + indexFile = 'index_without_flutterjs.html'; + break; + case ServiceWorkerTestType.withFlutterJsShort: + indexFile = 'index_with_flutterjs_short.html'; + break; + } + return indexFile; +} + +Future<void> _rebuildApp({ required int version, required ServiceWorkerTestType testType }) async { await _setAppVersion(version); await runCommand( _flutter, <String>[ 'clean' ], workingDirectory: _testAppDirectory, ); + await runCommand( + 'cp', + <String>[ + _testTypeToIndexFile(testType), + 'index.html', + ], + workingDirectory: _testAppWebDirectory, + ); await runCommand( _flutter, <String>['build', 'web', '--profile', '-t', _target], @@ -69,9 +102,8 @@ void expect(Object? actual, Object? expected) { Future<void> runWebServiceWorkerTest({ required bool headless, + required ServiceWorkerTestType testType, }) async { - await _rebuildApp(version: 1); - final Map<String, int> requestedPathCounts = <String, int>{}; void expectRequestCounts(Map<String, int> expectedCounts) { expect(requestedPathCounts, expectedCounts); @@ -124,10 +156,64 @@ Future<void> runWebServiceWorkerTest({ ); } + // Preserve old index.html as index_og.html so we can restore it later for other tests + await runCommand( + 'mv', + <String>[ + 'index.html', + 'index_og.html', + ], + workingDirectory: _testAppWebDirectory, + ); + + final bool shouldExpectFlutterJs = testType != ServiceWorkerTestType.withoutFlutterJs; + + print('BEGIN runWebServiceWorkerTest(headless: $headless, testType: $testType)\n'); + try { + ///// + // Attempt to load a different version of the service worker! + ///// + await _rebuildApp(version: 1, testType: testType); + + print('Call update() on the current web worker'); + await startAppServer(cacheControl: 'max-age=0'); + await waitForAppToLoad(<String, int> { + if (shouldExpectFlutterJs) + 'flutter.js': 1, + 'CLOSE': 1, + }); + expect(reportedVersion, '1'); + reportedVersion = null; + + await server!.chrome.reloadPage(ignoreCache: true); + await waitForAppToLoad(<String, int> { + if (shouldExpectFlutterJs) + 'flutter.js': 2, + 'CLOSE': 2, + }); + expect(reportedVersion, '1'); + reportedVersion = null; + + await _rebuildApp(version: 2, testType: testType); + + await server!.chrome.reloadPage(ignoreCache: true); + await waitForAppToLoad(<String, int>{ + if (shouldExpectFlutterJs) + 'flutter.js': 3, + 'CLOSE': 3, + }); + expect(reportedVersion, '2'); + + reportedVersion = null; + requestedPathCounts.clear(); + await server!.stop(); + ////////////////////////////////////////////////////// // Caching server ////////////////////////////////////////////////////// + await _rebuildApp(version: 1, testType: testType); + print('With cache: test first page load'); await startAppServer(cacheControl: 'max-age=3600'); await waitForAppToLoad(<String, int>{ @@ -140,6 +226,8 @@ Future<void> runWebServiceWorkerTest({ // once by the initial page load, and once by the service worker. // Other resources are loaded once only by the service worker. 'index.html': 2, + if (shouldExpectFlutterJs) + 'flutter.js': 1, 'main.dart.js': 1, 'flutter_service_worker.js': 1, 'assets/FontManifest.json': 1, @@ -171,7 +259,7 @@ Future<void> runWebServiceWorkerTest({ reportedVersion = null; print('With cache: test page reload after rebuild'); - await _rebuildApp(version: 2); + await _rebuildApp(version: 2, testType: testType); // Since we're caching, we need to ignore cache when reloading the page. await server!.chrome.reloadPage(ignoreCache: true); @@ -181,6 +269,8 @@ Future<void> runWebServiceWorkerTest({ }); expectRequestCounts(<String, int>{ 'index.html': 2, + if (shouldExpectFlutterJs) + 'flutter.js': 1, 'flutter_service_worker.js': 2, 'main.dart.js': 1, 'assets/NOTICES': 1, @@ -200,7 +290,7 @@ Future<void> runWebServiceWorkerTest({ // Non-caching server ////////////////////////////////////////////////////// print('No cache: test first page load'); - await _rebuildApp(version: 3); + await _rebuildApp(version: 3, testType: testType); await startAppServer(cacheControl: 'max-age=0'); await waitForAppToLoad(<String, int>{ 'CLOSE': 1, @@ -209,6 +299,8 @@ Future<void> runWebServiceWorkerTest({ expectRequestCounts(<String, int>{ 'index.html': 2, + if (shouldExpectFlutterJs) + 'flutter.js': 1, // We still download some resources multiple times if the server is non-caching. 'main.dart.js': 2, 'assets/FontManifest.json': 2, @@ -231,10 +323,14 @@ Future<void> runWebServiceWorkerTest({ await server!.chrome.reloadPage(); await waitForAppToLoad(<String, int>{ 'CLOSE': 1, + if (shouldExpectFlutterJs) + 'flutter.js': 1, 'flutter_service_worker.js': 1, }); expectRequestCounts(<String, int>{ + if (shouldExpectFlutterJs) + 'flutter.js': 1, 'flutter_service_worker.js': 1, 'CLOSE': 1, if (!headless) @@ -244,7 +340,7 @@ Future<void> runWebServiceWorkerTest({ reportedVersion = null; print('No cache: test page reload after rebuild'); - await _rebuildApp(version: 4); + await _rebuildApp(version: 4, testType: testType); // TODO(yjbanov): when running Chrome with DevTools protocol, for some // reason a hard refresh is still required. This works without a hard @@ -258,6 +354,8 @@ Future<void> runWebServiceWorkerTest({ }); expectRequestCounts(<String, int>{ 'index.html': 2, + if (shouldExpectFlutterJs) + 'flutter.js': 1, 'flutter_service_worker.js': 2, 'main.dart.js': 2, 'assets/NOTICES': 1, @@ -274,7 +372,17 @@ Future<void> runWebServiceWorkerTest({ expect(reportedVersion, '4'); reportedVersion = null; } finally { + await runCommand( + 'mv', + <String>[ + 'index_og.html', + 'index.html', + ], + workingDirectory: _testAppWebDirectory, + ); await _setAppVersion(1); await server?.stop(); } + + print('END runWebServiceWorkerTest(headless: $headless, testType: $testType)\n'); } diff --git a/dev/bots/test.dart b/dev/bots/test.dart index f58b9ebf99344..c2efd2dc289f3 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -1070,7 +1070,9 @@ Future<void> _runWebLongRunningTests() async { () => _runGalleryE2eWebTest('profile', canvasKit: true), () => _runGalleryE2eWebTest('release'), () => _runGalleryE2eWebTest('release', canvasKit: true), - () => runWebServiceWorkerTest(headless: true), + () => runWebServiceWorkerTest(headless: true, testType: ServiceWorkerTestType.withoutFlutterJs), + () => runWebServiceWorkerTest(headless: true, testType: ServiceWorkerTestType.withFlutterJs), + () => runWebServiceWorkerTest(headless: true, testType: ServiceWorkerTestType.withFlutterJsShort), () => _runWebStackTraceTest('profile', 'lib/stack_trace.dart'), () => _runWebStackTraceTest('release', 'lib/stack_trace.dart'), () => _runWebStackTraceTest('profile', 'lib/framework_stack_trace.dart'), diff --git a/dev/integration_tests/web/web/index_with_flutterjs.html b/dev/integration_tests/web/web/index_with_flutterjs.html new file mode 100644 index 0000000000000..8334b5b641ac8 --- /dev/null +++ b/dev/integration_tests/web/web/index_with_flutterjs.html @@ -0,0 +1,39 @@ +<!DOCTYPE HTML> +<!-- 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. --> +<html> +<head> + <meta charset="UTF-8"> + <meta content="IE=Edge" http-equiv="X-UA-Compatible"> + + <title>Web Test + + + + + + + + + + + + + diff --git a/dev/integration_tests/web/web/index_with_flutterjs_short.html b/dev/integration_tests/web/web/index_with_flutterjs_short.html new file mode 100644 index 0000000000000..21a494facb002 --- /dev/null +++ b/dev/integration_tests/web/web/index_with_flutterjs_short.html @@ -0,0 +1,37 @@ + + + + + + + + Web Test + + + + + + + + + + + + + diff --git a/dev/integration_tests/web/web/index_without_flutterjs.html b/dev/integration_tests/web/web/index_without_flutterjs.html new file mode 100644 index 0000000000000..05d4deecc14ea --- /dev/null +++ b/dev/integration_tests/web/web/index_without_flutterjs.html @@ -0,0 +1,86 @@ + + + + + + + + Web Test + + + + + + + + + + + diff --git a/dev/tools/gen_defaults/bin/gen_defaults.dart b/dev/tools/gen_defaults/bin/gen_defaults.dart index 0694020d09d94..d2b4fc53a0e90 100644 --- a/dev/tools/gen_defaults/bin/gen_defaults.dart +++ b/dev/tools/gen_defaults/bin/gen_defaults.dart @@ -17,6 +17,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:gen_defaults/app_bar_template.dart'; import 'package:gen_defaults/button_template.dart'; import 'package:gen_defaults/card_template.dart'; import 'package:gen_defaults/dialog_template.dart'; @@ -78,6 +79,7 @@ Future main(List args) async { tokens['colorsLight'] = _readTokenFile('color_light.json'); tokens['colorsDark'] = _readTokenFile('color_dark.json'); + AppBarTemplate('$materialLib/app_bar.dart', tokens).updateFile(); ButtonTemplate('md.comp.elevated-button', '$materialLib/elevated_button.dart', tokens).updateFile(); ButtonTemplate('md.comp.outlined-button', '$materialLib/outlined_button.dart', tokens).updateFile(); ButtonTemplate('md.comp.text-button', '$materialLib/text_button.dart', tokens).updateFile(); diff --git a/dev/tools/gen_defaults/lib/app_bar_template.dart b/dev/tools/gen_defaults/lib/app_bar_template.dart new file mode 100644 index 0000000000000..06b2ddfe028c4 --- /dev/null +++ b/dev/tools/gen_defaults/lib/app_bar_template.dart @@ -0,0 +1,58 @@ +// 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 'template.dart'; + +class AppBarTemplate extends TokenTemplate { + const AppBarTemplate(super.fileName, super.tokens) + : super( + colorSchemePrefix: '_colors.', + textThemePrefix: '_textTheme.', + ); + + @override + String generate() => ''' +// Generated version ${tokens["version"]} +class _TokenDefaultsM3 extends AppBarTheme { + _TokenDefaultsM3(this.context) + : super( + elevation: ${elevation('md.comp.top-app-bar.small.container')}, + scrolledUnderElevation: ${elevation('md.comp.top-app-bar.small.on-scroll.container')}, + titleSpacing: NavigationToolbar.kMiddleSpacing, + toolbarHeight: ${tokens['md.comp.top-app-bar.small.container.height']}, + ); + + final BuildContext context; + late final ThemeData _theme = Theme.of(context); + late final ColorScheme _colors = _theme.colorScheme; + late final TextTheme _textTheme = _theme.textTheme; + + @override + Color? get backgroundColor => ${componentColor('md.comp.top-app-bar.small.container')}; + + @override + 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')}; + + @override + IconThemeData? get iconTheme => IconThemeData( + color: ${componentColor('md.comp.top-app-bar.small.leading-icon')}, + size: ${tokens['md.comp.top-app-bar.small.leading-icon.size']}, + ); + + @override + IconThemeData? get actionsIconTheme => IconThemeData( + color: ${componentColor('md.comp.top-app-bar.small.trailing-icon')}, + size: ${tokens['md.comp.top-app-bar.small.trailing-icon.size']}, + ); + + @override + TextStyle? get toolbarTextStyle => _textTheme.bodyText2; + + @override + TextStyle? get titleTextStyle => ${textStyle('md.comp.top-app-bar.small.headline')}; +}'''; +} diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index 086095c70bb0d..28303fefd0cfb 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -161,7 +161,9 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { this.flexibleSpace, this.bottom, this.elevation, + this.scrolledUnderElevation, this.shadowColor, + this.surfaceTintColor, this.shape, this.backgroundColor, this.foregroundColor, @@ -373,7 +375,12 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// {@template flutter.material.appbar.elevation} /// The z-coordinate at which to place this app bar relative to its parent. /// - /// This property controls the size of the shadow below the app bar. + /// This property controls the size of the shadow below the app bar if + /// [shadowColor] is not null. + /// + /// If [surfaceTintColor] is not null then it will apply a surface tint overlay + /// to the background color (see [Material.surfaceTintColor] for more + /// detail). /// /// The value must be non-negative. /// @@ -384,11 +391,37 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// /// See also: /// + /// * [scrolledUnderElevation], which will be used when the app bar has + /// something scrolled underneath it. /// * [shadowColor], which is the color of the shadow below the app bar. + /// * [surfaceTintColor], which determines the elevation overlay that will + /// be applied to the background of the app bar. /// * [shape], which defines the shape of the app bar's [Material] and its /// shadow. final double? elevation; + /// {@template flutter.material.appbar.scrolledUnderElevation} + /// The elevation that will be used if this app bar has something + /// scrolled underneath it. + /// + /// If non-null then it [AppBarTheme.scrolledUnderElevation] of + /// [ThemeData.appBarTheme] will be used. If that is also null then [elevation] + /// will be used. + /// + /// The value must be non-negative. + /// + /// {@endtemplate} + /// + /// See also: + /// * [elevation], which will be used if there is no content scrolled under + /// the app bar. + /// * [shadowColor], which is the color of the shadow below the app bar. + /// * [surfaceTintColor], which determines the elevation overlay that will + /// be applied to the background of the app bar. + /// * [shape], which defines the shape of the app bar's [Material] and its + /// shadow. + final double? scrolledUnderElevation; + /// {@template flutter.material.appbar.shadowColor} /// The color of the shadow below the app bar. /// @@ -403,6 +436,17 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// * [shape], which defines the shape of the app bar and its shadow. final Color? shadowColor; + /// {@template flutter.material.appbar.surfaceTintColor} + /// The color of the surface tint overlay applied to the app bar's + /// background color to indicate elevation. + /// + /// If null no overlay will be applied. + /// {@endtemplate} + /// + /// See also: + /// * [Material.surfaceTintColor], which described this feature in more detail. + final Color? surfaceTintColor; + /// {@template flutter.material.appbar.shape} /// The shape of the app bar's [Material] as well as its shadow. /// @@ -710,23 +754,24 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// * [SystemChrome.setSystemUIOverlayStyle] final SystemUiOverlayStyle? systemOverlayStyle; - bool _getEffectiveCenterTitle(ThemeData theme) { - if (centerTitle != null) - return centerTitle!; - if (theme.appBarTheme.centerTitle != null) - return theme.appBarTheme.centerTitle!; - assert(theme.platform != null); - switch (theme.platform) { - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: - return false; - case TargetPlatform.iOS: - case TargetPlatform.macOS: - return actions == null || actions!.length < 2; + bool platformCenter() { + assert(theme.platform != null); + switch (theme.platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + return false; + case TargetPlatform.iOS: + case TargetPlatform.macOS: + return actions == null || actions!.length < 2; + } } + + return centerTitle + ?? theme.appBarTheme.centerTitle + ?? platformCenter(); } @override @@ -734,9 +779,6 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { } class _AppBarState extends State { - static const double _defaultElevation = 4.0; - static const Color _defaultShadowColor = Color(0xFF000000); - ScrollNotificationObserverState? _scrollNotificationObserver; bool _scrolledUnder = false; @@ -796,8 +838,8 @@ class _AppBarState extends State { assert(!widget.primary || debugCheckHasMediaQuery(context)); assert(debugCheckHasMaterialLocalizations(context)); final ThemeData theme = Theme.of(context); - final ColorScheme colorScheme = theme.colorScheme; final AppBarTheme appBarTheme = AppBarTheme.of(context); + final AppBarTheme defaults = theme.useMaterial3 ? _TokenDefaultsM3(context) : _DefaultsM2(context); final ScaffoldState? scaffold = Scaffold.maybeOf(context); final ModalRoute? parentRoute = ModalRoute.of(context); @@ -822,12 +864,23 @@ class _AppBarState extends State { states, widget.backgroundColor, appBarTheme.backgroundColor, - colorScheme.brightness == Brightness.dark ? colorScheme.surface : colorScheme.primary, + defaults.backgroundColor!, ); final Color foregroundColor = widget.foregroundColor ?? appBarTheme.foregroundColor - ?? (colorScheme.brightness == Brightness.dark ? colorScheme.onSurface : colorScheme.onPrimary); + ?? defaults.foregroundColor!; + + final double elevation = widget.elevation + ?? appBarTheme.elevation + ?? defaults.elevation!; + + final double effectiveElevation = states.contains(MaterialState.scrolledUnder) + ? widget.scrolledUnderElevation + ?? appBarTheme.scrolledUnderElevation + ?? defaults.scrolledUnderElevation + ?? elevation + : elevation; IconThemeData overallIconTheme = backwardsCompatibility ? widget.iconTheme @@ -835,10 +888,13 @@ class _AppBarState extends State { ?? theme.primaryIconTheme : widget.iconTheme ?? appBarTheme.iconTheme - ?? theme.iconTheme.copyWith(color: foregroundColor); + ?? defaults.iconTheme!.copyWith(color: foregroundColor); IconThemeData actionsIconTheme = widget.actionsIconTheme ?? appBarTheme.actionsIconTheme + ?? widget.iconTheme + ?? appBarTheme.iconTheme + ?? defaults.actionsIconTheme?.copyWith(color: foregroundColor) ?? overallIconTheme; TextStyle? toolbarTextStyle = backwardsCompatibility @@ -847,7 +903,7 @@ class _AppBarState extends State { ?? theme.primaryTextTheme.bodyText2 : widget.toolbarTextStyle ?? appBarTheme.toolbarTextStyle - ?? theme.textTheme.bodyText2?.copyWith(color: foregroundColor); + ?? defaults.toolbarTextStyle?.copyWith(color: foregroundColor); TextStyle? titleTextStyle = backwardsCompatibility ? widget.textTheme?.headline6 @@ -855,7 +911,7 @@ class _AppBarState extends State { ?? theme.primaryTextTheme.headline6 : widget.titleTextStyle ?? appBarTheme.titleTextStyle - ?? theme.textTheme.headline6?.copyWith(color: foregroundColor); + ?? defaults.titleTextStyle?.copyWith(color: foregroundColor); if (widget.toolbarOpacity != 1.0) { final double opacity = const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.toolbarOpacity); @@ -1051,6 +1107,7 @@ class _AppBarState extends State { ) : widget.systemOverlayStyle ?? appBarTheme.systemOverlayStyle + ?? defaults.systemOverlayStyle ?? _systemOverlayStyleForBrightness(ThemeData.estimateBrightnessForColor(backgroundColor)); return Semantics( @@ -1059,13 +1116,14 @@ class _AppBarState extends State { value: overlayStyle, child: Material( color: backgroundColor, - elevation: widget.elevation - ?? appBarTheme.elevation - ?? _defaultElevation, + elevation: effectiveElevation, shadowColor: widget.shadowColor ?? appBarTheme.shadowColor - ?? _defaultShadowColor, - shape: widget.shape ?? appBarTheme.shape, + ?? defaults.shadowColor, + surfaceTintColor: widget.surfaceTintColor + ?? appBarTheme.surfaceTintColor + ?? defaults.surfaceTintColor, + shape: widget.shape ?? appBarTheme.shape ?? defaults.shape, child: Semantics( explicitChildNodes: true, child: appBar, @@ -1085,7 +1143,9 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { required this.flexibleSpace, required this.bottom, required this.elevation, + required this.scrolledUnderElevation, required this.shadowColor, + required this.surfaceTintColor, required this.forceElevated, required this.backgroundColor, required this.foregroundColor, @@ -1127,7 +1187,9 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { final Widget? flexibleSpace; final PreferredSizeWidget? bottom; final double? elevation; + final double? scrolledUnderElevation; final Color? shadowColor; + final Color? surfaceTintColor; final bool forceElevated; final Color? backgroundColor; final Color? foregroundColor; @@ -1202,7 +1264,9 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { : flexibleSpace, bottom: bottom, elevation: forceElevated || isScrolledUnder ? elevation : 0.0, + scrolledUnderElevation: scrolledUnderElevation, shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, backgroundColor: backgroundColor, foregroundColor: foregroundColor, brightness: brightness, @@ -1369,7 +1433,9 @@ class SliverAppBar extends StatefulWidget { this.flexibleSpace, this.bottom, this.elevation, + this.scrolledUnderElevation, this.shadowColor, + this.surfaceTintColor, this.forceElevated = false, this.backgroundColor, this.foregroundColor, @@ -1456,11 +1522,21 @@ class SliverAppBar extends StatefulWidget { /// This property is used to configure an [AppBar]. final double? elevation; + /// {@macro flutter.material.appbar.scrolledUnderElevation} + /// + /// This property is used to configure an [AppBar]. + final double? scrolledUnderElevation; + /// {@macro flutter.material.appbar.shadowColor} /// /// This property is used to configure an [AppBar]. final Color? shadowColor; + /// {@macro flutter.material.appbar.surfaceTintColor} + /// + /// This property is used to configure an [AppBar]. + final Color? surfaceTintColor; + /// Whether to show the shadow appropriate for the [elevation] even if the /// content is not scrolled under the [AppBar]. /// @@ -1762,7 +1838,9 @@ class _SliverAppBarState extends State with TickerProviderStateMix flexibleSpace: widget.flexibleSpace, bottom: widget.bottom, elevation: widget.elevation, + scrolledUnderElevation: widget.scrolledUnderElevation, shadowColor: widget.shadowColor, + surfaceTintColor: widget.surfaceTintColor, forceElevated: widget.forceElevated, backgroundColor: widget.backgroundColor, foregroundColor: widget.foregroundColor, @@ -1835,3 +1913,82 @@ class _RenderAppBarTitleBox extends RenderAligningShiftedBox { alignChild(); } } + +class _DefaultsM2 extends AppBarTheme { + _DefaultsM2(this.context) + : super( + elevation: 4.0, + shadowColor: const Color(0xFF000000), + titleSpacing: NavigationToolbar.kMiddleSpacing, + toolbarHeight: kToolbarHeight, + ); + + final BuildContext context; + late final ThemeData _theme = Theme.of(context); + late final ColorScheme _colors = _theme.colorScheme; + + @override + Color? get backgroundColor => _colors.brightness == Brightness.dark ? _colors.surface : _colors.primary; + + @override + Color? get foregroundColor => _colors.brightness == Brightness.dark ? _colors.onSurface : _colors.onPrimary; + + @override + IconThemeData? get iconTheme => _theme.iconTheme; + + @override + TextStyle? get toolbarTextStyle => _theme.textTheme.bodyText2; + + @override + TextStyle? get titleTextStyle => _theme.textTheme.headline6; +} + +// BEGIN GENERATED TOKEN PROPERTIES + +// Generated code to the end of this file. Do not edit by hand. +// These defaults are generated from the Material Design Token +// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart. + +// Generated version v0_92 +class _TokenDefaultsM3 extends AppBarTheme { + _TokenDefaultsM3(this.context) + : super( + elevation: 0.0, + scrolledUnderElevation: 3.0, + titleSpacing: NavigationToolbar.kMiddleSpacing, + toolbarHeight: 64.0, + ); + + final BuildContext context; + late final ThemeData _theme = Theme.of(context); + late final ColorScheme _colors = _theme.colorScheme; + late final TextTheme _textTheme = _theme.textTheme; + + @override + Color? get backgroundColor => _colors.surface; + + @override + Color? get foregroundColor => _colors.onSurface; + + @override + Color? get surfaceTintColor => _colors.surfaceTint; + + @override + IconThemeData? get iconTheme => IconThemeData( + color: _colors.onSurface, + size: 24.0, + ); + + @override + IconThemeData? get actionsIconTheme => IconThemeData( + color: _colors.onSurfaceVariant, + size: 24.0, + ); + + @override + TextStyle? get toolbarTextStyle => _textTheme.bodyText2; + + @override + TextStyle? get titleTextStyle => _textTheme.titleLarge; +} +// END GENERATED TOKEN PROPERTIES diff --git a/packages/flutter/lib/src/material/app_bar_theme.dart b/packages/flutter/lib/src/material/app_bar_theme.dart index 583e1bd480338..5eb0ff4304903 100644 --- a/packages/flutter/lib/src/material/app_bar_theme.dart +++ b/packages/flutter/lib/src/material/app_bar_theme.dart @@ -37,7 +37,9 @@ class AppBarTheme with Diagnosticable { Color? backgroundColor, this.foregroundColor, this.elevation, + this.scrolledUnderElevation, this.shadowColor, + this.surfaceTintColor, this.shape, this.iconTheme, this.actionsIconTheme, @@ -121,10 +123,18 @@ class AppBarTheme with Diagnosticable { /// descendant [AppBar] widgets. final double? elevation; + /// Overrides the default value of [AppBar.scrolledUnderElevation] in all + /// descendant [AppBar] widgets. + final double? scrolledUnderElevation; + /// Overrides the default value for [AppBar.shadowColor] in all /// descendant widgets. final Color? shadowColor; + /// Overrides the default value for [AppBar.surfaceTintColor] in all + /// descendant widgets. + final Color? surfaceTintColor; + /// Overrides the default value for [AppBar.shape] in all /// descendant widgets. final ShapeBorder? shape; @@ -237,7 +247,9 @@ class AppBarTheme with Diagnosticable { Color? backgroundColor, Color? foregroundColor, double? elevation, + double? scrolledUnderElevation, Color? shadowColor, + Color? surfaceTintColor, ShapeBorder? shape, IconThemeData? iconTheme, @Deprecated( @@ -266,7 +278,9 @@ class AppBarTheme with Diagnosticable { backgroundColor: backgroundColor ?? color ?? this.backgroundColor, foregroundColor: foregroundColor ?? this.foregroundColor, elevation: elevation ?? this.elevation, + scrolledUnderElevation: scrolledUnderElevation ?? this.scrolledUnderElevation, shadowColor: shadowColor ?? this.shadowColor, + surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, shape: shape ?? this.shape, iconTheme: iconTheme ?? this.iconTheme, actionsIconTheme: actionsIconTheme ?? this.actionsIconTheme, @@ -298,7 +312,9 @@ class AppBarTheme with Diagnosticable { backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), foregroundColor: Color.lerp(a?.foregroundColor, b?.foregroundColor, t), elevation: lerpDouble(a?.elevation, b?.elevation, t), + scrolledUnderElevation: lerpDouble(a?.scrolledUnderElevation, b?.scrolledUnderElevation, 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), iconTheme: IconThemeData.lerp(a?.iconTheme, b?.iconTheme, t), actionsIconTheme: IconThemeData.lerp(a?.actionsIconTheme, b?.actionsIconTheme, t), @@ -319,7 +335,9 @@ class AppBarTheme with Diagnosticable { backgroundColor, foregroundColor, elevation, + scrolledUnderElevation, shadowColor, + surfaceTintColor, shape, iconTheme, actionsIconTheme, @@ -344,7 +362,9 @@ class AppBarTheme with Diagnosticable { && other.backgroundColor == backgroundColor && other.foregroundColor == foregroundColor && other.elevation == elevation + && other.scrolledUnderElevation == scrolledUnderElevation && other.shadowColor == shadowColor + && other.surfaceTintColor == surfaceTintColor && other.shape == shape && other.iconTheme == iconTheme && other.actionsIconTheme == actionsIconTheme @@ -365,7 +385,9 @@ class AppBarTheme with Diagnosticable { properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null)); properties.add(ColorProperty('foregroundColor', foregroundColor, defaultValue: null)); properties.add(DiagnosticsProperty('elevation', elevation, defaultValue: null)); + properties.add(DiagnosticsProperty('scrolledUnderElevation', scrolledUnderElevation, 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(DiagnosticsProperty('iconTheme', iconTheme, defaultValue: null)); properties.add(DiagnosticsProperty('actionsIconTheme', actionsIconTheme, defaultValue: null)); diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart index 8b210861db71d..1e0c1dcd235dd 100644 --- a/packages/flutter/lib/src/material/material.dart +++ b/packages/flutter/lib/src/material/material.dart @@ -401,6 +401,9 @@ 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); + // 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( backgroundColor != null || widget.type == MaterialType.transparency, 'If Material type is not MaterialType.transparency, a color must ' @@ -450,9 +453,9 @@ class _MaterialState extends State with TickerProviderStateMixin { duration: widget.animationDuration, shape: BoxShape.rectangle, clipBehavior: widget.clipBehavior, - elevation: widget.elevation, + elevation: modelElevation, color: color, - shadowColor: widget.shadowColor ?? (theme.useMaterial3 ? const Color(0x00000000) : theme.shadowColor), + shadowColor: modelShadowColor ?? const Color(0x00000000), animateColor: false, child: contents, ); @@ -477,7 +480,7 @@ class _MaterialState extends State with TickerProviderStateMixin { clipBehavior: widget.clipBehavior, elevation: widget.elevation, color: backgroundColor!, - shadowColor: widget.shadowColor ?? (theme.useMaterial3 ? const Color(0x00000000) : theme.shadowColor), + shadowColor: modelShadowColor, surfaceTintColor: widget.surfaceTintColor, child: contents, ); @@ -745,7 +748,6 @@ class _MaterialInterior extends ImplicitlyAnimatedWidget { assert(clipBehavior != null), assert(elevation != null && elevation >= 0.0), assert(color != null), - assert(shadowColor != null), super(key: key, curve: curve, duration: duration); /// The widget below this widget in the tree. @@ -780,7 +782,7 @@ class _MaterialInterior extends ImplicitlyAnimatedWidget { final Color color; /// The target shadow color. - final Color shadowColor; + final Color? shadowColor; /// The target surface tint color. final Color? surfaceTintColor; @@ -811,11 +813,13 @@ class _MaterialInteriorState extends AnimatedWidgetBaseState<_MaterialInterior> widget.elevation, (dynamic value) => Tween(begin: value as double), ) as Tween?; - _shadowColor = visitor( - _shadowColor, - widget.shadowColor, - (dynamic value) => ColorTween(begin: value as Color), - ) as ColorTween?; + _shadowColor = widget.shadowColor != null + ? visitor( + _shadowColor, + widget.shadowColor, + (dynamic value) => ColorTween(begin: value as Color), + ) as ColorTween? + : null; _surfaceTintColor = widget.surfaceTintColor != null ? visitor( _surfaceTintColor, @@ -837,15 +841,18 @@ class _MaterialInteriorState extends AnimatedWidgetBaseState<_MaterialInterior> final Color color = Theme.of(context).useMaterial3 ? ElevationOverlay.applySurfaceTint(widget.color, _surfaceTintColor?.evaluate(animation), elevation) : ElevationOverlay.applyOverlay(context, widget.color, elevation); + // If no shadow color is specified, use 0 for elevation in the model so a drop shadow won't be painted. + final double modelElevation = widget.shadowColor != null ? elevation : 0; + final Color shadowColor = _shadowColor?.evaluate(animation) ?? const Color(0x00000000); return PhysicalShape( clipper: ShapeBorderClipper( shape: shape, textDirection: Directionality.maybeOf(context), ), clipBehavior: widget.clipBehavior, - elevation: elevation, + elevation: modelElevation, color: color, - shadowColor: _shadowColor!.evaluate(animation)!, + shadowColor: shadowColor, child: _ShapeBorderPaint( shape: shape, borderOnForeground: widget.borderOnForeground, diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index 95b445a88c303..9f66b1a2c2a2e 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -1257,6 +1257,7 @@ class ThemeData with Diagnosticable { /// Components that have been migrated to Material 3 are: /// /// * [AlertDialog] + /// * [AppBar] /// * [Card] /// * [Dialog] /// * [ElevatedButton] diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index 7a3381110a672..b3431e78d7302 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -235,10 +235,13 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture /// /// See [dart:ui.PlatformDispatcher.onMetricsChanged]. @protected + @visibleForTesting void handleMetricsChanged() { assert(renderView != null); renderView.configuration = createViewConfiguration(); - scheduleForcedFrame(); + if (renderView.child != null) { + scheduleForcedFrame(); + } } /// Called when the platform text scale factor changes. diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 3f78736f692a5..7501f4304d33e 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -955,6 +955,8 @@ void main() { }); testWidgets('AppBar uses the specified elevation or defaults to 4.0', (WidgetTester tester) async { + final bool useMaterial3 = ThemeData().useMaterial3; + Widget buildAppBar([double? elevation]) { return MaterialApp( home: Scaffold( @@ -968,15 +970,48 @@ void main() { matching: find.byType(Material), )); - // Default elevation should be _AppBarState._defaultElevation = 4.0 + // Default elevation should be used for the material. await tester.pumpWidget(buildAppBar()); - expect(getMaterial().elevation, 4.0); + expect(getMaterial().elevation, useMaterial3 ? 0 : 4); // AppBar should use the specified elevation. await tester.pumpWidget(buildAppBar(8.0)); expect(getMaterial().elevation, 8.0); }); + testWidgets('scrolledUnderElevation', (WidgetTester tester) async { + Widget buildAppBar({double? elevation, double? scrolledUnderElevation}) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Title'), + elevation: elevation, + scrolledUnderElevation: scrolledUnderElevation, + ), + body: ListView.builder( + itemCount: 100, + itemBuilder: (BuildContext context, int index) => ListTile(title: Text('Item $index')), + ), + ), + ); + } + + Material getMaterial() => tester.widget(find.descendant( + of: find.byType(AppBar), + matching: find.byType(Material), + )); + + await tester.pumpWidget(buildAppBar(elevation: 2, scrolledUnderElevation: 10)); + // Starts with the base elevation. + expect(getMaterial().elevation, 2); + + await tester.fling(find.text('Item 2'), const Offset(0.0, -600.0), 2000.0); + await tester.pumpAndSettle(); + + // After scrolling it should be the scrolledUnderElevation. + expect(getMaterial().elevation, 10); + }); + group('SliverAppBar elevation', () { Widget buildSliverAppBar(bool forceElevated, {double? elevation, double? themeElevation}) { return MaterialApp( @@ -997,15 +1032,16 @@ void main() { // Regression test for https://github.com/flutter/flutter/issues/59158. AppBar getAppBar() => tester.widget(find.byType(AppBar)); Material getMaterial() => tester.widget(find.byType(Material)); + final bool useMaterial3 = ThemeData().useMaterial3; // When forceElevated is off, SliverAppBar should not be elevated. await tester.pumpWidget(buildSliverAppBar(false)); expect(getMaterial().elevation, 0.0); - // Default elevation should be _AppBarState._defaultElevation = 4.0, and + // Default elevation should be used by the material, but // the AppBar's elevation should not be specified by SliverAppBar. await tester.pumpWidget(buildSliverAppBar(true)); - expect(getMaterial().elevation, 4.0); + expect(getMaterial().elevation, useMaterial3 ? 0.0 : 4.0); expect(getAppBar().elevation, null); // SliverAppBar should use the specified elevation. @@ -1313,6 +1349,8 @@ void main() { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( + // Test was designed against InkSplash so need to make sure that is used. + theme: ThemeData(splashFactory: InkSplash.splashFactory), home: Center( child: AppBar( title: const Text('Abc'), @@ -2006,44 +2044,55 @@ void main() { )); }); - testWidgets('AppBar draws a light system bar for a light theme with a dark background', (WidgetTester tester) async { - final ThemeData lightTheme = ThemeData(primarySwatch: Colors.deepOrange); - await tester.pumpWidget(MaterialApp( - theme: lightTheme, - home: Scaffold( - appBar: AppBar( - title: const Text('test'), + testWidgets('Default system bar brightness based on AppBar background color brightness.', (WidgetTester tester) async { + Widget buildAppBar(ThemeData theme) { + return MaterialApp( + theme: theme, + home: Scaffold( + appBar: AppBar(title: const Text('Title')), ), - ), - )); - - expect(lightTheme.primaryColorBrightness, Brightness.dark); - expect(lightTheme.colorScheme.brightness, Brightness.light); - expect(SystemChrome.latestStyle, const SystemUiOverlayStyle( - statusBarBrightness: Brightness.dark, - statusBarIconBrightness: Brightness.light, - )); - }); + ); + } - testWidgets('AppBar draws a dark system bar for a dark theme with a light background', (WidgetTester tester) async { - final ThemeData darkTheme = ThemeData(brightness: Brightness.dark, cardColor: Colors.white); - await tester.pumpWidget( - MaterialApp( - theme: darkTheme, - home: Scaffold( - appBar: AppBar( - title: const Text('test'), - ), + // Using a light theme. + { + await tester.pumpWidget(buildAppBar(ThemeData.from(colorScheme: const ColorScheme.light()))); + final Material appBarMaterial = tester.widget( + find.descendant( + of: find.byType(AppBar), + matching: find.byType(Material), ), - ), - ); + ); + final Brightness appBarBrightness = ThemeData.estimateBrightnessForColor(appBarMaterial.color!); + final Brightness onAppBarBrightness = appBarBrightness == Brightness.light + ? Brightness.dark + : Brightness.light; + + expect(SystemChrome.latestStyle, SystemUiOverlayStyle( + statusBarBrightness: appBarBrightness, + statusBarIconBrightness: onAppBarBrightness, + )); + } - expect(darkTheme.primaryColorBrightness, Brightness.dark); - expect(darkTheme.colorScheme.brightness, Brightness.dark); - expect(SystemChrome.latestStyle, const SystemUiOverlayStyle( - statusBarBrightness: Brightness.light, - statusBarIconBrightness: Brightness.dark, - )); + // Using a dark theme. + { + await tester.pumpWidget(buildAppBar(ThemeData.from(colorScheme: const ColorScheme.dark()))); + final Material appBarMaterial = tester.widget( + find.descendant( + of: find.byType(AppBar), + matching: find.byType(Material), + ), + ); + final Brightness appBarBrightness = ThemeData.estimateBrightnessForColor(appBarMaterial.color!); + final Brightness onAppBarBrightness = appBarBrightness == Brightness.light + ? Brightness.dark + : Brightness.light; + + expect(SystemChrome.latestStyle, SystemUiOverlayStyle( + statusBarBrightness: appBarBrightness, + statusBarIconBrightness: onAppBarBrightness, + )); + } }); testWidgets('Changing SliverAppBar snap from true to false', (WidgetTester tester) async { @@ -2208,6 +2257,8 @@ void main() { Widget buildFrame() { return MaterialApp( + // Test designed against 2014 font sizes. + theme: ThemeData(textTheme: Typography.englishLike2014), home: Builder( builder: (BuildContext context) { return MediaQuery( @@ -2246,6 +2297,8 @@ void main() { Widget buildFrame() { return MaterialApp( + // Test designed against 2014 font sizes. + theme: ThemeData(textTheme: Typography.englishLike2014), home: Builder( builder: (BuildContext context) { return Directionality( @@ -2537,6 +2590,7 @@ void main() { await tester.pumpWidget( MaterialApp( theme: ThemeData.light().copyWith( + useMaterial3: false, appBarTheme: const AppBarTheme( backwardsCompatibility: false, ), diff --git a/packages/flutter/test/material/app_bar_theme_test.dart b/packages/flutter/test/material/app_bar_theme_test.dart index 171dbe5594136..856ccd2da02fe 100644 --- a/packages/flutter/test/material/app_bar_theme_test.dart +++ b/packages/flutter/test/material/app_bar_theme_test.dart @@ -15,8 +15,10 @@ void main() { }); testWidgets('Passing no AppBarTheme returns defaults', (WidgetTester tester) async { + final ThemeData theme = ThemeData(); await tester.pumpWidget( MaterialApp( + theme: theme, home: Scaffold( appBar: AppBar( actions: [ @@ -33,17 +35,33 @@ void main() { final RichText actionIconText = _getAppBarIconRichText(tester); final DefaultTextStyle text = _getAppBarText(tester); - expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); - expect(widget.color, Colors.blue); - expect(widget.elevation, 4.0); - expect(widget.shadowColor, Colors.black); - expect(widget.shape, null); - expect(iconTheme.data, const IconThemeData(color: Colors.white)); - expect(actionsIconTheme.data, const IconThemeData(color: Colors.white)); - expect(actionIconText.text.style!.color, Colors.white); - expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().white.bodyText2)); - expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); - expect(tester.getSize(find.byType(AppBar)).width, 800); + if (theme.useMaterial3) { + expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); + expect(widget.color, theme.colorScheme.surface); + expect(widget.elevation, 0); + expect(widget.shadowColor, null); + expect(widget.surfaceTintColor, theme.colorScheme.surfaceTint); + expect(widget.shape, null); + expect(iconTheme.data, IconThemeData(color: theme.colorScheme.onSurface, size: 24)); + expect(actionsIconTheme.data, IconThemeData(color: theme.colorScheme.onSurfaceVariant, size: 24)); + expect(actionIconText.text.style!.color, Colors.black); + expect(text.style, Typography.material2021().englishLike.bodyText2!.merge(Typography.material2021().black.bodyText2).copyWith(color: theme.colorScheme.onSurface)); + expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); + expect(tester.getSize(find.byType(AppBar)).width, 800); + } else { + expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); + expect(widget.color, Colors.blue); + expect(widget.elevation, 4.0); + expect(widget.shadowColor, Colors.black); + expect(widget.surfaceTintColor, null); + expect(widget.shape, null); + expect(iconTheme.data, const IconThemeData(color: Colors.white)); + expect(actionsIconTheme.data, const IconThemeData(color: Colors.white)); + expect(actionIconText.text.style!.color, Colors.white); + expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().white.bodyText2)); + expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); + expect(tester.getSize(find.byType(AppBar)).width, 800); + } }); testWidgets('AppBar uses values from AppBarTheme', (WidgetTester tester) async { @@ -73,6 +91,7 @@ void main() { expect(widget.color, appBarTheme.backgroundColor); expect(widget.elevation, appBarTheme.elevation); expect(widget.shadowColor, appBarTheme.shadowColor); + expect(widget.surfaceTintColor, appBarTheme.surfaceTintColor); expect(widget.shape, const StadiumBorder()); expect(iconTheme.data, appBarTheme.iconTheme); expect(actionsIconTheme.data, appBarTheme.actionsIconTheme); @@ -132,7 +151,8 @@ void main() { const SystemUiOverlayStyle systemOverlayStyle = SystemUiOverlayStyle.light; const Color color = Colors.orange; const double elevation = 3.0; - const Color shadowColor = Colors.red; + const Color shadowColor = Colors.purple; + const Color surfaceTintColor = Colors.brown; const ShapeBorder shape = RoundedRectangleBorder(); const IconThemeData iconThemeData = IconThemeData(color: Colors.green); const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue); @@ -151,6 +171,7 @@ void main() { systemOverlayStyle: systemOverlayStyle, elevation: elevation, shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, shape: shape, iconTheme: iconThemeData, actionsIconTheme: actionsIconThemeData, @@ -174,6 +195,7 @@ void main() { expect(widget.color, color); expect(widget.elevation, elevation); expect(widget.shadowColor, shadowColor); + expect(widget.surfaceTintColor, surfaceTintColor); expect(widget.shape, shape); expect(iconTheme.data, iconThemeData); expect(actionsIconTheme.data, actionsIconThemeData); @@ -228,6 +250,7 @@ void main() { expect(widget.color, appBarTheme.backgroundColor); expect(widget.elevation, appBarTheme.elevation); expect(widget.shadowColor, appBarTheme.shadowColor); + expect(widget.surfaceTintColor, appBarTheme.surfaceTintColor); expect(iconTheme.data, appBarTheme.iconTheme); expect(actionsIconTheme.data, appBarTheme.actionsIconTheme); expect(actionIconText.text.style!.color, appBarTheme.actionsIconTheme!.color); @@ -235,15 +258,13 @@ void main() { }); testWidgets('ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async { - late ThemeData theme; + final ThemeData lightTheme = ThemeData.from(colorScheme: const ColorScheme.light()); + final ThemeData darkTheme = ThemeData.from(colorScheme: const ColorScheme.dark()); Widget buildFrame(ThemeData appTheme) { return MaterialApp( theme: appTheme, home: Builder( builder: (BuildContext context) { - // This ThemeData has been localized with ThemeData.localize. The - // appTheme parameter has not, so its textTheme is incomplete. - theme = Theme.of(context); return Scaffold( appBar: AppBar( actions: [ @@ -256,57 +277,120 @@ void main() { ); } - // AppBar defaults for light themes: - // - elevation: 4 - // - shadow color: black - // - background color: ColorScheme.primary - // - foreground color: ColorScheme.onPrimary - // - actions text: style bodyText2, foreground color - // - status bar brightness: light (based on color scheme brightness) - { - await tester.pumpWidget(buildFrame(ThemeData.from(colorScheme: const ColorScheme.light()))); - - final Material widget = _getAppBarMaterial(tester); - final IconTheme iconTheme = _getAppBarIconTheme(tester); - final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); - final RichText actionIconText = _getAppBarIconRichText(tester); - final DefaultTextStyle text = _getAppBarText(tester); - - expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); - expect(widget.color, theme.colorScheme.primary); - expect(widget.elevation, 4.0); - expect(widget.shadowColor, Colors.black); - expect(iconTheme.data.color, theme.colorScheme.onPrimary); - expect(actionsIconTheme.data.color, theme.colorScheme.onPrimary); - expect(actionIconText.text.style!.color, theme.colorScheme.onPrimary); - expect(text.style.compareTo(theme.textTheme.bodyText2!.copyWith(color: theme.colorScheme.onPrimary)), RenderComparison.identical); - } - - // AppBar defaults for dark themes: - // - elevation: 4 - // - shadow color: black - // - background color: ColorScheme.surface - // - foreground color: ColorScheme.onSurface - // - actions text: style bodyText2, foreground color - // - status bar brightness: dark (based on background color) - { - await tester.pumpWidget(buildFrame(ThemeData.from(colorScheme: const ColorScheme.dark()))); - await tester.pumpAndSettle(); // Theme change animation - - final Material widget = _getAppBarMaterial(tester); - final IconTheme iconTheme = _getAppBarIconTheme(tester); - final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); - final RichText actionIconText = _getAppBarIconRichText(tester); - final DefaultTextStyle text = _getAppBarText(tester); - - expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); - expect(widget.color, theme.colorScheme.surface); - expect(widget.elevation, 4.0); - expect(widget.shadowColor, Colors.black); - expect(iconTheme.data.color, theme.colorScheme.onSurface); - expect(actionsIconTheme.data.color, theme.colorScheme.onSurface); - expect(actionIconText.text.style!.color, theme.colorScheme.onSurface); - expect(text.style.compareTo(theme.textTheme.bodyText2!.copyWith(color: theme.colorScheme.onSurface)), RenderComparison.identical); + if (lightTheme.useMaterial3) { + // M3 AppBar defaults for light themes: + // - elevation: 0 + // - shadow color: null + // - surface tint color: ColorScheme.surfaceTint + // - background color: ColorScheme.surface + // - foreground color: ColorScheme.onSurface + // - actions text: style bodyText2, foreground color + // - status bar brightness: light (based on color scheme brightness) + { + await tester.pumpWidget(buildFrame(lightTheme)); + + final Material widget = _getAppBarMaterial(tester); + final IconTheme iconTheme = _getAppBarIconTheme(tester); + final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); + final RichText actionIconText = _getAppBarIconRichText(tester); + final DefaultTextStyle text = _getAppBarText(tester); + + expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); + expect(widget.color, lightTheme.colorScheme.surface); + expect(widget.elevation, 0); + expect(widget.shadowColor, null); + expect(widget.surfaceTintColor, lightTheme.colorScheme.surfaceTint); + expect(iconTheme.data.color, lightTheme.colorScheme.onSurface); + expect(actionsIconTheme.data.color, lightTheme.colorScheme.onSurface); + expect(actionIconText.text.style!.color, lightTheme.colorScheme.onSurface); + expect(text.style, Typography.material2021().englishLike.bodyText2!.merge(Typography.material2021().black.bodyText2).copyWith(color: lightTheme.colorScheme.onSurface)); + } + + // M3 AppBar defaults for dark themes: + // - elevation: 0 + // - shadow color: null + // - surface tint color: ColorScheme.surfaceTint + // - background color: ColorScheme.surface + // - foreground color: ColorScheme.onSurface + // - actions text: style bodyText2, foreground color + // - status bar brightness: dark (based on background color) + { + await tester.pumpWidget(buildFrame(ThemeData.from(colorScheme: const ColorScheme.dark()))); + await tester.pumpAndSettle(); // Theme change animation + + final Material widget = _getAppBarMaterial(tester); + final IconTheme iconTheme = _getAppBarIconTheme(tester); + final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); + final RichText actionIconText = _getAppBarIconRichText(tester); + final DefaultTextStyle text = _getAppBarText(tester); + + expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.dark); + expect(widget.color, darkTheme.colorScheme.surface); + expect(widget.elevation, 0); + expect(widget.shadowColor, null); + expect(widget.surfaceTintColor, darkTheme.colorScheme.surfaceTint); + expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); + expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); + expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); + expect(text.style, Typography.material2021().englishLike.bodyText2!.merge(Typography.material2021().black.bodyText2).copyWith(color: darkTheme.colorScheme.onSurface)); + } + } else { + // AppBar defaults for light themes: + // - elevation: 4 + // - shadow color: black + // - surface tint color: null + // - background color: ColorScheme.primary + // - foreground color: ColorScheme.onPrimary + // - actions text: style bodyText2, foreground color + // - status bar brightness: light (based on color scheme brightness) + { + await tester.pumpWidget(buildFrame(lightTheme)); + + final Material widget = _getAppBarMaterial(tester); + final IconTheme iconTheme = _getAppBarIconTheme(tester); + final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); + final RichText actionIconText = _getAppBarIconRichText(tester); + final DefaultTextStyle text = _getAppBarText(tester); + + expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); + expect(widget.color, lightTheme.colorScheme.primary); + expect(widget.elevation, 4.0); + expect(widget.shadowColor, Colors.black); + expect(widget.surfaceTintColor, null); + expect(iconTheme.data.color, lightTheme.colorScheme.onPrimary); + expect(actionsIconTheme.data.color, lightTheme.colorScheme.onPrimary); + expect(actionIconText.text.style!.color, lightTheme.colorScheme.onPrimary); + expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2).copyWith(color: lightTheme.colorScheme.onPrimary)); + } + + // AppBar defaults for dark themes: + // - elevation: 4 + // - shadow color: black + // - surface tint color: null + // - background color: ColorScheme.surface + // - foreground color: ColorScheme.onSurface + // - actions text: style bodyText2, foreground color + // - status bar brightness: dark (based on background color) + { + await tester.pumpWidget(buildFrame(darkTheme)); + await tester.pumpAndSettle(); // Theme change animation + + final Material widget = _getAppBarMaterial(tester); + final IconTheme iconTheme = _getAppBarIconTheme(tester); + final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); + final RichText actionIconText = _getAppBarIconRichText(tester); + final DefaultTextStyle text = _getAppBarText(tester); + + expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); + expect(widget.color, darkTheme.colorScheme.surface); + expect(widget.elevation, 4.0); + expect(widget.shadowColor, Colors.black); + expect(widget.surfaceTintColor, null); + expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); + expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); + expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); + expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2).copyWith(color: darkTheme.colorScheme.onSurface)); + } } }); @@ -315,7 +399,7 @@ void main() { Widget buildFrame({ Color? appIconColor, Color? appBarIconColor }) { return MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light()), + theme: ThemeData.from(useMaterial3: false, colorScheme: const ColorScheme.light()), home: IconTheme( data: IconThemeData(color: appIconColor), child: Builder( @@ -408,6 +492,22 @@ void main() { expect(appBar.shadowColor, Colors.yellow); }); + testWidgets('AppBar.surfaceTintColor takes priority over AppBarTheme.surfaceTintColor', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(appBarTheme: const AppBarTheme(surfaceTintColor: Colors.red)), + home: Scaffold( + appBar: AppBar( + title: const Text('Title'), + surfaceTintColor: Colors.yellow, + ), + ), + )); + + final AppBar appBar = tester.widget(find.byType(AppBar)); + // The AppBar.surfaceTintColor should be used instead of AppBarTheme.surfaceTintColor. + expect(appBar.surfaceTintColor, Colors.yellow); + }); + testWidgets('AppBar uses AppBarTheme.titleSpacing', (WidgetTester tester) async { const double kTitleSpacing = 10; await tester.pumpWidget(MaterialApp( @@ -493,6 +593,7 @@ void main() { backgroundColor: Color(0xff000001), elevation: 8.0, shadowColor: Color(0xff000002), + surfaceTintColor: Color(0xff000003), centerTitle: true, titleSpacing: 40.0, ).debugFillProperties(builder); @@ -507,6 +608,7 @@ void main() { 'backgroundColor: Color(0xff000001)', 'elevation: 8.0', 'shadowColor: Color(0xff000002)', + 'surfaceTintColor: Color(0xff000003)', 'centerTitle: true', 'titleSpacing: 40.0', ]); @@ -524,6 +626,7 @@ AppBarTheme _appBarTheme() { const Color backgroundColor = Colors.lightBlue; const double elevation = 6.0; const Color shadowColor = Colors.red; + const Color surfaceTintColor = Colors.green; const IconThemeData iconThemeData = IconThemeData(color: Colors.black); const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.pink); return const AppBarTheme( @@ -532,6 +635,7 @@ AppBarTheme _appBarTheme() { backgroundColor: backgroundColor, elevation: elevation, shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, shape: StadiumBorder(), iconTheme: iconThemeData, toolbarHeight: 96, diff --git a/packages/flutter/test/rendering/binding_test.dart b/packages/flutter/test/rendering/binding_test.dart new file mode 100644 index 0000000000000..c10df12b05f41 --- /dev/null +++ b/packages/flutter/test/rendering/binding_test.dart @@ -0,0 +1,22 @@ +// 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 'package:flutter/rendering.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + + test('handleMetricsChanged does not scheduleForcedFrame unless there is a child to the renderView', () async { + expect(SchedulerBinding.instance.hasScheduledFrame, false); + RendererBinding.instance.handleMetricsChanged(); + expect(SchedulerBinding.instance.hasScheduledFrame, false); + + RendererBinding.instance.renderView.child = RenderLimitedBox(); + RendererBinding.instance.handleMetricsChanged(); + expect(SchedulerBinding.instance.hasScheduledFrame, true); + }); +} diff --git a/packages/flutter_tools/lib/src/web/flutter_js.dart b/packages/flutter_tools/lib/src/web/flutter_js.dart index dfff8270d3db9..af8950b1bcf19 100644 --- a/packages/flutter_tools/lib/src/web/flutter_js.dart +++ b/packages/flutter_tools/lib/src/web/flutter_js.dart @@ -31,7 +31,7 @@ _flutter.loader = null; // we support. In the meantime, we use the "revealing module" pattern. // Watchdog to prevent injecting the main entrypoint multiple times. - _scriptLoaded = false; + _scriptLoaded = null; // Resolver for the pending promise returned by loadEntrypoint. _didCreateEngineInitializerResolve = null; @@ -61,31 +61,38 @@ _flutter.loader = null; console.warn("Do not call didCreateEngineInitializer by hand. Start with loadEntrypoint instead."); } this._didCreateEngineInitializerResolve(engineInitializer); + // Remove this method after it's done, so Flutter Web can hot restart. + delete this.didCreateEngineInitializer; }).bind(this); _loadEntrypoint(entrypointUrl) { - if (this._scriptLoaded) { - return null; + if (!this._scriptLoaded) { + this._scriptLoaded = new Promise((resolve, reject) => { + let scriptTag = document.createElement("script"); + scriptTag.src = entrypointUrl; + scriptTag.type = "application/javascript"; + this._didCreateEngineInitializerResolve = resolve; // Cache the resolve, so it can be called from Flutter. + scriptTag.addEventListener("error", reject); + document.body.append(scriptTag); + }); } - this._scriptLoaded = true; - - return new Promise((resolve, reject) => { - let scriptTag = document.createElement("script"); - scriptTag.src = entrypointUrl; - scriptTag.type = "application/javascript"; - this._didCreateEngineInitializerResolve = resolve; // Cache the resolve, so it can be called from Flutter. - scriptTag.addEventListener("error", reject); - document.body.append(scriptTag); - }); + return this._scriptLoaded; } _waitForServiceWorkerActivation(serviceWorker, entrypointUrl) { - if (!serviceWorker) return; + if (!serviceWorker || serviceWorker.state == "activated") { + if (!serviceWorker) { + console.warn("Cannot activate a null service worker. Falling back to plain