Unverified Commit 4c8fa187 authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Reland Remove autovalidate deprecations (#91443)

parent 210a905f
......@@ -355,7 +355,7 @@ class DatePickerDialog extends StatefulWidget {
class _DatePickerDialogState extends State<DatePickerDialog> with RestorationMixin {
late final RestorableDateTime _selectedDate = RestorableDateTime(widget.initialDate);
late final _RestorableDatePickerEntryMode _entryMode = _RestorableDatePickerEntryMode(widget.initialEntryMode);
final RestorableBool _autoValidate = RestorableBool(false);
final _RestorableAutovalidateMode _autovalidateMode = _RestorableAutovalidateMode(AutovalidateMode.disabled);
@override
String? get restorationId => widget.restorationId;
......@@ -363,7 +363,7 @@ class _DatePickerDialogState extends State<DatePickerDialog> with RestorationMix
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(_selectedDate, 'selected_date');
registerForRestoration(_autoValidate, 'autovalidate');
registerForRestoration(_autovalidateMode, 'autovalidateMode');
registerForRestoration(_entryMode, 'calendar_entry_mode');
}
......@@ -374,7 +374,7 @@ class _DatePickerDialogState extends State<DatePickerDialog> with RestorationMix
if (_entryMode.value == DatePickerEntryMode.input || _entryMode.value == DatePickerEntryMode.inputOnly) {
final FormState form = _formKey.currentState!;
if (!form.validate()) {
setState(() => _autoValidate.value = true);
setState(() => _autovalidateMode.value = AutovalidateMode.always);
return;
}
form.save();
......@@ -390,7 +390,7 @@ class _DatePickerDialogState extends State<DatePickerDialog> with RestorationMix
setState(() {
switch (_entryMode.value) {
case DatePickerEntryMode.calendar:
_autoValidate.value = false;
_autovalidateMode.value = AutovalidateMode.disabled;
_entryMode.value = DatePickerEntryMode.input;
break;
case DatePickerEntryMode.input:
......@@ -492,7 +492,7 @@ class _DatePickerDialogState extends State<DatePickerDialog> with RestorationMix
Form inputDatePicker() {
return Form(
key: _formKey,
autovalidate: _autoValidate.value,
autovalidateMode: _autovalidateMode.value,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 24),
height: orientation == Orientation.portrait ? _inputFormPortraitHeight : _inputFormLandscapeHeight,
......@@ -642,6 +642,32 @@ class _RestorableDatePickerEntryMode extends RestorableValue<DatePickerEntryMode
Object? toPrimitives() => value.index;
}
// A restorable [AutovalidateMode] value.
//
// This serializes each entry as a unique `int` value.
class _RestorableAutovalidateMode extends RestorableValue<AutovalidateMode> {
_RestorableAutovalidateMode(
AutovalidateMode defaultValue,
) : _defaultValue = defaultValue;
final AutovalidateMode _defaultValue;
@override
AutovalidateMode createDefaultValue() => _defaultValue;
@override
void didUpdateValue(AutovalidateMode? oldValue) {
assert(debugIsSerializableForRestoration(value.index));
notifyListeners();
}
@override
AutovalidateMode fromPrimitives(Object? data) => AutovalidateMode.values[data! as int];
@override
Object? toPrimitives() => value.index;
}
/// Re-usable widget that displays the selected date (in large font) and the
/// help text above it.
///
......
......@@ -1535,12 +1535,6 @@ class DropdownButtonFormField<T> extends FormField<T> {
InputDecoration? decoration,
FormFieldSetter<T>? onSaved,
FormFieldValidator<T>? validator,
@Deprecated(
'Use autovalidateMode parameter which provide more specific '
'behaviour related to auto validation. '
'This feature was deprecated after v1.19.0.',
)
bool autovalidate = false,
AutovalidateMode? autovalidateMode,
double? menuMaxHeight,
bool? enableFeedback,
......@@ -1560,21 +1554,13 @@ class DropdownButtonFormField<T> extends FormField<T> {
assert(isExpanded != null),
assert(itemHeight == null || itemHeight >= kMinInteractiveDimension),
assert(autofocus != null),
assert(autovalidate != null),
assert(
autovalidate == false ||
autovalidate == true && autovalidateMode == null,
'autovalidate and autovalidateMode should not be used together.',
),
decoration = decoration ?? InputDecoration(focusColor: focusColor),
super(
key: key,
onSaved: onSaved,
initialValue: value,
validator: validator,
autovalidateMode: autovalidate
? AutovalidateMode.always
: (autovalidateMode ?? AutovalidateMode.disabled),
autovalidateMode: autovalidateMode ?? AutovalidateMode.disabled,
builder: (FormFieldState<T> field) {
final _DropdownButtonFormFieldState<T> state = field as _DropdownButtonFormFieldState<T>;
final InputDecoration decorationArg = decoration ?? InputDecoration(focusColor: focusColor);
......
......@@ -116,12 +116,6 @@ class TextFormField extends FormField<String> {
SmartDashesType? smartDashesType,
SmartQuotesType? smartQuotesType,
bool enableSuggestions = true,
@Deprecated(
'Use autovalidateMode parameter which provide more specific '
'behaviour related to auto validation. '
'This feature was deprecated after v1.19.0.',
)
bool autovalidate = false,
@Deprecated(
'Use maxLengthEnforcement parameter which provides more specific '
'behavior related to the maxLength limit. '
......@@ -164,12 +158,6 @@ class TextFormField extends FormField<String> {
assert(obscureText != null),
assert(autocorrect != null),
assert(enableSuggestions != null),
assert(autovalidate != null),
assert(
autovalidate == false ||
autovalidate == true && autovalidateMode == null,
'autovalidate and autovalidateMode should not be used together.',
),
assert(maxLengthEnforced != null),
assert(
maxLengthEnforced || maxLengthEnforcement == null,
......@@ -198,9 +186,7 @@ class TextFormField extends FormField<String> {
onSaved: onSaved,
validator: validator,
enabled: enabled ?? decoration?.enabled ?? true,
autovalidateMode: autovalidate
? AutovalidateMode.always
: (autovalidateMode ?? AutovalidateMode.disabled),
autovalidateMode: autovalidateMode ?? AutovalidateMode.disabled,
builder: (FormFieldState<String> field) {
final _TextFormFieldState state = field as _TextFormFieldState;
final InputDecoration effectiveDecoration = (decoration ?? const InputDecoration())
......
......@@ -1915,6 +1915,32 @@ class _RestorableTimePickerMode extends RestorableValue<_TimePickerMode> {
Object? toPrimitives() => value.index;
}
// A restorable [AutovalidateMode] value.
//
// This serializes each entry as a unique `int` value.
class _RestorableAutovalidateMode extends RestorableValue<AutovalidateMode> {
_RestorableAutovalidateMode(
AutovalidateMode defaultValue,
) : _defaultValue = defaultValue;
final AutovalidateMode _defaultValue;
@override
AutovalidateMode createDefaultValue() => _defaultValue;
@override
void didUpdateValue(AutovalidateMode? oldValue) {
assert(debugIsSerializableForRestoration(value.index));
notifyListeners();
}
@override
AutovalidateMode fromPrimitives(Object? data) => AutovalidateMode.values[data! as int];
@override
Object? toPrimitives() => value.index;
}
// A restorable [_RestorableTimePickerEntryMode] value.
//
// This serializes each entry as a unique `int` value.
......@@ -1949,7 +1975,7 @@ class _TimePickerDialogState extends State<TimePickerDialog> with RestorationMix
late final _RestorableTimePickerEntryMode _entryMode = _RestorableTimePickerEntryMode(widget.initialEntryMode);
final _RestorableTimePickerMode _mode = _RestorableTimePickerMode(_TimePickerMode.hour);
final _RestorableTimePickerModeN _lastModeAnnounced = _RestorableTimePickerModeN(null);
final RestorableBool _autoValidate = RestorableBool(false);
final _RestorableAutovalidateMode _autovalidateMode = _RestorableAutovalidateMode(AutovalidateMode.disabled);
final RestorableBoolN _autofocusHour = RestorableBoolN(null);
final RestorableBoolN _autofocusMinute = RestorableBoolN(null);
final RestorableBool _announcedInitialTime = RestorableBool(false);
......@@ -1979,7 +2005,7 @@ class _TimePickerDialogState extends State<TimePickerDialog> with RestorationMix
registerForRestoration(_entryMode, 'entry_mode');
registerForRestoration(_mode, 'mode');
registerForRestoration(_lastModeAnnounced, 'last_mode_announced');
registerForRestoration(_autoValidate, 'autovalidate');
registerForRestoration(_autovalidateMode, 'autovalidateMode');
registerForRestoration(_autofocusHour, 'autofocus_hour');
registerForRestoration(_autofocusMinute, 'autofocus_minute');
registerForRestoration(_announcedInitialTime, 'announced_initial_time');
......@@ -2022,7 +2048,7 @@ class _TimePickerDialogState extends State<TimePickerDialog> with RestorationMix
setState(() {
switch (_entryMode.value) {
case TimePickerEntryMode.dial:
_autoValidate.value = false;
_autovalidateMode.value = AutovalidateMode.disabled;
_entryMode.value = TimePickerEntryMode.input;
break;
case TimePickerEntryMode.input:
......@@ -2096,7 +2122,7 @@ class _TimePickerDialogState extends State<TimePickerDialog> with RestorationMix
if (_entryMode.value == TimePickerEntryMode.input) {
final FormState form = _formKey.currentState!;
if (!form.validate()) {
setState(() { _autoValidate.value = true; });
setState(() { _autovalidateMode.value = AutovalidateMode.always; });
return;
}
form.save();
......@@ -2257,7 +2283,7 @@ class _TimePickerDialogState extends State<TimePickerDialog> with RestorationMix
case TimePickerEntryMode.input:
picker = Form(
key: _formKey,
autovalidate: _autoValidate.value,
autovalidateMode: _autovalidateMode.value,
child: SingleChildScrollView(
restorationId: 'time_picker_scroll_view',
child: Column(
......
......@@ -40,24 +40,11 @@ class Form extends StatefulWidget {
const Form({
Key? key,
required this.child,
@Deprecated(
'Use autovalidateMode parameter which provides more specific '
'behavior related to auto validation. '
'This feature was deprecated after v1.19.0.',
)
this.autovalidate = false,
this.onWillPop,
this.onChanged,
AutovalidateMode? autovalidateMode,
}) : assert(child != null),
assert(autovalidate != null),
assert(
autovalidate == false ||
autovalidate == true && autovalidateMode == null,
'autovalidate and autovalidateMode should not be used together.',
),
autovalidateMode = autovalidateMode ??
(autovalidate ? AutovalidateMode.always : AutovalidateMode.disabled),
autovalidateMode = autovalidateMode ?? AutovalidateMode.disabled,
super(key: key);
/// Returns the closest [FormState] which encloses the given context.
......@@ -104,15 +91,6 @@ class Form extends StatefulWidget {
/// {@macro flutter.widgets.FormField.autovalidateMode}
final AutovalidateMode autovalidateMode;
/// Used to enable/disable form fields auto validation and update their error
/// text.
@Deprecated(
'Use autovalidateMode parameter which provides more specific '
'behavior related to auto validation. '
'This feature was deprecated after v1.19.0.',
)
final bool autovalidate;
@override
FormState createState() => FormState();
}
......@@ -287,23 +265,11 @@ class FormField<T> extends StatefulWidget {
this.onSaved,
this.validator,
this.initialValue,
@Deprecated(
'Use autovalidateMode parameter which provides more specific '
'behavior related to auto validation. '
'This feature was deprecated after v1.19.0.',
)
this.autovalidate = false,
this.enabled = true,
AutovalidateMode? autovalidateMode,
this.restorationId,
}) : assert(builder != null),
assert(
autovalidate == false ||
autovalidate == true && autovalidateMode == null,
'autovalidate and autovalidateMode should not be used together.',
),
autovalidateMode = autovalidateMode ??
(autovalidate ? AutovalidateMode.always : AutovalidateMode.disabled),
autovalidateMode = autovalidateMode ?? AutovalidateMode.disabled,
super(key: key);
/// An optional method to call with the final value when the form is saved via
......@@ -344,26 +310,15 @@ class FormField<T> extends StatefulWidget {
/// error text.
///
/// {@template flutter.widgets.FormField.autovalidateMode}
/// If [AutovalidateMode.onUserInteraction] this form field will only
/// auto-validate after its content changes, if [AutovalidateMode.always] it
/// will auto validate even without user interaction and
/// if [AutovalidateMode.disabled] the auto validation will be disabled.
/// If [AutovalidateMode.onUserInteraction], this FormField will only
/// auto-validate after its content changes. If [AutovalidateMode.always], it
/// will auto-validate even without user interaction. If
/// [AutovalidateMode.disabled], auto-validation will be disabled.
///
/// Defaults to [AutovalidateMode.disabled] if `autovalidate` is false which
/// means no auto validation will occur. If `autovalidate` is true then this
/// is set to [AutovalidateMode.always] for backward compatibility.
/// Defaults to [AutovalidateMode.disabled], cannot be null.
/// {@endtemplate}
final AutovalidateMode autovalidateMode;
/// Used to enable/disable auto validation and update their error
/// text.
@Deprecated(
'Use autovalidateMode parameter which provides more specific '
'behavior related to auto validation. '
'This feature was deprecated after v1.19.0.',
)
final bool autovalidate;
/// Restoration ID to save and restore the state of the form field.
///
/// Setting the restoration ID to a non-null value results in whether or not
......
......@@ -1078,29 +1078,6 @@ void main() {
expect(_validateCalled, 1);
});
testWidgets('autovalidateMode and autovalidate should not be used at the same time', (WidgetTester tester) async {
Widget builder() {
return MaterialApp(
home: Material(
child: Center(
child: DropdownButtonFormField<String>(
autovalidate: true,
autovalidateMode: AutovalidateMode.always,
items: menuItems.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: onChanged,
),
),
),
);
}
expect(() => builder(), throwsAssertionError);
});
testWidgets('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async {
await tester.pumpWidget(buildFormFrame(
buttonAlignment: AlignmentDirectional.center,
......
......@@ -649,23 +649,6 @@ void main() {
expect(_validateCalled, 1);
});
testWidgets('autovalidateMode and autovalidate should not be used at the same time', (WidgetTester tester) async {
expect(() async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Scaffold(
body: TextFormField(
autovalidate: true,
autovalidateMode: AutovalidateMode.onUserInteraction,
),
),
),
),
);
}, throwsAssertionError);
});
testWidgets('textSelectionControls is passed to super', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
......
......@@ -684,7 +684,7 @@ void main() {
);
}
// Makes sure the Form widget won't autovalidate the form fields
// Makes sure the Form widget won't auto-validate the form fields
// after rebuilds if there is not user interaction.
await tester.pumpWidget(builder());
await tester.pumpWidget(builder());
......@@ -733,38 +733,6 @@ void main() {
expect(find.text(errorText('')!), findsOneWidget);
});
testWidgets('autovalidate parameter is still used if true', (WidgetTester tester) async {
late FormFieldState<String> formFieldState;
String? errorText(String? value) => '$value/error';
Widget builder() {
return MaterialApp(
home: MediaQuery(
data: const MediaQueryData(),
child: Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Material(
child: FormField<String>(
initialValue: 'foo',
autovalidate: true,
builder: (FormFieldState<String> state) {
formFieldState = state;
return Container();
},
validator: errorText,
),
),
),
),
),
);
}
await tester.pumpWidget(builder());
expect(formFieldState.hasError, isTrue);
});
testWidgets('Form.reset() resets form fields, and auto validation will only happen on the next user interaction if autovalidateMode is onUserInteraction', (WidgetTester tester) async {
final GlobalKey<FormState> formState = GlobalKey<FormState>();
String? errorText(String? value) => '$value/error';
......@@ -809,46 +777,6 @@ void main() {
expect(find.text(errorText('bar')!), findsNothing);
});
testWidgets('Form.autovalidateMode and Form.autovalidate should not be used at the same time', (WidgetTester tester) async {
Widget builder() {
return MaterialApp(
home: MediaQuery(
data: const MediaQueryData(),
child: Directionality(
textDirection: TextDirection.ltr,
child: Form(
autovalidate: true,
autovalidateMode: AutovalidateMode.disabled,
child: Container(),
),
),
),
);
}
expect(() => builder(), throwsAssertionError);
});
testWidgets('FormField.autovalidateMode and FormField.autovalidate should not be used at the same time', (WidgetTester tester) async {
Widget builder() {
return MaterialApp(
home: MediaQuery(
data: const MediaQueryData(),
child: Directionality(
textDirection: TextDirection.ltr,
child: FormField<String>(
autovalidate: true,
autovalidateMode: AutovalidateMode.disabled,
builder: (_) {
return Container();
},
),
),
),
);
}
expect(() => builder(), throwsAssertionError);
});
// Regression test for https://github.com/flutter/flutter/issues/63753.
testWidgets('Validate form should return correct validation if the value is composing', (WidgetTester tester) async {
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
......@@ -886,87 +814,4 @@ void main() {
expect(fieldValue, '123456');
expect(formKey.currentState!.validate(), isFalse);
});
testWidgets('FormField.autovalidate parameter is passed into class the property', (WidgetTester tester) async {
String? errorText(String? value) => '$value/error';
const ObjectKey widgetKey = ObjectKey('key');
Widget builder({required bool autovalidate}) {
return MaterialApp(
home: MediaQuery(
data: const MediaQueryData(),
child: Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Material(
child: FormField<String>(
key: widgetKey,
initialValue: 'foo',
autovalidate: autovalidate,
builder: (FormFieldState<String> state) {
return Container();
},
validator: errorText,
),
),
),
),
),
);
}
// When autovalidate is true
await tester.pumpWidget(builder(autovalidate: true));
final Finder formFieldFinder = find.byKey(widgetKey);
FormField<String> formField = tester.widget(formFieldFinder);
expect(formField.autovalidate, isTrue);
expect(formField.autovalidateMode, equals(AutovalidateMode.always));
// When autovalidate is false
await tester.pumpWidget(builder(autovalidate: false));
formField = tester.widget(formFieldFinder);
expect(formField.autovalidate, isFalse);
expect(formField.autovalidateMode, equals(AutovalidateMode.disabled));
});
testWidgets('Form.autovalidate parameter is passed into class the property', (WidgetTester tester) async {
const ObjectKey widgetKey = ObjectKey('key');
Widget builder({required bool autovalidate}) {
return MaterialApp(
home: MediaQuery(
data: const MediaQueryData(),
child: Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Material(
child: Form(
key: widgetKey,
autovalidate: autovalidate,
child: Container(),
),
),
),
),
),
);
}
// When autovalidate is true
await tester.pumpWidget(builder(autovalidate: true));
final Finder formFinder = find.byKey(widgetKey);
Form formWidget = tester.widget(formFinder);
expect(formWidget.autovalidate, isTrue);
expect(formWidget.autovalidateMode, equals(AutovalidateMode.always));
// When autovalidate is false
await tester.pumpWidget(builder(autovalidate: false));
formWidget = tester.widget(formFinder);
expect(formWidget.autovalidate, isFalse);
expect(formWidget.autovalidateMode, equals(AutovalidateMode.disabled));
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment