Fix password auto-fill suggestion

This commit is contained in:
Neeraj Gupta 2022-07-14 18:58:37 +05:30
parent 3b9d4d3643
commit e33cc392b7
No known key found for this signature in database
GPG key ID: 3C5A1684DC1729E1
2 changed files with 249 additions and 227 deletions

View file

@ -70,136 +70,138 @@ class _LoginPageState extends State<LoginPage> {
return Column(
children: [
Expanded(
child: ListView(
children: [
Padding(
padding:
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Text(
'Welcome back!',
style: Theme.of(context).textTheme.headline4,
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 24, 20, 0),
child: TextFormField(
autofillHints: const [AutofillHints.email],
decoration: InputDecoration(
fillColor: _emailInputFieldColor,
filled: true,
hintText: 'Email',
contentPadding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 15,
),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(6),
),
suffixIcon: _emailIsValid
? Icon(
Icons.check,
size: 20,
color: Theme.of(context)
.inputDecorationTheme
.focusedBorder
.borderSide
.color,
)
: null,
child: AutofillGroup(
child: ListView(
children: [
Padding(
padding:
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Text(
'Welcome back!',
style: Theme.of(context).textTheme.headline4,
),
onChanged: (value) {
setState(() {
_email = value.trim();
_emailIsValid = EmailValidator.validate(_email);
if (_emailIsValid) {
_emailInputFieldColor =
const Color.fromRGBO(45, 194, 98, 0.2);
} else {
_emailInputFieldColor = null;
}
});
},
autocorrect: false,
keyboardType: TextInputType.emailAddress,
//initialValue: _email,
autofocus: true,
),
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 18),
child: Divider(
thickness: 1,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
Expanded(
flex: 5,
child: RichText(
text: TextSpan(
style: Theme.of(context)
.textTheme
.subtitle1
.copyWith(fontSize: 12),
children: [
const TextSpan(
text: "By clicking log in, I agree to the ",
),
TextSpan(
text: "terms of service",
style: const TextStyle(
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"terms",
"https://ente.io/terms",
);
},
),
);
},
),
const TextSpan(text: " and "),
TextSpan(
text: "privacy policy",
style: const TextStyle(
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"privacy",
"https://ente.io/privacy",
);
},
),
);
},
),
],
),
textAlign: TextAlign.left,
Padding(
padding: const EdgeInsets.fromLTRB(20, 24, 20, 0),
child: TextFormField(
autofillHints: const [AutofillHints.email],
decoration: InputDecoration(
fillColor: _emailInputFieldColor,
filled: true,
hintText: 'Email',
contentPadding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 15,
),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(6),
),
suffixIcon: _emailIsValid
? Icon(
Icons.check,
size: 20,
color: Theme.of(context)
.inputDecorationTheme
.focusedBorder
.borderSide
.color,
)
: null,
),
Expanded(
flex: 2,
child: Container(),
)
],
onChanged: (value) {
setState(() {
_email = value.trim();
_emailIsValid = EmailValidator.validate(_email);
if (_emailIsValid) {
_emailInputFieldColor =
const Color.fromRGBO(45, 194, 98, 0.2);
} else {
_emailInputFieldColor = null;
}
});
},
autocorrect: false,
keyboardType: TextInputType.emailAddress,
//initialValue: _email,
autofocus: true,
),
),
),
],
const Padding(
padding: EdgeInsets.symmetric(vertical: 18),
child: Divider(
thickness: 1,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
Expanded(
flex: 5,
child: RichText(
text: TextSpan(
style: Theme.of(context)
.textTheme
.subtitle1
.copyWith(fontSize: 12),
children: [
const TextSpan(
text: "By clicking log in, I agree to the ",
),
TextSpan(
text: "terms of service",
style: const TextStyle(
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"terms",
"https://ente.io/terms",
);
},
),
);
},
),
const TextSpan(text: " and "),
TextSpan(
text: "privacy policy",
style: const TextStyle(
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const WebPage(
"privacy",
"https://ente.io/privacy",
);
},
),
);
},
),
],
),
textAlign: TextAlign.left,
),
),
Expanded(
flex: 2,
child: Container(),
)
],
),
),
],
),
),
),
const Padding(padding: EdgeInsets.all(8)),

