mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Re-land "Deprecate WhitelistingTextInputFormatter and BlacklistingTextInputFormatter (#59120)" (#59876)
This relands #59120, which was reverted in #59870.
This commit is contained in:
parent
0d7ff7a9e7
commit
5cfb16b193
@ -29,6 +29,9 @@ 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.
|
||||
|
@ -135,7 +135,7 @@ Future<void> run(List<String> 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]+)\.'$");
|
||||
final RegExp _deprecationPattern3 = RegExp(r"^ *'This feature was deprecated after v([0-9]+)\.([0-9]+)\.([0-9]+)(\-[0-9]+\.[0-9]+\.pre)?\.'$");
|
||||
final RegExp _deprecationPattern4 = RegExp(r'^ *\)$');
|
||||
|
||||
/// Some deprecation notices are special, for example they're used to annotate members that
|
||||
@ -182,7 +182,7 @@ Future<void> 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.';
|
||||
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';
|
||||
}
|
||||
message = match2[1];
|
||||
lineNumber += 1;
|
||||
@ -190,6 +190,13 @@ Future<void> 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 '"))
|
||||
|
@ -55,6 +55,42 @@ void test10() { }
|
||||
|
||||
@Deprecated(
|
||||
'URLs are not required. '
|
||||
'This feature was deprecated after v2.0.0.'
|
||||
'This feature was deprecated after v1.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() { }
|
||||
|
@ -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.\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: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,7 +49,12 @@ 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'
|
||||
|
@ -217,7 +217,7 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
|
||||
validator: _validatePhoneNumber,
|
||||
// TextInputFormatters are applied in sequence.
|
||||
inputFormatters: <TextInputFormatter> [
|
||||
WhitelistingTextInputFormatter.digitsOnly,
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
// Fit the validating format.
|
||||
_phoneNumberFormatter,
|
||||
],
|
||||
|
@ -463,7 +463,7 @@ class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
|
||||
);
|
||||
|
||||
final Color actionsForegroundColor = CupertinoDynamicColor.resolve(
|
||||
widget.actionsForegroundColor, // ignore: deprecated_member_use_from_same_package
|
||||
widget.actionsForegroundColor,
|
||||
context,
|
||||
);
|
||||
if (!widget.transitionBetweenRoutes || !_isTransitionable(context)) {
|
||||
@ -694,8 +694,8 @@ class _CupertinoSliverNavigationBarState extends State<CupertinoSliverNavigation
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Lint ignore to maintain backward compatibility.
|
||||
final Color actionsForegroundColor = CupertinoDynamicColor.resolve(widget.actionsForegroundColor, context) // ignore: deprecated_member_use_from_same_package
|
||||
?? CupertinoTheme.of(context).primaryColor;
|
||||
final Color actionsForegroundColor = CupertinoDynamicColor.resolve(widget.actionsForegroundColor, context)
|
||||
?? CupertinoTheme.of(context).primaryColor;
|
||||
|
||||
final _NavigationBarStaticComponents components = _NavigationBarStaticComponents(
|
||||
keys: keys,
|
||||
|
@ -4,11 +4,6 @@
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
// TODO(shihaohong): remove ignoring deprecated member use analysis
|
||||
// when AlertDialog.scrollable parameter is removed. See
|
||||
// https://flutter.dev/go/scrollable-alert-dialog for more details.
|
||||
// ignore_for_file: deprecated_member_use_from_same_package
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
@ -1927,7 +1927,6 @@ class _InputDecoratorState extends State<InputDecorator> 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);
|
||||
|
||||
@ -1976,7 +1975,6 @@ class _InputDecoratorState extends State<InputDecorator> 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;
|
||||
}
|
||||
|
||||
@ -1987,7 +1985,6 @@ class _InputDecoratorState extends State<InputDecorator> 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) {
|
||||
@ -2520,7 +2517,7 @@ class InputDecoration {
|
||||
'Use floatingLabelBehavior instead. '
|
||||
'This feature was deprecated after v1.13.2.'
|
||||
)
|
||||
this.hasFloatingPlaceholder = true, // ignore: deprecated_member_use_from_same_package
|
||||
this.hasFloatingPlaceholder = true,
|
||||
this.floatingLabelBehavior = FloatingLabelBehavior.auto,
|
||||
this.isCollapsed = false,
|
||||
this.isDense,
|
||||
@ -2566,7 +2563,6 @@ 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,
|
||||
@ -2577,9 +2573,8 @@ 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,
|
||||
@ -3372,7 +3367,6 @@ 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,
|
||||
@ -3420,7 +3414,6 @@ 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,
|
||||
@ -3462,7 +3455,6 @@ 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
|
||||
@ -3511,7 +3503,7 @@ class InputDecoration {
|
||||
errorText,
|
||||
errorStyle,
|
||||
errorMaxLines,
|
||||
hasFloatingPlaceholder,// ignore: deprecated_member_use_from_same_package
|
||||
hasFloatingPlaceholder,
|
||||
floatingLabelBehavior,
|
||||
isDense,
|
||||
contentPadding,
|
||||
@ -3560,7 +3552,6 @@ 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',
|
||||
@ -3624,7 +3615,6 @@ 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,
|
||||
@ -3648,7 +3638,6 @@ 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');
|
||||
|
||||
@ -4001,7 +3990,6 @@ 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,
|
||||
@ -4033,7 +4021,6 @@ class InputDecorationTheme with Diagnosticable {
|
||||
hintStyle,
|
||||
errorStyle,
|
||||
errorMaxLines,
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
hasFloatingPlaceholder,
|
||||
floatingLabelBehavior,
|
||||
isDense,
|
||||
@ -4100,7 +4087,6 @@ class InputDecorationTheme with Diagnosticable {
|
||||
properties.add(DiagnosticsProperty<TextStyle>('hintStyle', hintStyle, defaultValue: defaultTheme.hintStyle));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('errorStyle', errorStyle, defaultValue: defaultTheme.errorStyle));
|
||||
properties.add(IntProperty('errorMaxLines', errorMaxLines, defaultValue: defaultTheme.errorMaxLines));
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
properties.add(DiagnosticsProperty<bool>('hasFloatingPlaceholder', hasFloatingPlaceholder, defaultValue: defaultTheme.hasFloatingPlaceholder));
|
||||
properties.add(DiagnosticsProperty<FloatingLabelBehavior>('floatingLabelBehavior', floatingLabelBehavior, defaultValue: defaultTheme.floatingLabelBehavior));
|
||||
properties.add(DiagnosticsProperty<bool>('isDense', isDense, defaultValue: defaultTheme.isDense));
|
||||
|
@ -29,9 +29,9 @@ const double _maxCalendarWidthPortrait = 480.0;
|
||||
|
||||
/// Displays a scrollable calendar grid that allows a user to select a range
|
||||
/// of dates.
|
||||
///
|
||||
/// Note: this is not publicly exported (see pickers.dart), as it is an
|
||||
/// internal component used by [showDateRangePicker].
|
||||
//
|
||||
// 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({
|
||||
|
@ -21,7 +21,7 @@ import '../theme.dart';
|
||||
|
||||
import 'date_picker_common.dart';
|
||||
|
||||
// NOTE: this is the original implementation for the Material Date Picker.
|
||||
// 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,7 +406,6 @@ class MonthPicker extends StatefulWidget {
|
||||
_MonthPickerState createState() => _MonthPickerState();
|
||||
}
|
||||
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
class _MonthPickerState extends State<MonthPicker> with SingleTickerProviderStateMixin {
|
||||
static final Animatable<double> _chevronOpacityTween = Tween<double>(begin: 1.0, end: 0.0)
|
||||
.chain(CurveTween(curve: Curves.easeInOut));
|
||||
@ -428,7 +427,6 @@ class _MonthPickerState extends State<MonthPicker> with SingleTickerProviderStat
|
||||
}
|
||||
|
||||
@override
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
void didUpdateWidget(MonthPicker oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.selectedDate != oldWidget.selectedDate) {
|
||||
@ -479,7 +477,6 @@ class _MonthPickerState extends State<MonthPicker> 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<DateTime>(month),
|
||||
selectedDate: widget.selectedDate,
|
||||
@ -675,7 +672,6 @@ class YearPicker extends StatefulWidget {
|
||||
_YearPickerState createState() => _YearPickerState();
|
||||
}
|
||||
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
class _YearPickerState extends State<YearPicker> {
|
||||
static const double _itemExtent = 50.0;
|
||||
ScrollController scrollController;
|
||||
|
@ -12,7 +12,7 @@ import '../material.dart';
|
||||
import '../text_theme.dart';
|
||||
import '../theme.dart';
|
||||
|
||||
// NOTE: This is an internal implementation file. Even though there are public
|
||||
// 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.
|
||||
|
@ -4,10 +4,9 @@
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
|
||||
// Common date utility functions used by the date picker implementation
|
||||
|
||||
// NOTE: This is an internal implementation file. Even though there are public
|
||||
// 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.
|
||||
|
@ -244,16 +244,16 @@ class _InputDatePickerFormFieldState extends State<InputDatePickerFormField> {
|
||||
}
|
||||
|
||||
/// A `TextInputFormatter` set up to format dates.
|
||||
///
|
||||
/// Note: this is not publicly exported (see pickers.dart), as it is
|
||||
/// just meant for internal use by `InputDatePickerFormField` and
|
||||
/// `InputDateRangePicker`.
|
||||
//
|
||||
// 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 = WhitelistingTextInputFormatter(RegExp('[\\d$_commonSeparators\\$separator]+'));
|
||||
) : _filterFormatter = FilteringTextInputFormatter.allow(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 WhitelistingTextInputFormatter _filterFormatter;
|
||||
final TextInputFormatter _filterFormatter;
|
||||
|
||||
@override
|
||||
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
|
||||
|
@ -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.
|
||||
///
|
||||
/// Note: this is not publicly exported (see pickers.dart), as it is just an
|
||||
/// internal component used by [showDateRangePicker].
|
||||
//
|
||||
// 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.
|
||||
|
@ -15,3 +15,9 @@ 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.
|
||||
|
@ -2092,7 +2092,6 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
|
||||
|
||||
// Backwards compatibility for deprecated resizeToAvoidBottomPadding property
|
||||
bool get _resizeToAvoidBottomInset {
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
return widget.resizeToAvoidBottomInset ?? widget.resizeToAvoidBottomPadding ?? true;
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,6 @@ 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
|
||||
|
@ -218,7 +218,7 @@ class PlatformAssetBundle extends CachingAssetBundle {
|
||||
Future<ByteData> 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()); // ignore: deprecated_member_use_from_same_package
|
||||
await defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData());
|
||||
if (asset == null)
|
||||
throw FlutterError('Unable to load asset: $key');
|
||||
return asset;
|
||||
|
@ -48,7 +48,7 @@ class BasicMessageChannel<T> {
|
||||
final MessageCodec<T> codec;
|
||||
|
||||
/// The messenger which sends the bytes for this channel, not null.
|
||||
BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger; // ignore: deprecated_member_use_from_same_package
|
||||
BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger;
|
||||
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; // ignore: deprecated_member_use_from_same_package
|
||||
BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger;
|
||||
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; // ignore: deprecated_member_use_from_same_package
|
||||
BinaryMessenger get binaryMessenger => _binaryMessenger ?? defaultBinaryMessenger;
|
||||
final BinaryMessenger _binaryMessenger;
|
||||
|
||||
/// Sets up a broadcast stream for receiving events on this channel.
|
||||
|
@ -6,7 +6,8 @@
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart' show visibleForTesting;
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'text_editing.dart';
|
||||
import 'text_input.dart';
|
||||
|
||||
@ -17,10 +18,9 @@ import 'text_input.dart';
|
||||
/// IME and not on text under composition (i.e., only when
|
||||
/// [TextEditingValue.composing] is collapsed).
|
||||
///
|
||||
/// Concrete implementations [BlacklistingTextInputFormatter], which removes
|
||||
/// blacklisted characters upon edit commit, and
|
||||
/// [WhitelistingTextInputFormatter], which only allows entries of whitelisted
|
||||
/// characters, are provided.
|
||||
/// 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).
|
||||
///
|
||||
/// To create custom formatters, extend the [TextInputFormatter] class and
|
||||
/// implement the [formatEditUpdate] method.
|
||||
@ -28,9 +28,7 @@ import 'text_input.dart';
|
||||
/// See also:
|
||||
///
|
||||
/// * [EditableText] on which the formatting apply.
|
||||
/// * [BlacklistingTextInputFormatter], a provided formatter for blacklisting
|
||||
/// characters.
|
||||
/// * [WhitelistingTextInputFormatter], a provided formatter for whitelisting
|
||||
/// * [FilteringTextInputFormatter], a provided formatter for filtering
|
||||
/// characters.
|
||||
abstract class TextInputFormatter {
|
||||
/// Called when text is being typed or cut/copy/pasted in the [EditableText].
|
||||
@ -77,34 +75,140 @@ class _SimpleTextInputFormatter extends TextInputFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
/// A [TextInputFormatter] that prevents the insertion of blacklisted
|
||||
/// characters patterns.
|
||||
/// A [TextInputFormatter] that prevents the insertion of characters
|
||||
/// matching (or not matching) a particular pattern.
|
||||
///
|
||||
/// Instances of blacklisted characters found in the new [TextEditingValue]s
|
||||
/// Instances of filtered 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.
|
||||
///
|
||||
/// 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.
|
||||
class FilteringTextInputFormatter extends TextInputFormatter {
|
||||
/// Creates a formatter that prevents the insertion of characters
|
||||
/// based on a filter pattern.
|
||||
///
|
||||
/// The [blacklistedPattern] must not be null.
|
||||
BlacklistingTextInputFormatter(
|
||||
this.blacklistedPattern, {
|
||||
/// 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(blacklistedPattern != null);
|
||||
}) : assert(filterPattern != null),
|
||||
assert(allow != null),
|
||||
assert(replacementString != null);
|
||||
|
||||
/// A [Pattern] to match and replace incoming [TextEditingValue]s.
|
||||
final Pattern blacklistedPattern;
|
||||
/// Creates a formatter that only allows characters matching a pattern.
|
||||
///
|
||||
/// The [filterPattern] and [replacementString] arguments
|
||||
/// must not be null.
|
||||
FilteringTextInputFormatter.allow(
|
||||
this.filterPattern, {
|
||||
this.replacementString = '',
|
||||
}) : assert(filterPattern != null),
|
||||
assert(replacementString != null),
|
||||
allow = true;
|
||||
|
||||
/// String used to replace found patterns.
|
||||
/// 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 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.
|
||||
final String replacementString;
|
||||
|
||||
@override
|
||||
@ -115,16 +219,87 @@ class BlacklistingTextInputFormatter extends TextInputFormatter {
|
||||
return _selectionAwareTextManipulation(
|
||||
newValue,
|
||||
(String substring) {
|
||||
return substring.replaceAll(blacklistedPattern, replacementString);
|
||||
return substring.splitMapJoin(
|
||||
filterPattern,
|
||||
onMatch: !allow ? (Match match) => replacementString : null,
|
||||
onNonMatch: allow ? (String nonMatch) => nonMatch.isNotEmpty ? replacementString : '' : null,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// A [BlacklistingTextInputFormatter] that forces input to be a single line.
|
||||
/// 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.'
|
||||
)
|
||||
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.
|
||||
///
|
||||
@ -216,50 +391,6 @@ 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<String>((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),
|
||||
|
@ -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, // ignore: deprecated_member_use_from_same_package
|
||||
this.onPointerEnter,
|
||||
@Deprecated(
|
||||
'Use MouseRegion.onExit instead. See MouseRegion.opaque for behavioral difference. '
|
||||
'This feature was deprecated after v1.10.14.'
|
||||
)
|
||||
this.onPointerExit, // ignore: deprecated_member_use_from_same_package
|
||||
this.onPointerExit,
|
||||
@Deprecated(
|
||||
'Use MouseRegion.onHover instead. See MouseRegion.opaque for behavioral difference. '
|
||||
'This feature was deprecated after v1.10.14.'
|
||||
)
|
||||
this.onPointerHover, // ignore: deprecated_member_use_from_same_package
|
||||
this.onPointerHover,
|
||||
this.onPointerUp,
|
||||
this.onPointerCancel,
|
||||
this.onPointerSignal,
|
||||
|
@ -460,7 +460,7 @@ class EditableText extends StatefulWidget {
|
||||
keyboardType = keyboardType ?? _inferKeyboardType(autofillHints: autofillHints, maxLines: maxLines),
|
||||
inputFormatters = maxLines == 1
|
||||
? <TextInputFormatter>[
|
||||
BlacklistingTextInputFormatter.singleLineFormatter,
|
||||
FilteringTextInputFormatter.singleLineFormatter,
|
||||
...inputFormatters ?? const Iterable<TextInputFormatter>.empty(),
|
||||
]
|
||||
: inputFormatters,
|
||||
|
@ -2846,7 +2846,6 @@ void main() {
|
||||
isEmpty: true,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(borderSide: BorderSide.none),
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
hasFloatingPlaceholder: false,
|
||||
labelText: 'label',
|
||||
),
|
||||
@ -2871,7 +2870,6 @@ void main() {
|
||||
// isFocused: false (default)
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(borderSide: BorderSide.none),
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
hasFloatingPlaceholder: false,
|
||||
labelText: 'label',
|
||||
),
|
||||
@ -3941,7 +3939,6 @@ 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),
|
||||
|
@ -3157,6 +3157,27 @@ 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: <TextInputFormatter> [
|
||||
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,
|
||||
@ -3178,6 +3199,33 @@ 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: <TextInputFormatter> [
|
||||
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,
|
||||
@ -3205,6 +3253,44 @@ 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: <TextInputFormatter> [
|
||||
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<TextSelectionPoint> 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(
|
||||
@ -3473,7 +3559,28 @@ void main() {
|
||||
expect(textController.text, '0123456789');
|
||||
});
|
||||
|
||||
testWidgets('maxLength still works with other formatters.', (WidgetTester tester) async {
|
||||
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: <TextInputFormatter> [
|
||||
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 {
|
||||
final TextEditingController textController = TextEditingController();
|
||||
|
||||
await tester.pumpWidget(boilerplate(
|
||||
|
@ -86,4 +86,148 @@ 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));
|
||||
});
|
||||
}
|
||||
|
@ -13,10 +13,6 @@ 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);
|
||||
|
||||
|
@ -9,11 +9,10 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
void main() {
|
||||
TextEditingValue testOldValue;
|
||||
const TextEditingValue testOldValue = TextEditingValue();
|
||||
TextEditingValue testNewValue;
|
||||
|
||||
test('withFunction wraps formatting function', () {
|
||||
testOldValue = const TextEditingValue();
|
||||
testNewValue = const TextEditingValue();
|
||||
|
||||
TextEditingValue calledOldValue;
|
||||
@ -47,7 +46,62 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
test('test blacklisting formatter', () {
|
||||
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)', () {
|
||||
final TextEditingValue actualValue =
|
||||
BlacklistingTextInputFormatter(RegExp(r'[a-z]'))
|
||||
.formatEditUpdate(testOldValue, testNewValue);
|
||||
@ -65,6 +119,22 @@ 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);
|
||||
@ -80,7 +150,23 @@ void main() {
|
||||
));
|
||||
});
|
||||
|
||||
test('test whitelisting formatter', () {
|
||||
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)', () {
|
||||
final TextEditingValue actualValue =
|
||||
WhitelistingTextInputFormatter(RegExp(r'[a-c]'))
|
||||
.formatEditUpdate(testOldValue, testNewValue);
|
||||
@ -97,6 +183,22 @@ 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);
|
||||
@ -246,6 +348,5 @@ void main() {
|
||||
),
|
||||
));
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -129,9 +129,9 @@ class FlutterDriverExtension {
|
||||
'waitFor': _waitFor,
|
||||
'waitForAbsent': _waitForAbsent,
|
||||
'waitForCondition': _waitForCondition,
|
||||
'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
|
||||
'waitUntilNoTransientCallbacks': _waitUntilNoTransientCallbacks,
|
||||
'waitUntilNoPendingFrame': _waitUntilNoPendingFrame,
|
||||
'waitUntilFirstFrameRasterized': _waitUntilFirstFrameRasterized,
|
||||
'get_semantics_id': _getSemanticsId,
|
||||
'get_offset': _getOffset,
|
||||
'get_diagnostics_tree': _getDiagnosticsTree,
|
||||
@ -153,9 +153,9 @@ class FlutterDriverExtension {
|
||||
'waitFor': (Map<String, String> params) => WaitFor.deserialize(params),
|
||||
'waitForAbsent': (Map<String, String> params) => WaitForAbsent.deserialize(params),
|
||||
'waitForCondition': (Map<String, String> params) => WaitForCondition.deserialize(params),
|
||||
'waitUntilNoTransientCallbacks': (Map<String, String> params) => WaitUntilNoTransientCallbacks.deserialize(params), // ignore: deprecated_member_use_from_same_package
|
||||
'waitUntilNoPendingFrame': (Map<String, String> params) => WaitUntilNoPendingFrame.deserialize(params), // ignore: deprecated_member_use_from_same_package
|
||||
'waitUntilFirstFrameRasterized': (Map<String, String> params) => WaitUntilFirstFrameRasterized.deserialize(params), // ignore: deprecated_member_use_from_same_package
|
||||
'waitUntilNoTransientCallbacks': (Map<String, String> params) => WaitUntilNoTransientCallbacks.deserialize(params),
|
||||
'waitUntilNoPendingFrame': (Map<String, String> params) => WaitUntilNoPendingFrame.deserialize(params),
|
||||
'waitUntilFirstFrameRasterized': (Map<String, String> params) => WaitUntilFirstFrameRasterized.deserialize(params),
|
||||
'get_semantics_id': (Map<String, String> params) => GetSemanticsId.deserialize(params),
|
||||
'get_offset': (Map<String, String> params) => GetOffset.deserialize(params),
|
||||
'get_diagnostics_tree': (Map<String, String> params) => GetDiagnosticsTree.deserialize(params),
|
||||
|
@ -41,7 +41,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('returns immediately when transient callback queue is empty', (WidgetTester tester) async {
|
||||
extension.call(const WaitUntilNoTransientCallbacks().serialize()) // ignore: deprecated_member_use_from_same_package
|
||||
extension.call(const WaitUntilNoTransientCallbacks().serialize())
|
||||
.then<void>(expectAsync1((Map<String, dynamic> r) {
|
||||
result = r;
|
||||
}));
|
||||
@ -61,7 +61,7 @@ void main() {
|
||||
// Intentionally blank. We only care about existence of a callback.
|
||||
});
|
||||
|
||||
extension.call(const WaitUntilNoTransientCallbacks().serialize()) // ignore: deprecated_member_use_from_same_package
|
||||
extension.call(const WaitUntilNoTransientCallbacks().serialize())
|
||||
.then<void>(expectAsync1((Map<String, dynamic> r) {
|
||||
result = r;
|
||||
}));
|
||||
@ -888,7 +888,7 @@ void main() {
|
||||
|
||||
testWidgets('returns immediately when frame is synced', (
|
||||
WidgetTester tester) async {
|
||||
extension.call(const WaitUntilNoPendingFrame().serialize()) // ignore: deprecated_member_use_from_same_package
|
||||
extension.call(const WaitUntilNoPendingFrame().serialize())
|
||||
.then<void>(expectAsync1((Map<String, dynamic> r) {
|
||||
result = r;
|
||||
}));
|
||||
@ -909,7 +909,7 @@ void main() {
|
||||
// Intentionally blank. We only care about existence of a callback.
|
||||
});
|
||||
|
||||
extension.call(const WaitUntilNoPendingFrame().serialize()) // ignore: deprecated_member_use_from_same_package
|
||||
extension.call(const WaitUntilNoPendingFrame().serialize())
|
||||
.then<void>(expectAsync1((Map<String, dynamic> 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()) // ignore: deprecated_member_use_from_same_package
|
||||
extension.call(const WaitUntilNoPendingFrame().serialize())
|
||||
.then<void>(expectAsync1((Map<String, dynamic> r) {
|
||||
result = r;
|
||||
}));
|
||||
|
Loading…
Reference in New Issue
Block a user