From 0d7ff7a9e7c6f10fe929376bbd9685e3efb3c626 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Fri, 19 Jun 2020 10:52:52 -0700 Subject: [PATCH] Revert "Deprecate WhitelistingTextInputFormatter and BlacklistingTextInputFormatter (#59120)" (#59870) This reverts commit 8665e13801fe6b53a0e67866d2ee6cd5ef2083f4. --- analysis_options.yaml | 3 - dev/bots/analyze.dart | 11 +- .../root/packages/foo/deprecation.dart | 38 +-- dev/bots/test/analyze_test.dart | 7 +- .../demo/material/text_form_field_demo.dart | 2 +- .../flutter/lib/src/cupertino/nav_bar.dart | 6 +- packages/flutter/lib/src/material/dialog.dart | 5 + .../lib/src/material/input_decorator.dart | 20 +- .../pickers/calendar_date_range_picker.dart | 6 +- .../pickers/date_picker_deprecated.dart | 6 +- .../material/pickers/date_picker_header.dart | 2 +- .../lib/src/material/pickers/date_utils.dart | 3 +- .../material/pickers/input_date_picker.dart | 12 +- .../pickers/input_date_range_picker.dart | 6 +- .../lib/src/material/pickers/pickers.dart | 6 - .../flutter/lib/src/material/scaffold.dart | 1 + .../flutter/lib/src/material/text_theme.dart | 4 + .../lib/src/services/asset_bundle.dart | 2 +- .../lib/src/services/platform_channel.dart | 6 +- .../lib/src/services/text_formatter.dart | 273 +++++------------- packages/flutter/lib/src/widgets/basic.dart | 6 +- .../lib/src/widgets/editable_text.dart | 2 +- .../test/material/input_decorator_test.dart | 3 + .../test/material/text_field_test.dart | 109 +------ .../test/services/text_formatter_test.dart | 144 --------- .../widgets/listener_deprecated_test.dart | 4 + .../test/widgets/text_formatter_test.dart | 111 +------ .../lib/src/extension/extension.dart | 12 +- .../test/src/real_tests/extension_test.dart | 10 +- 29 files changed, 158 insertions(+), 662 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 9990dcbd07e55..213bf942ac900 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -29,9 +29,6 @@ analyzer: missing_return: warning # allow having TODOs in the code todo: ignore - # allow self-reference to deprecated members (we do this because otherwise we have - # to annotate every member in every test, assert, etc, when we deprecate something) - deprecated_member_use_from_same_package: ignore # Ignore analyzer hints for updating pubspecs when using Future or # Stream and not importing dart:async # Please see https://github.com/flutter/flutter/pull/24528 for details. diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart index d4c788b4259a2..b0e93534deaff 100644 --- a/dev/bots/analyze.dart +++ b/dev/bots/analyze.dart @@ -135,7 +135,7 @@ Future run(List arguments) async { final RegExp _findDeprecationPattern = RegExp(r'@[Dd]eprecated'); final RegExp _deprecationPattern1 = RegExp(r'^( *)@Deprecated\($'); // ignore: flutter_deprecation_syntax (see analyze.dart) final RegExp _deprecationPattern2 = RegExp(r"^ *'(.+) '$"); -final RegExp _deprecationPattern3 = RegExp(r"^ *'This feature was deprecated after v([0-9]+)\.([0-9]+)\.([0-9]+)(\-[0-9]+\.[0-9]+\.pre)?\.'$"); +final RegExp _deprecationPattern3 = RegExp(r"^ *'This feature was deprecated after v([0-9]+)\.([0-9]+)\.([0-9]+)\.'$"); final RegExp _deprecationPattern4 = RegExp(r'^ *\)$'); /// Some deprecation notices are special, for example they're used to annotate members that @@ -182,7 +182,7 @@ Future verifyDeprecations(String workingDirectory, { int minimumMatches = if (message == null) { final String firstChar = String.fromCharCode(match2[1].runes.first); if (firstChar.toUpperCase() != firstChar) - throw 'Deprecation notice should be a grammatically correct sentence and start with a capital letter; see style guide: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo'; + throw 'Deprecation notice should be a grammatically correct sentence and start with a capital letter; see style guide.'; } message = match2[1]; lineNumber += 1; @@ -190,13 +190,6 @@ Future verifyDeprecations(String workingDirectory, { int minimumMatches = throw 'Incomplete deprecation notice.'; match3 = _deprecationPattern3.firstMatch(lines[lineNumber]); } while (match3 == null); - final int v1 = int.parse(match3[1]); - final int v2 = int.parse(match3[2]); - final bool hasV4 = match3[4] != null; - if (v1 > 1 || (v1 == 1 && v2 >= 20)) { - if (!hasV4) - throw 'Deprecation notice does not accurately indicate a dev branch version number; please see https://flutter.dev/docs/development/tools/sdk/releases to find the latest dev build version number.'; - } if (!message.endsWith('.') && !message.endsWith('!') && !message.endsWith('?')) throw 'Deprecation notice should be a grammatically correct sentence and end with a period.'; if (!lines[lineNumber].startsWith("$indent '")) diff --git a/dev/bots/test/analyze-test-input/root/packages/foo/deprecation.dart b/dev/bots/test/analyze-test-input/root/packages/foo/deprecation.dart index b430a0a3693d1..aad90fbaa0694 100644 --- a/dev/bots/test/analyze-test-input/root/packages/foo/deprecation.dart +++ b/dev/bots/test/analyze-test-input/root/packages/foo/deprecation.dart @@ -55,42 +55,6 @@ void test10() { } @Deprecated( 'URLs are not required. ' - 'This feature was deprecated after v1.0.0.' + 'This feature was deprecated after v2.0.0.' ) void test11() { } - -@Deprecated( - 'Version number test (should fail). ' - 'This feature was deprecated after v1.19.0.' -) -void test12() { } - -@Deprecated( - 'Version number test (should fail). ' - 'This feature was deprecated after v1.20.0.' -) -void test13() { } - -@Deprecated( - 'Version number test (should fail). ' - 'This feature was deprecated after v1.21.0.' -) -void test14() { } - -@Deprecated( - 'Version number test (should fail). ' - 'This feature was deprecated after v3.1.0.' -) -void test15() { } - -@Deprecated( - 'Version number test (should be fine). ' - 'This feature was deprecated after v0.1.0.' -) -void test16() { } - -@Deprecated( - 'Version number test (should be fine). ' - 'This feature was deprecated after v1.20.0-1.0.pre.' -) -void test17() { } diff --git a/dev/bots/test/analyze_test.dart b/dev/bots/test/analyze_test.dart index d3799b39db6b8..faba5bb0503cf 100644 --- a/dev/bots/test/analyze_test.dart +++ b/dev/bots/test/analyze_test.dart @@ -41,7 +41,7 @@ void main() { + ( 'test/analyze-test-input/root/packages/foo/deprecation.dart:12: Deprecation notice does not match required pattern.\n' - 'test/analyze-test-input/root/packages/foo/deprecation.dart:18: Deprecation notice should be a grammatically correct sentence and start with a capital letter; see style guide: STYLE_GUIDE_URL\n' + 'test/analyze-test-input/root/packages/foo/deprecation.dart:18: Deprecation notice should be a grammatically correct sentence and start with a capital letter; see style guide.\n' 'test/analyze-test-input/root/packages/foo/deprecation.dart:25: Deprecation notice should be a grammatically correct sentence and end with a period.\n' 'test/analyze-test-input/root/packages/foo/deprecation.dart:29: Deprecation notice does not match required pattern.\n' 'test/analyze-test-input/root/packages/foo/deprecation.dart:32: Deprecation notice does not match required pattern.\n' @@ -49,12 +49,7 @@ void main() { 'test/analyze-test-input/root/packages/foo/deprecation.dart:41: Deprecation notice does not match required pattern.\n' 'test/analyze-test-input/root/packages/foo/deprecation.dart:48: End of deprecation notice does not match required pattern.\n' 'test/analyze-test-input/root/packages/foo/deprecation.dart:51: Unexpected deprecation notice indent.\n' - 'test/analyze-test-input/root/packages/foo/deprecation.dart:70: Deprecation notice does not accurately indicate a dev branch version number; please see RELEASES_URL to find the latest dev build version number.\n' - 'test/analyze-test-input/root/packages/foo/deprecation.dart:76: Deprecation notice does not accurately indicate a dev branch version number; please see RELEASES_URL to find the latest dev build version number.\n' - 'test/analyze-test-input/root/packages/foo/deprecation.dart:82: Deprecation notice does not accurately indicate a dev branch version number; please see RELEASES_URL to find the latest dev build version number.\n' .replaceAll('/', Platform.isWindows ? r'\' : '/') - .replaceAll('STYLE_GUIDE_URL', 'https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo') - .replaceAll('RELEASES_URL', 'https://flutter.dev/docs/development/tools/sdk/releases') ) + 'See: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes\n' diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart index 1dbeccaa4aa8e..cd87f74534fe8 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart @@ -217,7 +217,7 @@ class TextFormFieldDemoState extends State { validator: _validatePhoneNumber, // TextInputFormatters are applied in sequence. inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, + WhitelistingTextInputFormatter.digitsOnly, // Fit the validating format. _phoneNumberFormatter, ], diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart index 2e98b17c6b332..b6c5a4ea756c1 100644 --- a/packages/flutter/lib/src/cupertino/nav_bar.dart +++ b/packages/flutter/lib/src/cupertino/nav_bar.dart @@ -463,7 +463,7 @@ class _CupertinoNavigationBarState extends State { ); final Color actionsForegroundColor = CupertinoDynamicColor.resolve( - widget.actionsForegroundColor, + widget.actionsForegroundColor, // ignore: deprecated_member_use_from_same_package context, ); if (!widget.transitionBetweenRoutes || !_isTransitionable(context)) { @@ -694,8 +694,8 @@ class _CupertinoSliverNavigationBarState extends State with TickerProviderStat final bool labelIsInitiallyFloating = widget.decoration.floatingLabelBehavior == FloatingLabelBehavior.always || (widget.decoration.floatingLabelBehavior != FloatingLabelBehavior.never && + // ignore: deprecated_member_use_from_same_package widget.decoration.hasFloatingPlaceholder && widget._labelShouldWithdraw); @@ -1975,6 +1976,7 @@ class _InputDecoratorState extends State with TickerProviderStat bool get isHovering => widget.isHovering && decoration.enabled; bool get isEmpty => widget.isEmpty; bool get _floatingLabelEnabled { + // ignore: deprecated_member_use_from_same_package return decoration.hasFloatingPlaceholder && decoration.floatingLabelBehavior != FloatingLabelBehavior.never; } @@ -1985,6 +1987,7 @@ class _InputDecoratorState extends State with TickerProviderStat _effectiveDecoration = null; final bool floatBehaviorChanged = widget.decoration.floatingLabelBehavior != old.decoration.floatingLabelBehavior + // ignore: deprecated_member_use_from_same_package || widget.decoration.hasFloatingPlaceholder != old.decoration.hasFloatingPlaceholder; if (widget._labelShouldWithdraw != old._labelShouldWithdraw || floatBehaviorChanged) { @@ -2517,7 +2520,7 @@ class InputDecoration { 'Use floatingLabelBehavior instead. ' 'This feature was deprecated after v1.13.2.' ) - this.hasFloatingPlaceholder = true, + this.hasFloatingPlaceholder = true, // ignore: deprecated_member_use_from_same_package this.floatingLabelBehavior = FloatingLabelBehavior.auto, this.isCollapsed = false, this.isDense, @@ -2563,6 +2566,7 @@ class InputDecoration { 'Use floatingLabelBehavior instead. ' 'This feature was deprecated after v1.13.2.' ) + // ignore: deprecated_member_use_from_same_package this.hasFloatingPlaceholder = true, this.floatingLabelBehavior = FloatingLabelBehavior.auto, this.hintStyle, @@ -2573,8 +2577,9 @@ class InputDecoration { this.border = InputBorder.none, this.enabled = true, }) : assert(enabled != null), + // ignore: deprecated_member_use_from_same_package assert(!(!hasFloatingPlaceholder && identical(floatingLabelBehavior, FloatingLabelBehavior.always)), - 'hasFloatingPlaceholder=false conflicts with FloatingLabelBehavior.always'), + 'hasFloatingPlaceholder=false conflicts with FloatingLabelBehavior.always'), icon = null, labelText = null, labelStyle = null, @@ -3367,6 +3372,7 @@ class InputDecoration { errorText: errorText ?? this.errorText, errorStyle: errorStyle ?? this.errorStyle, errorMaxLines: errorMaxLines ?? this.errorMaxLines, + // ignore: deprecated_member_use_from_same_package hasFloatingPlaceholder: hasFloatingPlaceholder ?? this.hasFloatingPlaceholder, floatingLabelBehavior: floatingLabelBehavior ?? this.floatingLabelBehavior, isCollapsed: isCollapsed ?? this.isCollapsed, @@ -3414,6 +3420,7 @@ class InputDecoration { hintStyle: hintStyle ?? theme.hintStyle, errorStyle: errorStyle ?? theme.errorStyle, errorMaxLines: errorMaxLines ?? theme.errorMaxLines, + // ignore: deprecated_member_use_from_same_package hasFloatingPlaceholder: hasFloatingPlaceholder ?? theme.hasFloatingPlaceholder, floatingLabelBehavior: floatingLabelBehavior ?? theme.floatingLabelBehavior, isCollapsed: isCollapsed ?? theme.isCollapsed, @@ -3455,6 +3462,7 @@ class InputDecoration { && other.errorText == errorText && other.errorStyle == errorStyle && other.errorMaxLines == errorMaxLines + // ignore: deprecated_member_use_from_same_package && other.hasFloatingPlaceholder == hasFloatingPlaceholder && other.floatingLabelBehavior == floatingLabelBehavior && other.isDense == isDense @@ -3503,7 +3511,7 @@ class InputDecoration { errorText, errorStyle, errorMaxLines, - hasFloatingPlaceholder, + hasFloatingPlaceholder,// ignore: deprecated_member_use_from_same_package floatingLabelBehavior, isDense, contentPadding, @@ -3552,6 +3560,7 @@ class InputDecoration { if (errorText != null) 'errorText: "$errorText"', if (errorStyle != null) 'errorStyle: "$errorStyle"', if (errorMaxLines != null) 'errorMaxLines: "$errorMaxLines"', + // ignore: deprecated_member_use_from_same_package if (hasFloatingPlaceholder == false) 'hasFloatingPlaceholder: false', if (floatingLabelBehavior != null) 'floatingLabelBehavior: $floatingLabelBehavior', if (isDense ?? false) 'isDense: $isDense', @@ -3615,6 +3624,7 @@ class InputDecorationTheme with Diagnosticable { 'Use floatingLabelBehavior instead. ' 'This feature was deprecated after v1.13.2.' ) + // ignore: deprecated_member_use_from_same_package this.hasFloatingPlaceholder = true, this.floatingLabelBehavior = FloatingLabelBehavior.auto, this.isDense = false, @@ -3638,6 +3648,7 @@ class InputDecorationTheme with Diagnosticable { assert(isCollapsed != null), assert(filled != null), assert(alignLabelWithHint != null), + // ignore: deprecated_member_use_from_same_package assert(!(!hasFloatingPlaceholder && identical(floatingLabelBehavior, FloatingLabelBehavior.always)), 'hasFloatingPlaceholder=false conflicts with FloatingLabelBehavior.always'); @@ -3990,6 +4001,7 @@ class InputDecorationTheme with Diagnosticable { hintStyle: hintStyle ?? this.hintStyle, errorStyle: errorStyle ?? this.errorStyle, errorMaxLines: errorMaxLines ?? this.errorMaxLines, + // ignore: deprecated_member_use_from_same_package hasFloatingPlaceholder: hasFloatingPlaceholder ?? this.hasFloatingPlaceholder, floatingLabelBehavior: floatingLabelBehavior ?? this.floatingLabelBehavior, isDense: isDense ?? this.isDense, @@ -4021,6 +4033,7 @@ class InputDecorationTheme with Diagnosticable { hintStyle, errorStyle, errorMaxLines, + // ignore: deprecated_member_use_from_same_package hasFloatingPlaceholder, floatingLabelBehavior, isDense, @@ -4087,6 +4100,7 @@ class InputDecorationTheme with Diagnosticable { properties.add(DiagnosticsProperty('hintStyle', hintStyle, defaultValue: defaultTheme.hintStyle)); properties.add(DiagnosticsProperty('errorStyle', errorStyle, defaultValue: defaultTheme.errorStyle)); properties.add(IntProperty('errorMaxLines', errorMaxLines, defaultValue: defaultTheme.errorMaxLines)); + // ignore: deprecated_member_use_from_same_package properties.add(DiagnosticsProperty('hasFloatingPlaceholder', hasFloatingPlaceholder, defaultValue: defaultTheme.hasFloatingPlaceholder)); properties.add(DiagnosticsProperty('floatingLabelBehavior', floatingLabelBehavior, defaultValue: defaultTheme.floatingLabelBehavior)); properties.add(DiagnosticsProperty('isDense', isDense, defaultValue: defaultTheme.isDense)); diff --git a/packages/flutter/lib/src/material/pickers/calendar_date_range_picker.dart b/packages/flutter/lib/src/material/pickers/calendar_date_range_picker.dart index bb018b5be3dcf..01ef1aa4ea4b7 100644 --- a/packages/flutter/lib/src/material/pickers/calendar_date_range_picker.dart +++ b/packages/flutter/lib/src/material/pickers/calendar_date_range_picker.dart @@ -29,9 +29,9 @@ const double _maxCalendarWidthPortrait = 480.0; /// Displays a scrollable calendar grid that allows a user to select a range /// of dates. -// -// This is not publicly exported (see pickers.dart), as it is an -// internal component used by [showDateRangePicker]. +/// +/// Note: this is not publicly exported (see pickers.dart), as it is an +/// internal component used by [showDateRangePicker]. class CalendarDateRangePicker extends StatefulWidget { /// Creates a scrollable calendar grid for picking date ranges. CalendarDateRangePicker({ diff --git a/packages/flutter/lib/src/material/pickers/date_picker_deprecated.dart b/packages/flutter/lib/src/material/pickers/date_picker_deprecated.dart index c8e4e151f889b..e7831a0f8c48d 100644 --- a/packages/flutter/lib/src/material/pickers/date_picker_deprecated.dart +++ b/packages/flutter/lib/src/material/pickers/date_picker_deprecated.dart @@ -21,7 +21,7 @@ import '../theme.dart'; import 'date_picker_common.dart'; -// This is the original implementation for the Material Date Picker. +// NOTE: this is the original implementation for the Material Date Picker. // These classes are deprecated and the whole file can be removed after // this has been on stable for long enough for people to migrate to the new // CalendarDatePicker (if needed, as showDatePicker has already been migrated @@ -406,6 +406,7 @@ class MonthPicker extends StatefulWidget { _MonthPickerState createState() => _MonthPickerState(); } +// ignore: deprecated_member_use_from_same_package class _MonthPickerState extends State with SingleTickerProviderStateMixin { static final Animatable _chevronOpacityTween = Tween(begin: 1.0, end: 0.0) .chain(CurveTween(curve: Curves.easeInOut)); @@ -427,6 +428,7 @@ class _MonthPickerState extends State with SingleTickerProviderStat } @override + // ignore: deprecated_member_use_from_same_package void didUpdateWidget(MonthPicker oldWidget) { super.didUpdateWidget(oldWidget); if (widget.selectedDate != oldWidget.selectedDate) { @@ -477,6 +479,7 @@ class _MonthPickerState extends State with SingleTickerProviderStat Widget _buildItems(BuildContext context, int index) { final DateTime month = _addMonthsToMonthDate(widget.firstDate, index); + // ignore: deprecated_member_use_from_same_package return DayPicker( key: ValueKey(month), selectedDate: widget.selectedDate, @@ -672,6 +675,7 @@ class YearPicker extends StatefulWidget { _YearPickerState createState() => _YearPickerState(); } +// ignore: deprecated_member_use_from_same_package class _YearPickerState extends State { static const double _itemExtent = 50.0; ScrollController scrollController; diff --git a/packages/flutter/lib/src/material/pickers/date_picker_header.dart b/packages/flutter/lib/src/material/pickers/date_picker_header.dart index 2409ac9c07b42..8cd2878ab7d1f 100644 --- a/packages/flutter/lib/src/material/pickers/date_picker_header.dart +++ b/packages/flutter/lib/src/material/pickers/date_picker_header.dart @@ -12,7 +12,7 @@ import '../material.dart'; import '../text_theme.dart'; import '../theme.dart'; -// This is an internal implementation file. Even though there are public +// NOTE: This is an internal implementation file. Even though there are public // classes and functions defined here, they are only meant to be used by the // date picker implementation and are not exported as part of the Material library. // See pickers.dart for exactly what is considered part of the public API. diff --git a/packages/flutter/lib/src/material/pickers/date_utils.dart b/packages/flutter/lib/src/material/pickers/date_utils.dart index ef90c0431d900..eb2447b09c212 100644 --- a/packages/flutter/lib/src/material/pickers/date_utils.dart +++ b/packages/flutter/lib/src/material/pickers/date_utils.dart @@ -4,9 +4,10 @@ // @dart = 2.8 + // Common date utility functions used by the date picker implementation -// This is an internal implementation file. Even though there are public +// NOTE: This is an internal implementation file. Even though there are public // classes and functions defined here, they are only meant to be used by the // date picker implementation and are not exported as part of the Material library. // See pickers.dart for exactly what is considered part of the public API. diff --git a/packages/flutter/lib/src/material/pickers/input_date_picker.dart b/packages/flutter/lib/src/material/pickers/input_date_picker.dart index dda971425157a..ce936830a29e4 100644 --- a/packages/flutter/lib/src/material/pickers/input_date_picker.dart +++ b/packages/flutter/lib/src/material/pickers/input_date_picker.dart @@ -244,16 +244,16 @@ class _InputDatePickerFormFieldState extends State { } /// A `TextInputFormatter` set up to format dates. -// -// This is not publicly exported (see pickers.dart), as it is -// just meant for internal use by `InputDatePickerFormField` and -// `InputDateRangePicker`. +/// +/// Note: this is not publicly exported (see pickers.dart), as it is +/// just meant for internal use by `InputDatePickerFormField` and +/// `InputDateRangePicker`. class DateTextInputFormatter extends TextInputFormatter { /// Creates a date formatter with the given separator. DateTextInputFormatter( this.separator - ) : _filterFormatter = FilteringTextInputFormatter.allow(RegExp('[\\d$_commonSeparators\\$separator]+')); + ) : _filterFormatter = WhitelistingTextInputFormatter(RegExp('[\\d$_commonSeparators\\$separator]+')); /// List of common separators that are used in dates. This is used to make /// sure that if given platform's [TextInputType.datetime] keyboard doesn't @@ -267,7 +267,7 @@ class DateTextInputFormatter extends TextInputFormatter { // Formatter that will filter out all characters except digits and date // separators. - final TextInputFormatter _filterFormatter; + final WhitelistingTextInputFormatter _filterFormatter; @override TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { diff --git a/packages/flutter/lib/src/material/pickers/input_date_range_picker.dart b/packages/flutter/lib/src/material/pickers/input_date_range_picker.dart index 60297333abe97..abfa7fa79c9ee 100644 --- a/packages/flutter/lib/src/material/pickers/input_date_range_picker.dart +++ b/packages/flutter/lib/src/material/pickers/input_date_range_picker.dart @@ -18,9 +18,9 @@ import 'input_date_picker.dart' show DateTextInputFormatter; /// Provides a pair of text fields that allow the user to enter the start and /// end dates that represent a range of dates. -// -// This is not publicly exported (see pickers.dart), as it is just an -// internal component used by [showDateRangePicker]. +/// +/// Note: this is not publicly exported (see pickers.dart), as it is just an +/// internal component used by [showDateRangePicker]. class InputDateRangePicker extends StatefulWidget { /// Creates a row with two text fields configured to accept the start and end dates /// of a date range. diff --git a/packages/flutter/lib/src/material/pickers/pickers.dart b/packages/flutter/lib/src/material/pickers/pickers.dart index 60bb88307baf6..7dca95ffec142 100644 --- a/packages/flutter/lib/src/material/pickers/pickers.dart +++ b/packages/flutter/lib/src/material/pickers/pickers.dart @@ -15,9 +15,3 @@ export 'date_picker_deprecated.dart'; export 'date_picker_dialog.dart' show showDatePicker; export 'date_range_picker_dialog.dart' show showDateRangePicker; export 'input_date_picker.dart' show InputDatePickerFormField; - -// TODO(ianh): Not exporting everything is unusual and we should -// probably change to just exporting everything and making sure it's -// acceptable as a public API, or, worst case, merging the parts -// that really must be public into a single file and make them -// actually private. diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index 2027edd08eb79..2d0c7f303b455 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -2092,6 +2092,7 @@ class ScaffoldState extends State with TickerProviderStateMixin { // Backwards compatibility for deprecated resizeToAvoidBottomPadding property bool get _resizeToAvoidBottomInset { + // ignore: deprecated_member_use_from_same_package return widget.resizeToAvoidBottomInset ?? widget.resizeToAvoidBottomPadding ?? true; } diff --git a/packages/flutter/lib/src/material/text_theme.dart b/packages/flutter/lib/src/material/text_theme.dart index f82bb62003a3b..37b104c83547f 100644 --- a/packages/flutter/lib/src/material/text_theme.dart +++ b/packages/flutter/lib/src/material/text_theme.dart @@ -9,6 +9,10 @@ import 'package:flutter/painting.dart'; import 'typography.dart'; +// Eventually we'll get rid of the deprecated members, but for now, we have to use them +// in order to implement them. +// ignore_for_file: deprecated_member_use_from_same_package + /// Material design text theme. /// /// Definitions for the various typographical styles found in Material Design diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart index 461f88612489b..5242445146a85 100644 --- a/packages/flutter/lib/src/services/asset_bundle.dart +++ b/packages/flutter/lib/src/services/asset_bundle.dart @@ -218,7 +218,7 @@ class PlatformAssetBundle extends CachingAssetBundle { Future load(String key) async { final Uint8List encoded = utf8.encoder.convert(Uri(path: Uri.encodeFull(key)).path); final ByteData asset = - await defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData()); + await defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData()); // ignore: deprecated_member_use_from_same_package if (asset == null) throw FlutterError('Unable to load asset: $key'); return asset; diff --git a/packages/flutter/lib/src/services/platform_channel.dart b/packages/flutter/lib/src/services/platform_channel.dart index 74cfe701b86a6..cb23d29b5025c 100644 --- a/packages/flutter/lib/src/services/platform_channel.dart +++ b/packages/flutter/lib/src/services/platform_channel.dart @@ -48,7 +48,7 @@ class BasicMessageChannel { final MessageCodec codec; /// The messenger which sends the bytes for this channel, not null. - BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger; + BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger; // ignore: deprecated_member_use_from_same_package final BinaryMessenger _binaryMessenger; /// Sends the specified [message] to the platform plugins on this channel. @@ -142,7 +142,7 @@ class MethodChannel { /// The messenger used by this channel to send platform messages. /// /// The messenger may not be null. - BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger; + BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger; // ignore: deprecated_member_use_from_same_package final BinaryMessenger _binaryMessenger; @optionalTypeArgs @@ -506,7 +506,7 @@ class EventChannel { final MethodCodec codec; /// The messenger used by this channel to send platform messages, not null. - BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger; + BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger; // ignore: deprecated_member_use_from_same_package final BinaryMessenger _binaryMessenger; /// Sets up a broadcast stream for receiving events on this channel. diff --git a/packages/flutter/lib/src/services/text_formatter.dart b/packages/flutter/lib/src/services/text_formatter.dart index 7bcc6ebb44619..766f9f68449cf 100644 --- a/packages/flutter/lib/src/services/text_formatter.dart +++ b/packages/flutter/lib/src/services/text_formatter.dart @@ -6,8 +6,7 @@ import 'dart:math' as math; -import 'package:flutter/foundation.dart'; - +import 'package:flutter/foundation.dart' show visibleForTesting; import 'text_editing.dart'; import 'text_input.dart'; @@ -18,9 +17,10 @@ import 'text_input.dart'; /// IME and not on text under composition (i.e., only when /// [TextEditingValue.composing] is collapsed). /// -/// See also the [FilteringTextInputFormatter], a subclass that -/// removes characters that the user tries to enter if they do, or do -/// not, match a given pattern (as applicable). +/// Concrete implementations [BlacklistingTextInputFormatter], which removes +/// blacklisted characters upon edit commit, and +/// [WhitelistingTextInputFormatter], which only allows entries of whitelisted +/// characters, are provided. /// /// To create custom formatters, extend the [TextInputFormatter] class and /// implement the [formatEditUpdate] method. @@ -28,7 +28,9 @@ import 'text_input.dart'; /// See also: /// /// * [EditableText] on which the formatting apply. -/// * [FilteringTextInputFormatter], a provided formatter for filtering +/// * [BlacklistingTextInputFormatter], a provided formatter for blacklisting +/// characters. +/// * [WhitelistingTextInputFormatter], a provided formatter for whitelisting /// characters. abstract class TextInputFormatter { /// Called when text is being typed or cut/copy/pasted in the [EditableText]. @@ -75,140 +77,34 @@ class _SimpleTextInputFormatter extends TextInputFormatter { } } -/// A [TextInputFormatter] that prevents the insertion of characters -/// matching (or not matching) a particular pattern. +/// A [TextInputFormatter] that prevents the insertion of blacklisted +/// characters patterns. /// -/// Instances of filtered characters found in the new [TextEditingValue]s +/// Instances of blacklisted characters found in the new [TextEditingValue]s /// will be replaced with the [replacementString] which defaults to the empty /// string. /// /// Since this formatter only removes characters from the text, it attempts to /// preserve the existing [TextEditingValue.selection] to values it would now /// fall at with the removed characters. -class FilteringTextInputFormatter extends TextInputFormatter { - /// Creates a formatter that prevents the insertion of characters - /// based on a filter pattern. - /// - /// If [allow] is true, then the filter pattern is an allow list, - /// and characters must match the pattern to be accepted. See also - /// [new FilteringTextInputFormatter.allow]. - /// - /// If [allow] is false, then the filter pattern is a deny list, - /// and characters that match the pattern are rejected. See also - /// [new FilteringTextInputFormatter.deny]. - /// - /// The [filterPattern], [allow], and [replacementString] arguments - /// must not be null. - FilteringTextInputFormatter( - this.filterPattern, { - @required this.allow, - this.replacementString = '', - }) : assert(filterPattern != null), - assert(allow != null), - assert(replacementString != null); - - /// Creates a formatter that only allows characters matching a pattern. +/// +/// See also: +/// +/// * [WhitelistingTextInputFormatter], which uses a whitelist instead of a +/// blacklist. +class BlacklistingTextInputFormatter extends TextInputFormatter { + /// Creates a formatter that prevents the insertion of blacklisted characters patterns. /// - /// The [filterPattern] and [replacementString] arguments - /// must not be null. - FilteringTextInputFormatter.allow( - this.filterPattern, { + /// The [blacklistedPattern] must not be null. + BlacklistingTextInputFormatter( + this.blacklistedPattern, { this.replacementString = '', - }) : assert(filterPattern != null), - assert(replacementString != null), - allow = true; + }) : assert(blacklistedPattern != null); - /// Creates a formatter that blocks characters matching a pattern. - /// - /// The [filterPattern] and [replacementString] arguments - /// must not be null. - FilteringTextInputFormatter.deny( - this.filterPattern, { - this.replacementString = '', - }) : assert(filterPattern != null), - assert(replacementString != null), - allow = false; + /// A [Pattern] to match and replace incoming [TextEditingValue]s. + final Pattern blacklistedPattern; - /// A [Pattern] to match and replace in incoming [TextEditingValue]s. - /// - /// The behaviour of the pattern depends on the [allow] property. If - /// it is true, then this is an allow list, specifying a pattern that - /// characters must match to be accepted. Otherwise, it is a deny list, - /// specifying a pattern that characters must not match to be accepted. - /// - /// In general, the pattern should only match one character at a - /// time. See the discussion at [replacementString]. - /// - /// {@tool snippet} - /// Typically the pattern is a regular expression, as in: - /// - /// ```dart - /// var onlyDigits = FilteringTextInputFormatter.allow(RegExp(r'[0-9]')); - /// ``` - /// {@end-tool} - /// - /// {@tool snippet} - /// If the pattern is a single character, a pattern consisting of a - /// [String] can be used: - /// - /// ```dart - /// var noTabs = FilteringTextInputFormatter.deny('\t'); - /// ``` - /// {@end-tool} - final Pattern filterPattern; - - /// Whether the pattern is an allow list or not. - /// - /// When true, [filterPattern] denotes an allow list: characters - /// must match the filter to be allowed. - /// - /// When false, [filterPattern] denotes a deny list: characters - /// that match the filter are disallowed. - final bool allow; - - /// String used to replace banned patterns. - /// - /// For deny lists ([allow] is false), each match of the - /// [filterPattern] is replaced with this string. If [filterPattern] - /// can match more than one character at a time, then this can - /// result in multiple characters being replaced by a single - /// instance of this [replacementString]. - /// - /// For allow lists ([allow] is true), sequences between matches of - /// [filterPattern] are replaced as one, regardless of the number of - /// characters. - /// - /// For example, consider a [filterPattern] consisting of just the - /// letter "o", applied to text field whose initial value is the - /// string "Into The Woods", with the [replacementString] set to - /// `*`. - /// - /// If [allow] is true, then the result will be "*o*oo*". Each - /// sequence of characters not matching the pattern is replaced by - /// its own single copy of the replacement string, regardless of how - /// many characters are in that sequence. - /// - /// If [allow] is false, then the result will be "Int* the W**ds". - /// Every matching sequence is replaced, and each "o" matches the - /// pattern separately. - /// - /// If the pattern was the [RegExp] `o+`, the result would be the - /// same in the case where [allow] is true, but in the case where - /// [allow] is false, the result would be "Int* the W*ds" (with the - /// two "o"s replaced by a single occurrence of the replacement - /// string) because both of the "o"s would be matched simultaneously - /// by the pattern. - /// - /// Additionally, each segment of the string before, during, and - /// after the current selection in the [TextEditingValue] is handled - /// separately. This means that, in the case of the "Into the Woods" - /// example above, if the selection ended between the two "o"s in - /// "Woods", even if the pattern was `RegExp('o+')`, the result - /// would be "Int* the W**ds", since the two "o"s would be handled - /// in separate passes. - /// - /// See also [String.splitMapJoin], which is used to implement this - /// behavior in both cases. + /// String used to replace found patterns. final String replacementString; @override @@ -219,87 +115,16 @@ class FilteringTextInputFormatter extends TextInputFormatter { return _selectionAwareTextManipulation( newValue, (String substring) { - return substring.splitMapJoin( - filterPattern, - onMatch: !allow ? (Match match) => replacementString : null, - onNonMatch: allow ? (String nonMatch) => nonMatch.isNotEmpty ? replacementString : '' : null, - ); + return substring.replaceAll(blacklistedPattern, replacementString); }, ); } - /// A [TextInputFormatter] that forces input to be a single line. - static final TextInputFormatter singleLineFormatter = FilteringTextInputFormatter.deny('\n'); - - /// A [TextInputFormatter] that takes in digits `[0-9]` only. - static final TextInputFormatter digitsOnly = FilteringTextInputFormatter.allow(RegExp(r'[0-9]')); -} - -/// Old name for [FilteringTextInputFormatter.deny]. -@Deprecated( - 'Use FilteringTextInputFormatter.deny instead. ' - 'This feature was deprecated after v1.20.0-1.0.pre.' -) -class BlacklistingTextInputFormatter extends FilteringTextInputFormatter { - /// Old name for [FilteringTextInputFormatter.deny]. - @Deprecated( - 'Use FilteringTextInputFormatter.deny instead. ' - 'This feature was deprecated after v1.20.0-1.0.pre.' - ) - BlacklistingTextInputFormatter( - Pattern blacklistedPattern, { - String replacementString = '', - }) : super.deny(blacklistedPattern, replacementString: replacementString); - - /// Old name for [filterPattern]. - @Deprecated( - 'Use filterPattern instead. ' - 'This feature was deprecated after v1.20.0-1.0.pre.' - ) - Pattern get blacklistedPattern => filterPattern; - - /// Old name for [FilteringTextInputFormatter.singleLineFormatter]. - @Deprecated( - 'Use FilteringTextInputFormatter.singleLineFormatter instead. ' - 'This feature was deprecated after v1.20.0-1.0.pre.' - ) + /// A [BlacklistingTextInputFormatter] that forces input to be a single line. static final BlacklistingTextInputFormatter singleLineFormatter = BlacklistingTextInputFormatter(RegExp(r'\n')); } -/// Old name for [FilteringTextInputFormatter.allow]. -// TODO(ianh): Deprecate these once the samples are migrated. -// at-Deprecated( -// 'Use FilteringTextInputFormatter.allow instead. ' -// 'This feature was deprecated after v1.20.0-1.0.pre.' -// ) -class WhitelistingTextInputFormatter extends FilteringTextInputFormatter { - /// Old name for [FilteringTextInputFormatter.allow]. - @Deprecated( - 'Use FilteringTextInputFormatter.allow instead. ' - 'This feature was deprecated after v1.20.0-1.0.pre.' - ) - WhitelistingTextInputFormatter(Pattern whitelistedPattern) - : assert(whitelistedPattern != null), - super.allow(whitelistedPattern); - - /// Old name for [filterPattern]. - @Deprecated( - 'Use filterPattern instead. ' - 'This feature was deprecated after v1.20.0-1.0.pre.' - ) - Pattern get whitelistedPattern => filterPattern; - - /// Old name for [FilteringTextInputFormatter.digitsOnly]. - // TODO(ianh): Deprecate these once the samples are migrated. - // at-Deprecated( - // 'Use FilteringTextInputFormatter.digitsOnly instead. ' - // 'This feature was deprecated after v1.20.0-1.0.pre.' - // ) - static final WhitelistingTextInputFormatter digitsOnly - = WhitelistingTextInputFormatter(RegExp(r'\d+')); -} - /// A [TextInputFormatter] that prevents the insertion of more characters /// (currently defined as Unicode scalar values) than allowed. /// @@ -391,6 +216,50 @@ class LengthLimitingTextInputFormatter extends TextInputFormatter { } } +/// A [TextInputFormatter] that allows only the insertion of whitelisted +/// characters patterns. +/// +/// Since this formatter only removes characters from the text, it attempts to +/// preserve the existing [TextEditingValue.selection] to values it would now +/// fall at with the removed characters. +/// +/// See also: +/// +/// * [BlacklistingTextInputFormatter], which uses a blacklist instead of a +/// whitelist. +class WhitelistingTextInputFormatter extends TextInputFormatter { + /// Creates a formatter that allows only the insertion of whitelisted characters patterns. + /// + /// The [whitelistedPattern] must not be null. + WhitelistingTextInputFormatter(this.whitelistedPattern) + : assert(whitelistedPattern != null); + + /// A [Pattern] to extract all instances of allowed characters. + /// + /// [RegExp] with multiple groups is not supported. + final Pattern whitelistedPattern; + + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, // unused. + TextEditingValue newValue, + ) { + return _selectionAwareTextManipulation( + newValue, + (String substring) { + return whitelistedPattern + .allMatches(substring) + .map((Match match) => match.group(0)) + .join(); + } , + ); + } + + /// A [WhitelistingTextInputFormatter] that takes in digits `[0-9]` only. + static final WhitelistingTextInputFormatter digitsOnly + = WhitelistingTextInputFormatter(RegExp(r'\d+')); +} + TextEditingValue _selectionAwareTextManipulation( TextEditingValue value, String substringManipulation(String substring), diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 66577bc78a0a9..0d091fdda6a04 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -5709,17 +5709,17 @@ class Listener extends StatelessWidget { 'Use MouseRegion.onEnter instead. See MouseRegion.opaque for behavioral difference. ' 'This feature was deprecated after v1.10.14.' ) - this.onPointerEnter, + this.onPointerEnter, // ignore: deprecated_member_use_from_same_package @Deprecated( 'Use MouseRegion.onExit instead. See MouseRegion.opaque for behavioral difference. ' 'This feature was deprecated after v1.10.14.' ) - this.onPointerExit, + this.onPointerExit, // ignore: deprecated_member_use_from_same_package @Deprecated( 'Use MouseRegion.onHover instead. See MouseRegion.opaque for behavioral difference. ' 'This feature was deprecated after v1.10.14.' ) - this.onPointerHover, + this.onPointerHover, // ignore: deprecated_member_use_from_same_package this.onPointerUp, this.onPointerCancel, this.onPointerSignal, diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 42e7e7f193516..2c632fdbfece3 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -460,7 +460,7 @@ class EditableText extends StatefulWidget { keyboardType = keyboardType ?? _inferKeyboardType(autofillHints: autofillHints, maxLines: maxLines), inputFormatters = maxLines == 1 ? [ - FilteringTextInputFormatter.singleLineFormatter, + BlacklistingTextInputFormatter.singleLineFormatter, ...inputFormatters ?? const Iterable.empty(), ] : inputFormatters, diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index 7070ee4c72c56..14f3bb8fd1b49 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -2846,6 +2846,7 @@ void main() { isEmpty: true, decoration: const InputDecoration( border: OutlineInputBorder(borderSide: BorderSide.none), + // ignore: deprecated_member_use_from_same_package hasFloatingPlaceholder: false, labelText: 'label', ), @@ -2870,6 +2871,7 @@ void main() { // isFocused: false (default) decoration: const InputDecoration( border: OutlineInputBorder(borderSide: BorderSide.none), + // ignore: deprecated_member_use_from_same_package hasFloatingPlaceholder: false, labelText: 'label', ), @@ -3939,6 +3941,7 @@ void main() { helperMaxLines: 6, hintStyle: TextStyle(), errorMaxLines: 5, + // ignore: deprecated_member_use_from_same_package hasFloatingPlaceholder: false, floatingLabelBehavior: FloatingLabelBehavior.never, contentPadding: EdgeInsetsDirectional.only(start: 40.0, top: 12.0, bottom: 12.0), diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index affc8e1c67ccb..78c11fa377c8a 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -3157,27 +3157,6 @@ void main() { testWidgets('Injected formatters are chained', (WidgetTester tester) async { final TextEditingController textController = TextEditingController(); - await tester.pumpWidget(boilerplate( - child: TextField( - controller: textController, - decoration: null, - inputFormatters: [ - FilteringTextInputFormatter.deny( - RegExp(r'[a-z]'), - replacementString: '#', - ), - ], - ), - )); - - await tester.enterText(find.byType(TextField), 'a一b二c三\nd四e五f六'); - // The default single line formatter replaces \n with empty string. - expect(textController.text, '#一#二#三#四#五#六'); - }); - - testWidgets('Injected formatters are chained (deprecated names)', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); - await tester.pumpWidget(boilerplate( child: TextField( controller: textController, @@ -3199,33 +3178,6 @@ void main() { testWidgets('Chained formatters are in sequence', (WidgetTester tester) async { final TextEditingController textController = TextEditingController(); - await tester.pumpWidget(boilerplate( - child: TextField( - controller: textController, - decoration: null, - maxLines: 2, - inputFormatters: [ - FilteringTextInputFormatter.deny( - RegExp(r'[a-z]'), - replacementString: '12\n', - ), - FilteringTextInputFormatter.allow(RegExp(r'\n[0-9]')), - ], - ), - )); - - await tester.enterText(find.byType(TextField), 'a1b2c3'); - // The first formatter turns it into - // 12\n112\n212\n3 - // The second formatter turns it into - // \n1\n2\n3 - // Multiline is allowed since maxLine != 1. - expect(textController.text, '\n1\n2\n3'); - }); - - testWidgets('Chained formatters are in sequence (deprecated names)', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); - await tester.pumpWidget(boilerplate( child: TextField( controller: textController, @@ -3253,44 +3205,6 @@ void main() { testWidgets('Pasted values are formatted', (WidgetTester tester) async { final TextEditingController textController = TextEditingController(); - await tester.pumpWidget( - overlay( - child: TextField( - controller: textController, - decoration: null, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, - ], - ), - ), - ); - - await tester.enterText(find.byType(TextField), 'a1b\n2c3'); - expect(textController.text, '123'); - await skipPastScrollingAnimation(tester); - - await tester.tapAt(textOffsetToPosition(tester, '123'.indexOf('2'))); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero - final RenderEditable renderEditable = findRenderEditable(tester); - final List endpoints = globalize( - renderEditable.getEndpointsForSelection(textController.selection), - renderEditable, - ); - await tester.tapAt(endpoints[0].point + const Offset(1.0, 1.0)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero - - Clipboard.setData(const ClipboardData(text: '一4二\n5三6')); - await tester.tap(find.text('PASTE')); - await tester.pump(); - // Puts 456 before the 2 in 123. - expect(textController.text, '145623'); - }); - - testWidgets('Pasted values are formatted (deprecated names)', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); - await tester.pumpWidget( overlay( child: TextField( @@ -3559,28 +3473,7 @@ void main() { expect(textController.text, '0123456789'); }); - testWidgets('maxLength still works with other formatters', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); - - await tester.pumpWidget(boilerplate( - child: TextField( - controller: textController, - maxLength: 10, - inputFormatters: [ - FilteringTextInputFormatter.deny( - RegExp(r'[a-z]'), - replacementString: '#', - ), - ], - ), - )); - - await tester.enterText(find.byType(TextField), 'a一b二c三\nd四e五f六'); - // The default single line formatter replaces \n with empty string. - expect(textController.text, '#一#二#三#四#五'); - }); - - testWidgets('maxLength still works with other formatters (deprecated names)', (WidgetTester tester) async { + testWidgets('maxLength still works with other formatters.', (WidgetTester tester) async { final TextEditingController textController = TextEditingController(); await tester.pumpWidget(boilerplate( diff --git a/packages/flutter/test/services/text_formatter_test.dart b/packages/flutter/test/services/text_formatter_test.dart index dcbb9e7614f00..e90966fb7cdf5 100644 --- a/packages/flutter/test/services/text_formatter_test.dart +++ b/packages/flutter/test/services/text_formatter_test.dart @@ -86,148 +86,4 @@ void main() { }); }); }); - - test('FilteringTextInputFormatter should return the old value if new value contains non-white-listed character', () { - const TextEditingValue oldValue = TextEditingValue(text: '12345'); - const TextEditingValue newValue = TextEditingValue(text: '12345@'); - - final TextInputFormatter formatter = FilteringTextInputFormatter.digitsOnly; - final TextEditingValue formatted = formatter.formatEditUpdate(oldValue, newValue); - - // assert that we are passing digits only at the first time - expect(oldValue.text, equals('12345')); - // The new value is always the oldValue plus a non-digit character (user press @) - expect(newValue.text, equals('12345@')); - // we expect that the formatted value returns the oldValue only since the newValue does not - // satisfy the formatter condition (which is, in this case, digitsOnly) - expect(formatted.text, equals('12345')); - }); - - test('FilteringTextInputFormatter should move the cursor to the right position', () { - TextEditingValue collapsedValue(String text, int offset) => - TextEditingValue( - text: text, - selection: TextSelection.collapsed(offset: offset), - ); - - TextEditingValue oldValue = collapsedValue('123', 0); - TextEditingValue newValue = collapsedValue('123456', 6); - - final TextInputFormatter formatter = FilteringTextInputFormatter.digitsOnly; - TextEditingValue formatted = formatter.formatEditUpdate(oldValue, newValue); - - // assert that we are passing digits only at the first time - expect(oldValue.text, equals('123')); - // assert that we are passing digits only at the second time - expect(newValue.text, equals('123456')); - // assert that cursor is at the end of the text - expect(formatted.selection.baseOffset, equals(6)); - - // move cursor at the middle of the text and then add the number 9. - oldValue = newValue.copyWith(selection: const TextSelection.collapsed(offset: 4)); - newValue = oldValue.copyWith(text: '1239456'); - - formatted = formatter.formatEditUpdate(oldValue, newValue); - - // cursor must be now at fourth position (right after the number 9) - expect(formatted.selection.baseOffset, equals(4)); - }); - - test('FilteringTextInputFormatter should remove non-allowed characters', () { - const TextEditingValue oldValue = TextEditingValue(text: '12345'); - const TextEditingValue newValue = TextEditingValue(text: '12345@'); - - final TextInputFormatter formatter = FilteringTextInputFormatter.digitsOnly; - final TextEditingValue formatted = formatter.formatEditUpdate(oldValue, newValue); - - // assert that we are passing digits only at the first time - expect(oldValue.text, equals('12345')); - // The new value is always the oldValue plus a non-digit character (user press @) - expect(newValue.text, equals('12345@')); - // we expect that the formatted value returns the oldValue only since the difference - // between the oldValue and the newValue is only material that isn't allowed - expect(formatted.text, equals('12345')); - }); - - test('WhitelistingTextInputFormatter should return the old value if new value contains non-allowed character', () { - const TextEditingValue oldValue = TextEditingValue(text: '12345'); - const TextEditingValue newValue = TextEditingValue(text: '12345@'); - - final WhitelistingTextInputFormatter formatter = WhitelistingTextInputFormatter.digitsOnly; - final TextEditingValue formatted = formatter.formatEditUpdate(oldValue, newValue); - - // assert that we are passing digits only at the first time - expect(oldValue.text, equals('12345')); - // The new value is always the oldValue plus a non-digit character (user press @) - expect(newValue.text, equals('12345@')); - // we expect that the formatted value returns the oldValue only since the newValue does not - // satisfy the formatter condition (which is, in this case, digitsOnly) - expect(formatted.text, equals('12345')); - }); - - test('FilteringTextInputFormatter should move the cursor to the right position', () { - TextEditingValue collapsedValue(String text, int offset) => - TextEditingValue( - text: text, - selection: TextSelection.collapsed(offset: offset), - ); - - TextEditingValue oldValue = collapsedValue('123', 0); - TextEditingValue newValue = collapsedValue('123456', 6); - - final TextInputFormatter formatter = - FilteringTextInputFormatter.digitsOnly; - TextEditingValue formatted = formatter.formatEditUpdate(oldValue, - newValue); - - // assert that we are passing digits only at the first time - expect(oldValue.text, equals('123')); - // assert that we are passing digits only at the second time - expect(newValue.text, equals('123456')); - // assert that cursor is at the end of the text - expect(formatted.selection.baseOffset, equals(6)); - - // move cursor at the middle of the text and then add the number 9. - oldValue = newValue.copyWith( - selection: const TextSelection.collapsed(offset: 4)); - newValue = oldValue.copyWith(text: '1239456'); - - formatted = formatter.formatEditUpdate(oldValue, newValue); - - // cursor must be now at fourth position (right after the number 9) - expect(formatted.selection.baseOffset, equals(4)); - }); - - test('WhitelistingTextInputFormatter should move the cursor to the right position', () { - TextEditingValue collapsedValue(String text, int offset) => - TextEditingValue( - text: text, - selection: TextSelection.collapsed(offset: offset), - ); - - TextEditingValue oldValue = collapsedValue('123', 0); - TextEditingValue newValue = collapsedValue('123456', 6); - - final WhitelistingTextInputFormatter formatter = - WhitelistingTextInputFormatter.digitsOnly; - TextEditingValue formatted = formatter.formatEditUpdate(oldValue, - newValue); - - // assert that we are passing digits only at the first time - expect(oldValue.text, equals('123')); - // assert that we are passing digits only at the second time - expect(newValue.text, equals('123456')); - // assert that cursor is at the end of the text - expect(formatted.selection.baseOffset, equals(6)); - - // move cursor at the middle of the text and then add the number 9. - oldValue = newValue.copyWith( - selection: const TextSelection.collapsed(offset: 4)); - newValue = oldValue.copyWith(text: '1239456'); - - formatted = formatter.formatEditUpdate(oldValue, newValue); - - // cursor must be now at fourth position (right after the number 9) - expect(formatted.selection.baseOffset, equals(4)); - }); } diff --git a/packages/flutter/test/widgets/listener_deprecated_test.dart b/packages/flutter/test/widgets/listener_deprecated_test.dart index d8e8a51dda0ea..cf2b7e360fcce 100644 --- a/packages/flutter/test/widgets/listener_deprecated_test.dart +++ b/packages/flutter/test/widgets/listener_deprecated_test.dart @@ -13,6 +13,10 @@ import 'package:flutter/gestures.dart'; // The tests in this file are moved from listener_test.dart, which tests several // deprecated APIs. The file should be removed once these parameters are. +// ignore_for_file: deprecated_member_use_from_same_package +// We have to ignore the lint rule here because we need to use the deprecated +// callbacks in order to test them. + class HoverClient extends StatefulWidget { const HoverClient({Key key, this.onHover, this.child}) : super(key: key); diff --git a/packages/flutter/test/widgets/text_formatter_test.dart b/packages/flutter/test/widgets/text_formatter_test.dart index 0da0dd13bf5a3..b37d8a3fdf741 100644 --- a/packages/flutter/test/widgets/text_formatter_test.dart +++ b/packages/flutter/test/widgets/text_formatter_test.dart @@ -9,10 +9,11 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; void main() { - const TextEditingValue testOldValue = TextEditingValue(); + TextEditingValue testOldValue; TextEditingValue testNewValue; test('withFunction wraps formatting function', () { + testOldValue = const TextEditingValue(); testNewValue = const TextEditingValue(); TextEditingValue calledOldValue; @@ -46,62 +47,7 @@ void main() { ); }); - test('test filtering formatter example', () { - const TextEditingValue intoTheWoods = TextEditingValue(text: 'Into the Woods'); - expect( - FilteringTextInputFormatter('o', allow: true, replacementString: '*').formatEditUpdate(testOldValue, intoTheWoods), - const TextEditingValue(text: '*o*oo*'), - ); - expect( - FilteringTextInputFormatter('o', allow: false, replacementString: '*').formatEditUpdate(testOldValue, intoTheWoods), - const TextEditingValue(text: 'Int* the W**ds'), - ); - expect( - FilteringTextInputFormatter(RegExp('o+'), allow: true, replacementString: '*').formatEditUpdate(testOldValue, intoTheWoods), - const TextEditingValue(text: '*o*oo*'), - ); - expect( - FilteringTextInputFormatter(RegExp('o+'), allow: false, replacementString: '*').formatEditUpdate(testOldValue, intoTheWoods), - const TextEditingValue(text: 'Int* the W*ds'), - ); - - const TextEditingValue selectedIntoTheWoods = TextEditingValue(text: 'Into the Woods', selection: TextSelection(baseOffset: 11, extentOffset: 14)); - expect( - FilteringTextInputFormatter('o', allow: true, replacementString: '*').formatEditUpdate(testOldValue, selectedIntoTheWoods), - const TextEditingValue(text: '*o*oo*', selection: TextSelection(baseOffset: 4, extentOffset: 6)), - ); - expect( - FilteringTextInputFormatter('o', allow: false, replacementString: '*').formatEditUpdate(testOldValue, selectedIntoTheWoods), - const TextEditingValue(text: 'Int* the W**ds', selection: TextSelection(baseOffset: 11, extentOffset: 14)), - ); - expect( - FilteringTextInputFormatter(RegExp('o+'), allow: true, replacementString: '*').formatEditUpdate(testOldValue, selectedIntoTheWoods), - const TextEditingValue(text: '*o*oo*', selection: TextSelection(baseOffset: 4, extentOffset: 6)), - ); - expect( - FilteringTextInputFormatter(RegExp('o+'), allow: false, replacementString: '*').formatEditUpdate(testOldValue, selectedIntoTheWoods), - const TextEditingValue(text: 'Int* the W**ds', selection: TextSelection(baseOffset: 11, extentOffset: 14)), - ); - }); - - test('test filtering formatter, deny mode', () { - final TextEditingValue actualValue = - FilteringTextInputFormatter.deny(RegExp(r'[a-z]')) - .formatEditUpdate(testOldValue, testNewValue); - - // Expecting - // 1(23 - // 4)56 - expect(actualValue, const TextEditingValue( - text: '123\n456', - selection: TextSelection( - baseOffset: 1, - extentOffset: 5, - ), - )); - }); - - test('test filtering formatter, deny mode (deprecated names)', () { + test('test blacklisting formatter', () { final TextEditingValue actualValue = BlacklistingTextInputFormatter(RegExp(r'[a-z]')) .formatEditUpdate(testOldValue, testNewValue); @@ -119,22 +65,6 @@ void main() { }); test('test single line formatter', () { - final TextEditingValue actualValue = - FilteringTextInputFormatter.singleLineFormatter - .formatEditUpdate(testOldValue, testNewValue); - - // Expecting - // a1b(2c3d4)e5f6 - expect(actualValue, const TextEditingValue( - text: 'a1b2c3d4e5f6', - selection: TextSelection( - baseOffset: 3, - extentOffset: 8, - ), - )); - }); - - test('test single line formatter (deprecated names)', () { final TextEditingValue actualValue = BlacklistingTextInputFormatter.singleLineFormatter .formatEditUpdate(testOldValue, testNewValue); @@ -150,23 +80,7 @@ void main() { )); }); - test('test filtering formatter, allow mode', () { - final TextEditingValue actualValue = - FilteringTextInputFormatter.allow(RegExp(r'[a-c]')) - .formatEditUpdate(testOldValue, testNewValue); - - // Expecting - // ab(c) - expect(actualValue, const TextEditingValue( - text: 'abc', - selection: TextSelection( - baseOffset: 2, - extentOffset: 3, - ), - )); - }); - - test('test filtering formatter, allow mode (deprecated names)', () { + test('test whitelisting formatter', () { final TextEditingValue actualValue = WhitelistingTextInputFormatter(RegExp(r'[a-c]')) .formatEditUpdate(testOldValue, testNewValue); @@ -183,22 +97,6 @@ void main() { }); test('test digits only formatter', () { - final TextEditingValue actualValue = - FilteringTextInputFormatter.digitsOnly - .formatEditUpdate(testOldValue, testNewValue); - - // Expecting - // 1(234)56 - expect(actualValue, const TextEditingValue( - text: '123456', - selection: TextSelection( - baseOffset: 1, - extentOffset: 4, - ), - )); - }); - - test('test digits only formatter (deprecated names)', () { final TextEditingValue actualValue = WhitelistingTextInputFormatter.digitsOnly .formatEditUpdate(testOldValue, testNewValue); @@ -348,5 +246,6 @@ void main() { ), )); }); + }); } diff --git a/packages/flutter_driver/lib/src/extension/extension.dart b/packages/flutter_driver/lib/src/extension/extension.dart index 135c888694a67..c7bbdcf9efd5d 100644 --- a/packages/flutter_driver/lib/src/extension/extension.dart +++ b/packages/flutter_driver/lib/src/extension/extension.dart @@ -129,9 +129,9 @@ class FlutterDriverExtension { 'waitFor': _waitFor, 'waitForAbsent': _waitForAbsent, 'waitForCondition': _waitForCondition, - 'waitUntilNoTransientCallbacks': _waitUntilNoTransientCallbacks, - 'waitUntilNoPendingFrame': _waitUntilNoPendingFrame, - 'waitUntilFirstFrameRasterized': _waitUntilFirstFrameRasterized, + 'waitUntilNoTransientCallbacks': _waitUntilNoTransientCallbacks, // ignore: deprecated_member_use_from_same_package + 'waitUntilNoPendingFrame': _waitUntilNoPendingFrame, // ignore: deprecated_member_use_from_same_package + 'waitUntilFirstFrameRasterized': _waitUntilFirstFrameRasterized, // ignore: deprecated_member_use_from_same_package 'get_semantics_id': _getSemanticsId, 'get_offset': _getOffset, 'get_diagnostics_tree': _getDiagnosticsTree, @@ -153,9 +153,9 @@ class FlutterDriverExtension { 'waitFor': (Map params) => WaitFor.deserialize(params), 'waitForAbsent': (Map params) => WaitForAbsent.deserialize(params), 'waitForCondition': (Map params) => WaitForCondition.deserialize(params), - 'waitUntilNoTransientCallbacks': (Map params) => WaitUntilNoTransientCallbacks.deserialize(params), - 'waitUntilNoPendingFrame': (Map params) => WaitUntilNoPendingFrame.deserialize(params), - 'waitUntilFirstFrameRasterized': (Map params) => WaitUntilFirstFrameRasterized.deserialize(params), + 'waitUntilNoTransientCallbacks': (Map params) => WaitUntilNoTransientCallbacks.deserialize(params), // ignore: deprecated_member_use_from_same_package + 'waitUntilNoPendingFrame': (Map params) => WaitUntilNoPendingFrame.deserialize(params), // ignore: deprecated_member_use_from_same_package + 'waitUntilFirstFrameRasterized': (Map params) => WaitUntilFirstFrameRasterized.deserialize(params), // ignore: deprecated_member_use_from_same_package 'get_semantics_id': (Map params) => GetSemanticsId.deserialize(params), 'get_offset': (Map params) => GetOffset.deserialize(params), 'get_diagnostics_tree': (Map params) => GetDiagnosticsTree.deserialize(params), diff --git a/packages/flutter_driver/test/src/real_tests/extension_test.dart b/packages/flutter_driver/test/src/real_tests/extension_test.dart index b00abea68bdc7..30e52eaa32968 100644 --- a/packages/flutter_driver/test/src/real_tests/extension_test.dart +++ b/packages/flutter_driver/test/src/real_tests/extension_test.dart @@ -41,7 +41,7 @@ void main() { }); testWidgets('returns immediately when transient callback queue is empty', (WidgetTester tester) async { - extension.call(const WaitUntilNoTransientCallbacks().serialize()) + extension.call(const WaitUntilNoTransientCallbacks().serialize()) // ignore: deprecated_member_use_from_same_package .then(expectAsync1((Map r) { result = r; })); @@ -61,7 +61,7 @@ void main() { // Intentionally blank. We only care about existence of a callback. }); - extension.call(const WaitUntilNoTransientCallbacks().serialize()) + extension.call(const WaitUntilNoTransientCallbacks().serialize()) // ignore: deprecated_member_use_from_same_package .then(expectAsync1((Map r) { result = r; })); @@ -888,7 +888,7 @@ void main() { testWidgets('returns immediately when frame is synced', ( WidgetTester tester) async { - extension.call(const WaitUntilNoPendingFrame().serialize()) + extension.call(const WaitUntilNoPendingFrame().serialize()) // ignore: deprecated_member_use_from_same_package .then(expectAsync1((Map r) { result = r; })); @@ -909,7 +909,7 @@ void main() { // Intentionally blank. We only care about existence of a callback. }); - extension.call(const WaitUntilNoPendingFrame().serialize()) + extension.call(const WaitUntilNoPendingFrame().serialize()) // ignore: deprecated_member_use_from_same_package .then(expectAsync1((Map r) { result = r; })); @@ -933,7 +933,7 @@ void main() { 'waits until no pending scheduled frame', (WidgetTester tester) async { SchedulerBinding.instance.scheduleFrame(); - extension.call(const WaitUntilNoPendingFrame().serialize()) + extension.call(const WaitUntilNoPendingFrame().serialize()) // ignore: deprecated_member_use_from_same_package .then(expectAsync1((Map r) { result = r; }));