View file

@ -18,12 +18,14 @@ class PasswordReentryPage extends StatefulWidget {
class _PasswordReentryPageState extends State<PasswordReentryPage> {
final _passwordController = TextEditingController();
final FocusNode _passwordFocusNode = FocusNode();
String email;
bool _passwordInFocus = false;
bool _passwordVisible = false;
@override
void initState() {
super.initState();
email = Configuration.instance.getEmail();
_passwordFocusNode.addListener(() {
setState(() {
_passwordInFocus = _passwordFocusNode.hasFocus;
@ -96,116 +98,134 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
return Column(
children: [
Expanded(
child: ListView(
children: [
Padding(
padding:
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Text(
'Welcome back!',
style: Theme.of(context).textTheme.headline4,
child: AutofillGroup(
child: ListView(
children: [
Padding(
padding:
const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Text(
'Welcome back!',
style: Theme.of(context).textTheme.headline4,
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 24, 20, 0),
child: TextFormField(
autofillHints: const [AutofillHints.password],
decoration: InputDecoration(
hintText: "Enter your password",
filled: true,
contentPadding: const EdgeInsets.all(20),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(6),
Visibility(
// hidden textForm for suggesting auto-fill service for saving
// password
visible: false,
child: TextFormField(
autofillHints: const [
AutofillHints.email,
],
autocorrect: false,
keyboardType: TextInputType.emailAddress,
initialValue: email,
textInputAction: TextInputAction.next,
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 24, 20, 0),
child: TextFormField(
autofillHints: const [AutofillHints.password],
decoration: InputDecoration(
hintText: "Enter your password",
filled: true,
contentPadding: const EdgeInsets.all(20),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(6),
),
suffixIcon: _passwordInFocus
? IconButton(
icon: Icon(
_passwordVisible
? Icons.visibility
: Icons.visibility_off,
color: Theme.of(context).iconTheme.color,
size: 20,
),
onPressed: () {
setState(() {
_passwordVisible = !_passwordVisible;
});
},
)
: null,
),
suffixIcon: _passwordInFocus
? IconButton(
icon: Icon(
_passwordVisible
? Icons.visibility
: Icons.visibility_off,
color: Theme.of(context).iconTheme.color,
size: 20,
style: const TextStyle(
fontSize: 14,
),
controller: _passwordController,
autofocus: true,
autocorrect: false,
obscureText: !_passwordVisible,
keyboardType: TextInputType.visiblePassword,
focusNode: _passwordFocusNode,
onChanged: (_) {
setState(() {});
},
),
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 18),
child: Divider(
thickness: 1,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const RecoveryPage();
},
),
onPressed: () {
setState(() {
_passwordVisible = !_passwordVisible;
});
},
)
: null,
),
style: const TextStyle(
fontSize: 14,
),
controller: _passwordController,
autofocus: true,
autocorrect: false,
obscureText: !_passwordVisible,
keyboardType: TextInputType.visiblePassword,
focusNode: _passwordFocusNode,
onChanged: (_) {
setState(() {});
},
),
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 18),
child: Divider(
thickness: 1,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return const RecoveryPage();
},
);
},
child: Center(
child: Text(
"Forgot password",
style:
Theme.of(context).textTheme.subtitle1.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
),
);
},
child: Center(
child: Text(
"Forgot password",
style: Theme.of(context).textTheme.subtitle1.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
final dialog =
createProgressDialog(context, "Please wait...");
await dialog.show();
await Configuration.instance.logout();
await dialog.hide();
Navigator.of(context)
.popUntil((route) => route.isFirst);
},
child: Center(
child: Text(
"Change email",
style: Theme.of(context).textTheme.subtitle1.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
final dialog =
createProgressDialog(context, "Please wait...");
await dialog.show();
await Configuration.instance.logout();
await dialog.hide();
Navigator.of(context)
.popUntil((route) => route.isFirst);
},
child: Center(
child: Text(
"Change email",
style:
Theme.of(context).textTheme.subtitle1.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
),
),
),
),
],
),
)
],
],
),
)
],
),
),
),
],