Unverified Commit b6cca392 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Updated the gallery text fields demo (#15362)

parent c345c1bb
...@@ -23,6 +23,60 @@ class PersonData { ...@@ -23,6 +23,60 @@ class PersonData {
String password = ''; String password = '';
} }
class PasswordField extends StatefulWidget {
const PasswordField({
this.fieldKey,
this.hintText,
this.labelText,
this.helperText,
this.onSaved,
this.validator,
this.onFieldSubmitted,
});
final Key fieldKey;
final String hintText;
final String labelText;
final String helperText;
final FormFieldSetter<String> onSaved;
final FormFieldValidator<String> validator;
final ValueChanged<String> onFieldSubmitted;
@override
_PasswordFieldState createState() => new _PasswordFieldState();
}
class _PasswordFieldState extends State<PasswordField> {
bool _obscureText = true;
@override
Widget build(BuildContext context) {
return new TextFormField(
key: widget.fieldKey,
obscureText: _obscureText,
maxLength: 8,
onSaved: widget.onSaved,
validator: widget.validator,
onFieldSubmitted: widget.onFieldSubmitted,
decoration: new InputDecoration(
border: const UnderlineInputBorder(),
filled: true,
hintText: widget.hintText,
labelText: widget.labelText,
helperText: widget.helperText,
suffixIcon: new GestureDetector(
onTap: () {
setState(() {
_obscureText = !_obscureText;
});
},
child: new Icon(_obscureText ? Icons.visibility : Icons.visibility_off),
),
),
);
}
}
class TextFormFieldDemoState extends State<TextFormFieldDemo> { class TextFormFieldDemoState extends State<TextFormFieldDemo> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
...@@ -36,6 +90,7 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -36,6 +90,7 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
bool _autovalidate = false; bool _autovalidate = false;
bool _formWasEdited = false; bool _formWasEdited = false;
final GlobalKey<FormState> _formKey = new GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
final GlobalKey<FormFieldState<String>> _passwordFieldKey = new GlobalKey<FormFieldState<String>>(); final GlobalKey<FormFieldState<String>> _passwordFieldKey = new GlobalKey<FormFieldState<String>>();
final _UsNumberTextInputFormatter _phoneNumberFormatter = new _UsNumberTextInputFormatter(); final _UsNumberTextInputFormatter _phoneNumberFormatter = new _UsNumberTextInputFormatter();
...@@ -64,7 +119,7 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -64,7 +119,7 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
_formWasEdited = true; _formWasEdited = true;
final RegExp phoneExp = new RegExp(r'^\(\d\d\d\) \d\d\d\-\d\d\d\d$'); final RegExp phoneExp = new RegExp(r'^\(\d\d\d\) \d\d\d\-\d\d\d\d$');
if (!phoneExp.hasMatch(value)) if (!phoneExp.hasMatch(value))
return '(###) ###-#### - Please enter a valid US phone number.'; return '(###) ###-#### - Enter a US phone number.';
return null; return null;
} }
...@@ -72,9 +127,9 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -72,9 +127,9 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
_formWasEdited = true; _formWasEdited = true;
final FormFieldState<String> passwordField = _passwordFieldKey.currentState; final FormFieldState<String> passwordField = _passwordFieldKey.currentState;
if (passwordField.value == null || passwordField.value.isEmpty) if (passwordField.value == null || passwordField.value.isEmpty)
return 'Please choose a password.'; return 'Please enter a password.';
if (passwordField.value != value) if (passwordField.value != value)
return 'Passwords don\'t match'; return 'The passwords don\'t match';
return null; return null;
} }
...@@ -118,11 +173,16 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -118,11 +173,16 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
key: _formKey, key: _formKey,
autovalidate: _autovalidate, autovalidate: _autovalidate,
onWillPop: _warnUserAboutInvalidData, onWillPop: _warnUserAboutInvalidData,
child: new ListView( child: new SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
const SizedBox(height: 24.0),
new TextFormField( new TextFormField(
decoration: const InputDecoration( decoration: const InputDecoration(
border: const UnderlineInputBorder(),
filled: true,
icon: const Icon(Icons.person), icon: const Icon(Icons.person),
hintText: 'What do people call you?', hintText: 'What do people call you?',
labelText: 'Name *', labelText: 'Name *',
...@@ -130,12 +190,15 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -130,12 +190,15 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
onSaved: (String value) { person.name = value; }, onSaved: (String value) { person.name = value; },
validator: _validateName, validator: _validateName,
), ),
const SizedBox(height: 24.0),
new TextFormField( new TextFormField(
decoration: const InputDecoration( decoration: const InputDecoration(
border: const UnderlineInputBorder(),
filled: true,
icon: const Icon(Icons.phone), icon: const Icon(Icons.phone),
hintText: 'Where can we reach you?', hintText: 'Where can we reach you?',
labelText: 'Phone Number *', labelText: 'Phone Number *',
prefixText: '+1' prefixText: '+1',
), ),
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
onSaved: (String value) { person.phoneNumber = value; }, onSaved: (String value) { person.phoneNumber = value; },
...@@ -147,8 +210,11 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -147,8 +210,11 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
_phoneNumberFormatter, _phoneNumberFormatter,
], ],
), ),
const SizedBox(height: 24.0),
new TextFormField( new TextFormField(
decoration: const InputDecoration( decoration: const InputDecoration(
border: const UnderlineInputBorder(),
filled: true,
icon: const Icon(Icons.email), icon: const Icon(Icons.email),
hintText: 'Your email address', hintText: 'Your email address',
labelText: 'E-mail', labelText: 'E-mail',
...@@ -156,17 +222,21 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -156,17 +222,21 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
keyboardType: TextInputType.emailAddress, keyboardType: TextInputType.emailAddress,
onSaved: (String value) { person.email = value; }, onSaved: (String value) { person.email = value; },
), ),
const SizedBox(height: 24.0),
new TextFormField( new TextFormField(
decoration: const InputDecoration( decoration: const InputDecoration(
border: const OutlineInputBorder(),
hintText: 'Tell us about yourself', hintText: 'Tell us about yourself',
helperText: 'Keep it short, this is just a demo', helperText: 'Keep it short, this is just a demo.',
labelText: 'Life story', labelText: 'Life story',
), ),
maxLines: 3, maxLines: 3,
), ),
const SizedBox(height: 24.0),
new TextFormField( new TextFormField(
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
decoration: const InputDecoration( decoration: const InputDecoration(
border: const OutlineInputBorder(),
labelText: 'Salary', labelText: 'Salary',
prefixText: '\$', prefixText: '\$',
suffixText: 'USD', suffixText: 'USD',
...@@ -174,50 +244,43 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -174,50 +244,43 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
), ),
maxLines: 1, maxLines: 1,
), ),
new Row( const SizedBox(height: 24.0),
crossAxisAlignment: CrossAxisAlignment.start, new PasswordField(
children: <Widget>[ fieldKey: _passwordFieldKey,
new Expanded( helperText: 'No more than 8 characters.',
child: new TextFormField( labelText: 'Password *',
key: _passwordFieldKey,
decoration: const InputDecoration(
hintText: 'How do you log in?',
labelText: 'New Password *',
),
obscureText: true,
onSaved: (String value) { person.password = value; }, onSaved: (String value) { person.password = value; },
), ),
), const SizedBox(height: 24.0),
const SizedBox(width: 16.0), new TextFormField(
new Expanded(
child: new TextFormField(
decoration: const InputDecoration( decoration: const InputDecoration(
hintText: 'How do you log in?', border: const UnderlineInputBorder(),
labelText: 'Re-type Password *', filled: true,
labelText: 'Re-type password',
), ),
maxLength: 8,
onFieldSubmitted: (String value) { person.password = value; },
obscureText: true, obscureText: true,
onFieldSubmitted: (String value) { _handleSubmitted(); },
validator: _validatePassword, validator: _validatePassword,
), ),
), const SizedBox(height: 24.0),
], new Center(
),
new Container(
padding: const EdgeInsets.all(20.0),
alignment: Alignment.center,
child: new RaisedButton( child: new RaisedButton(
child: const Text('SUBMIT'), child: const Text('SUBMIT'),
onPressed: _handleSubmitted, onPressed: _handleSubmitted,
), ),
), ),
new Container( const SizedBox(height: 24.0),
padding: const EdgeInsets.only(top: 20.0), new Text(
child: new Text('* indicates required field', style: Theme.of(context).textTheme.caption), '* indicates required field',
style: Theme.of(context).textTheme.caption
), ),
const SizedBox(height: 24.0),
], ],
), ),
), ),
), ),
),
); );
} }
} }
......
...@@ -16,21 +16,36 @@ void main() { ...@@ -16,21 +16,36 @@ void main() {
final Finder nameField = find.widgetWithText(TextFormField, 'Name *'); final Finder nameField = find.widgetWithText(TextFormField, 'Name *');
expect(nameField, findsOneWidget); expect(nameField, findsOneWidget);
final Finder passwordField = find.widgetWithText(TextFormField, 'Password *');
expect(passwordField, findsOneWidget);
await tester.enterText(nameField, ''); await tester.enterText(nameField, '');
// The submit button isn't initially visible. Drag it into view so that
// it will see the tap.
await tester.drag(nameField, const Offset(0.0, -1200.0));
await tester.pumpAndSettle();
await tester.tap(submitButton); await tester.tap(submitButton);
await tester.pump(); await tester.pumpAndSettle();
// Now drag the password field (the submit button will be obscured by
// the snackbar) and expose the name field again.
await tester.drag(passwordField, const Offset(0.0, 1200.0));
await tester.pumpAndSettle();
expect(find.text('Name is required.'), findsOneWidget); expect(find.text('Name is required.'), findsOneWidget);
expect(find.text('Please enter only alphabetical characters.'), findsNothing); expect(find.text('Please enter only alphabetical characters.'), findsNothing);
await tester.enterText(nameField, '#'); await tester.enterText(nameField, '#');
// Make the submit button visible again (by dragging the name field), so
// it will see the tap.
await tester.drag(nameField, const Offset(0.0, -1200.0));
await tester.tap(submitButton); await tester.tap(submitButton);
await tester.pump(); await tester.pumpAndSettle();
expect(find.text('Name is required.'), findsNothing); expect(find.text('Name is required.'), findsNothing);
expect(find.text('Please enter only alphabetical characters.'), findsOneWidget); expect(find.text('Please enter only alphabetical characters.'), findsOneWidget);
await tester.enterText(nameField, 'Jane Doe'); await tester.enterText(nameField, 'Jane Doe');
await tester.tap(submitButton); await tester.tap(submitButton);
await tester.pump(); await tester.pumpAndSettle();
expect(find.text('Name is required.'), findsNothing); expect(find.text('Name is required.'), findsNothing);
expect(find.text('Please enter only alphabetical characters.'), findsNothing); expect(find.text('Please enter only alphabetical characters.'), findsNothing);
}); });
......
...@@ -60,7 +60,9 @@ class TextFormField extends FormField<String> { ...@@ -60,7 +60,9 @@ class TextFormField extends FormField<String> {
bool autofocus: false, bool autofocus: false,
bool obscureText: false, bool obscureText: false,
bool autocorrect: true, bool autocorrect: true,
bool maxLengthEnforced: true,
int maxLines: 1, int maxLines: 1,
int maxLength,
ValueChanged<String> onFieldSubmitted, ValueChanged<String> onFieldSubmitted,
FormFieldSetter<String> onSaved, FormFieldSetter<String> onSaved,
FormFieldValidator<String> validator, FormFieldValidator<String> validator,
...@@ -71,7 +73,9 @@ class TextFormField extends FormField<String> { ...@@ -71,7 +73,9 @@ class TextFormField extends FormField<String> {
assert(autofocus != null), assert(autofocus != null),
assert(obscureText != null), assert(obscureText != null),
assert(autocorrect != null), assert(autocorrect != null),
assert(maxLengthEnforced != null),
assert(maxLines == null || maxLines > 0), assert(maxLines == null || maxLines > 0),
assert(maxLength == null || maxLength > 0),
super( super(
key: key, key: key,
initialValue: controller != null ? controller.text : (initialValue ?? ''), initialValue: controller != null ? controller.text : (initialValue ?? ''),
...@@ -91,7 +95,9 @@ class TextFormField extends FormField<String> { ...@@ -91,7 +95,9 @@ class TextFormField extends FormField<String> {
autofocus: autofocus, autofocus: autofocus,
obscureText: obscureText, obscureText: obscureText,
autocorrect: autocorrect, autocorrect: autocorrect,
maxLengthEnforced: maxLengthEnforced,
maxLines: maxLines, maxLines: maxLines,
maxLength: maxLength,
onChanged: field.onChanged, onChanged: field.onChanged,
onSubmitted: onFieldSubmitted, onSubmitted: onFieldSubmitted,
inputFormatters: inputFormatters, inputFormatters: inputFormatters,
......
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