mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 23:42:00 +01:00
Add autofill group to fields in auth screen
This commit is contained in:
@@ -177,163 +177,165 @@ class _AuthCardState extends State<AuthCard> {
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
TextFormField(
|
||||
key: Key('inputUsername'),
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.username),
|
||||
autofillHints: [AutofillHints.username],
|
||||
controller: _usernameController,
|
||||
textInputAction: TextInputAction.next,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
validator: (value) {
|
||||
if (value!.isEmpty) {
|
||||
return AppLocalizations.of(context)!.invalidUsername;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSaved: (value) {
|
||||
_authData['username'] = value!;
|
||||
},
|
||||
),
|
||||
if (_authMode == AuthMode.Signup)
|
||||
child: AutofillGroup(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
TextFormField(
|
||||
key: Key('inputEmail'),
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.email),
|
||||
autofillHints: [AutofillHints.email],
|
||||
controller: _emailController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
key: Key('inputUsername'),
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.username),
|
||||
autofillHints: [AutofillHints.username],
|
||||
controller: _usernameController,
|
||||
textInputAction: TextInputAction.next,
|
||||
|
||||
// Email is not required
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
validator: (value) {
|
||||
if (value!.isNotEmpty && !value.contains('@')) {
|
||||
return AppLocalizations.of(context)!.invalidEmail;
|
||||
if (value!.isEmpty) {
|
||||
return AppLocalizations.of(context)!.invalidUsername;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSaved: (value) {
|
||||
_authData['email'] = value!;
|
||||
_authData['username'] = value!;
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
key: Key('inputPassword'),
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.password),
|
||||
autofillHints: [AutofillHints.password],
|
||||
obscureText: true,
|
||||
controller: _passwordController,
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value!.isEmpty || value.length < 8) {
|
||||
return AppLocalizations.of(context)!.passwordTooShort;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSaved: (value) {
|
||||
_authData['password'] = value!;
|
||||
},
|
||||
),
|
||||
if (_authMode == AuthMode.Signup)
|
||||
TextFormField(
|
||||
key: Key('inputPassword2'),
|
||||
decoration:
|
||||
InputDecoration(labelText: AppLocalizations.of(context)!.confirmPassword),
|
||||
controller: _password2Controller,
|
||||
enabled: _authMode == AuthMode.Signup,
|
||||
obscureText: true,
|
||||
validator: _authMode == AuthMode.Signup
|
||||
? (value) {
|
||||
if (value != _passwordController.text) {
|
||||
return AppLocalizations.of(context)!.passwordsDontMatch;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
: null,
|
||||
),
|
||||
// Off-stage widgets are kept in the tree, otherwise the server URL
|
||||
// would not be saved to _authData
|
||||
Offstage(
|
||||
offstage: _hideCustomServer,
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: TextFormField(
|
||||
key: Key('inputServer'),
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context)!.customServerUrl,
|
||||
helperText: AppLocalizations.of(context)!.customServerHint,
|
||||
helperMaxLines: 4),
|
||||
controller: _serverUrlController,
|
||||
validator: (value) {
|
||||
if (Uri.tryParse(value!) == null) {
|
||||
return AppLocalizations.of(context)!.invalidUrl;
|
||||
}
|
||||
if (_authMode == AuthMode.Signup)
|
||||
TextFormField(
|
||||
key: Key('inputEmail'),
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.email),
|
||||
autofillHints: [AutofillHints.email],
|
||||
controller: _emailController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
textInputAction: TextInputAction.next,
|
||||
|
||||
if (value.isEmpty || !value.contains('http')) {
|
||||
return AppLocalizations.of(context)!.invalidUrl;
|
||||
// Email is not required
|
||||
validator: (value) {
|
||||
if (value!.isNotEmpty && !value.contains('@')) {
|
||||
return AppLocalizations.of(context)!.invalidEmail;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSaved: (value) {
|
||||
_authData['email'] = value!;
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
key: Key('inputPassword'),
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.password),
|
||||
autofillHints: [AutofillHints.password],
|
||||
obscureText: true,
|
||||
controller: _passwordController,
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value!.isEmpty || value.length < 8) {
|
||||
return AppLocalizations.of(context)!.passwordTooShort;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSaved: (value) {
|
||||
_authData['password'] = value!;
|
||||
},
|
||||
),
|
||||
if (_authMode == AuthMode.Signup)
|
||||
TextFormField(
|
||||
key: Key('inputPassword2'),
|
||||
decoration:
|
||||
InputDecoration(labelText: AppLocalizations.of(context)!.confirmPassword),
|
||||
controller: _password2Controller,
|
||||
enabled: _authMode == AuthMode.Signup,
|
||||
obscureText: true,
|
||||
validator: _authMode == AuthMode.Signup
|
||||
? (value) {
|
||||
if (value != _passwordController.text) {
|
||||
return AppLocalizations.of(context)!.passwordsDontMatch;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSaved: (value) {
|
||||
_authData['serverUrl'] = value!;
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
IconButton(
|
||||
icon: const Icon(Icons.undo),
|
||||
onPressed: () {
|
||||
_serverUrlController.text = DEFAULT_SERVER;
|
||||
: null,
|
||||
),
|
||||
// Off-stage widgets are kept in the tree, otherwise the server URL
|
||||
// would not be saved to _authData
|
||||
Offstage(
|
||||
offstage: _hideCustomServer,
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: TextFormField(
|
||||
key: Key('inputServer'),
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context)!.customServerUrl,
|
||||
helperText: AppLocalizations.of(context)!.customServerHint,
|
||||
helperMaxLines: 4),
|
||||
controller: _serverUrlController,
|
||||
validator: (value) {
|
||||
if (Uri.tryParse(value!) == null) {
|
||||
return AppLocalizations.of(context)!.invalidUrl;
|
||||
}
|
||||
|
||||
if (value.isEmpty || !value.contains('http')) {
|
||||
return AppLocalizations.of(context)!.invalidUrl;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSaved: (value) {
|
||||
_authData['serverUrl'] = value!;
|
||||
},
|
||||
),
|
||||
Text(AppLocalizations.of(context)!.reset)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
IconButton(
|
||||
icon: const Icon(Icons.undo),
|
||||
onPressed: () {
|
||||
_serverUrlController.text = DEFAULT_SERVER;
|
||||
},
|
||||
),
|
||||
Text(AppLocalizations.of(context)!.reset)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
if (_isLoading)
|
||||
CircularProgressIndicator()
|
||||
else
|
||||
ElevatedButton(
|
||||
key: Key('actionButton'),
|
||||
child: Text(_authMode == AuthMode.Login
|
||||
? AppLocalizations.of(context)!.login
|
||||
: AppLocalizations.of(context)!.register),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
if (_isLoading)
|
||||
CircularProgressIndicator()
|
||||
else
|
||||
ElevatedButton(
|
||||
key: Key('actionButton'),
|
||||
child: Text(_authMode == AuthMode.Login
|
||||
? AppLocalizations.of(context)!.login
|
||||
: AppLocalizations.of(context)!.register),
|
||||
onPressed: () {
|
||||
return _submit(context);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
key: Key('toggleActionButton'),
|
||||
child: Text(
|
||||
_authMode == AuthMode.Login
|
||||
? AppLocalizations.of(context)!.registerInstead.toUpperCase()
|
||||
: AppLocalizations.of(context)!.loginInstead.toUpperCase(),
|
||||
),
|
||||
onPressed: _switchAuthMode,
|
||||
),
|
||||
TextButton(
|
||||
child: Text(_hideCustomServer
|
||||
? AppLocalizations.of(context)!.useCustomServer
|
||||
: AppLocalizations.of(context)!.useDefaultServer),
|
||||
key: Key('toggleCustomServerButton'),
|
||||
onPressed: () {
|
||||
return _submit(context);
|
||||
setState(() {
|
||||
_hideCustomServer = !_hideCustomServer;
|
||||
});
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
key: Key('toggleActionButton'),
|
||||
child: Text(
|
||||
_authMode == AuthMode.Login
|
||||
? AppLocalizations.of(context)!.registerInstead.toUpperCase()
|
||||
: AppLocalizations.of(context)!.loginInstead.toUpperCase(),
|
||||
),
|
||||
onPressed: _switchAuthMode,
|
||||
),
|
||||
TextButton(
|
||||
child: Text(_hideCustomServer
|
||||
? AppLocalizations.of(context)!.useCustomServer
|
||||
: AppLocalizations.of(context)!.useDefaultServer),
|
||||
key: Key('toggleCustomServerButton'),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_hideCustomServer = !_hideCustomServer;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user