mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-26 10:33:15 +03:00
Add visibility icon to fields with obscureText
This commit is contained in:
parent
fa92927f13
commit
613d05fbb2
@ -48,6 +48,9 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
String? _newPinError;
|
||||
bool _currentIsWrong = false;
|
||||
bool _newIsWrong = false;
|
||||
bool _isObscureCurrent = true;
|
||||
bool _isObscureNew = true;
|
||||
bool _isObscureConfirm = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -76,7 +79,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
AppTextFormField(
|
||||
initialValue: _currentPin,
|
||||
autofocus: true,
|
||||
obscureText: true,
|
||||
obscureText: _isObscureCurrent,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
@ -84,8 +87,30 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
errorText: _currentIsWrong ? _currentPinError : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.pin_outlined),
|
||||
suffixIcon: _currentIsWrong ? const Icon(Icons.error) : null,
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscureCurrent
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureCurrent = !_isObscureCurrent;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureCurrent
|
||||
? l10n.s_show_pin
|
||||
: l10n.s_hide_pin,
|
||||
),
|
||||
if (_currentIsWrong) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
)),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_currentIsWrong = false;
|
||||
@ -99,7 +124,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
AppTextFormField(
|
||||
initialValue: _newPin,
|
||||
autofocus: !hasPin,
|
||||
obscureText: true,
|
||||
obscureText: _isObscureNew,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
@ -108,7 +133,28 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
errorText: _newIsWrong ? _newPinError : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.pin_outlined),
|
||||
suffixIcon: _newIsWrong ? const Icon(Icons.error) : null,
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip:
|
||||
_isObscureNew ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
if (_newIsWrong) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
]),
|
||||
),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
@ -119,12 +165,29 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
),
|
||||
AppTextFormField(
|
||||
initialValue: _confirmPin,
|
||||
obscureText: true,
|
||||
obscureText: _isObscureConfirm,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_confirm_pin,
|
||||
prefixIcon: const Icon(Icons.pin_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip:
|
||||
_isObscureConfirm ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
)
|
||||
],
|
||||
),
|
||||
enabled:
|
||||
(!hasPin || _currentPin.isNotEmpty) && _newPin.isNotEmpty,
|
||||
),
|
||||
|
@ -198,6 +198,8 @@
|
||||
"s_change_puk": "Change PUK",
|
||||
"s_show_pin": "Show PIN",
|
||||
"s_hide_pin": "Hide PIN",
|
||||
"s_show_puk": "Show PUK",
|
||||
"s_hide_puk": "Hide PUK",
|
||||
"s_current_pin": "Current PIN",
|
||||
"s_current_puk": "Current PUK",
|
||||
"s_new_pin": "New PIN",
|
||||
@ -295,6 +297,8 @@
|
||||
"s_management_key": "Management key",
|
||||
"s_current_management_key": "Current management key",
|
||||
"s_new_management_key": "New management key",
|
||||
"s_show_management_key": "Show management key",
|
||||
"s_hide_management_key": "Hide management key",
|
||||
"l_change_management_key": "Change management key",
|
||||
"p_change_management_key_desc": "Change your management key. You can optionally choose to allow the PIN to be used instead of the management key.",
|
||||
"l_management_key_changed": "Management key changed",
|
||||
|
@ -42,6 +42,9 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
String _newPassword = '';
|
||||
String _confirmPassword = '';
|
||||
bool _currentIsWrong = false;
|
||||
bool _isObscureCurrent = true;
|
||||
bool _isObscureNew = true;
|
||||
bool _isObscureConfirm = true;
|
||||
|
||||
_submit() async {
|
||||
FocusUtils.unfocus(context);
|
||||
@ -85,7 +88,7 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
Text(l10n.p_enter_current_password_or_reset),
|
||||
AppTextField(
|
||||
autofocus: true,
|
||||
obscureText: true,
|
||||
obscureText: _isObscureCurrent,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
key: keys.currentPasswordField,
|
||||
decoration: InputDecoration(
|
||||
@ -94,8 +97,29 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
errorText: _currentIsWrong ? l10n.s_wrong_password : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: _currentIsWrong ? const Icon(Icons.error) : null,
|
||||
),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscureCurrent
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureCurrent = !_isObscureCurrent;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureCurrent
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
if (_currentIsWrong) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
)),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
@ -147,12 +171,28 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
AppTextField(
|
||||
key: keys.newPasswordField,
|
||||
autofocus: !widget.state.hasKey,
|
||||
obscureText: true,
|
||||
obscureText: _isObscureNew,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_new_password,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureNew
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
]),
|
||||
enabled: !widget.state.hasKey || _currentPassword.isNotEmpty,
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
@ -169,12 +209,29 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
),
|
||||
AppTextField(
|
||||
key: keys.confirmPasswordField,
|
||||
obscureText: true,
|
||||
obscureText: _isObscureConfirm,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_confirm_password,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureConfirm
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password)
|
||||
],
|
||||
),
|
||||
enabled:
|
||||
(!widget.state.hasKey || _currentPassword.isNotEmpty) &&
|
||||
_newPassword.isNotEmpty,
|
||||
|
@ -51,6 +51,7 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
String _password = '';
|
||||
bool _passwordIsWrong = false;
|
||||
bool _importing = false;
|
||||
bool _isObscure = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -125,7 +126,7 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
Text(l10n.p_password_protected_file),
|
||||
AppTextField(
|
||||
autofocus: true,
|
||||
obscureText: true,
|
||||
obscureText: _isObscure,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
key: keys.managementKeyField,
|
||||
decoration: InputDecoration(
|
||||
@ -134,7 +135,28 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
errorText: _passwordIsWrong ? l10n.s_wrong_password : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: _passwordIsWrong ? const Icon(Icons.error) : null,
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscure
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
if (_passwordIsWrong) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
]),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
|
@ -55,6 +55,7 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
ManagementKeyType _keyType = ManagementKeyType.tdes;
|
||||
final _currentController = TextEditingController();
|
||||
final _keyController = TextEditingController();
|
||||
bool _isObscure = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -167,7 +168,7 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
if (protected)
|
||||
AppTextField(
|
||||
autofocus: true,
|
||||
obscureText: true,
|
||||
obscureText: _isObscure,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
key: keys.pinPukField,
|
||||
maxLength: 8,
|
||||
@ -183,9 +184,27 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
: null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.pin_outlined),
|
||||
suffixIcon: _currentIsWrong || _currentInvalidFormat
|
||||
? const Icon(Icons.error)
|
||||
: null,
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscure
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip:
|
||||
_isObscure ? l10n.s_show_pin : l10n.s_hide_pin),
|
||||
if (_currentIsWrong || _currentInvalidFormat) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
]),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
|
@ -44,6 +44,9 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
String _confirmPin = '';
|
||||
bool _currentIsWrong = false;
|
||||
int _attemptsRemaining = -1;
|
||||
bool _isObscureCurrent = true;
|
||||
bool _isObscureNew = true;
|
||||
bool _isObscureConfirm = true;
|
||||
|
||||
_submit() async {
|
||||
final notifier = ref.read(pivStateProvider(widget.path).notifier);
|
||||
@ -104,7 +107,7 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
: l10n.p_enter_current_puk_or_reset),
|
||||
AppTextField(
|
||||
autofocus: true,
|
||||
obscureText: true,
|
||||
obscureText: _isObscureCurrent,
|
||||
maxLength: 8,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
key: keys.pinPukField,
|
||||
@ -115,15 +118,41 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
: l10n.s_current_puk,
|
||||
errorText: _currentIsWrong
|
||||
? (widget.target == ManageTarget.pin
|
||||
? l10n
|
||||
.l_wrong_pin_attempts_remaining(_attemptsRemaining)
|
||||
: l10n
|
||||
.l_wrong_puk_attempts_remaining(_attemptsRemaining))
|
||||
? l10n.l_wrong_pin_attempts_remaining(
|
||||
_attemptsRemaining)
|
||||
: l10n.l_wrong_puk_attempts_remaining(
|
||||
_attemptsRemaining))
|
||||
: null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: _currentIsWrong ? const Icon(Icons.error) : null,
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscureCurrent
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureCurrent = !_isObscureCurrent;
|
||||
});
|
||||
},
|
||||
tooltip: widget.target == ManageTarget.pin
|
||||
? (_isObscureCurrent
|
||||
? l10n.s_show_pin
|
||||
: l10n.s_hide_pin)
|
||||
: (_isObscureCurrent
|
||||
? l10n.s_show_puk
|
||||
: l10n.s_hide_puk),
|
||||
),
|
||||
if (_currentIsWrong) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
)),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
@ -136,7 +165,7 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
widget.target == ManageTarget.puk ? l10n.s_puk : l10n.s_pin)),
|
||||
AppTextField(
|
||||
key: keys.newPinPukField,
|
||||
obscureText: true,
|
||||
obscureText: _isObscureNew,
|
||||
maxLength: 8,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: InputDecoration(
|
||||
@ -145,6 +174,27 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
? l10n.s_new_puk
|
||||
: l10n.s_new_pin,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: widget.target == ManageTarget.pin
|
||||
? (_isObscureNew
|
||||
? l10n.s_show_pin
|
||||
: l10n.s_hide_pin)
|
||||
: (_isObscureNew
|
||||
? l10n.s_show_puk
|
||||
: l10n.s_hide_puk),
|
||||
),
|
||||
]),
|
||||
// Old YubiKeys allowed a 4 digit PIN
|
||||
enabled: _currentPin.length >= 4,
|
||||
),
|
||||
@ -162,7 +212,7 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
),
|
||||
AppTextField(
|
||||
key: keys.confirmPinPukField,
|
||||
obscureText: true,
|
||||
obscureText: _isObscureConfirm,
|
||||
maxLength: 8,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: InputDecoration(
|
||||
@ -171,6 +221,27 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
? l10n.s_confirm_puk
|
||||
: l10n.s_confirm_pin,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip: widget.target == ManageTarget.pin
|
||||
? (_isObscureConfirm
|
||||
? l10n.s_show_pin
|
||||
: l10n.s_hide_pin)
|
||||
: (_isObscureConfirm
|
||||
? l10n.s_show_puk
|
||||
: l10n.s_hide_puk),
|
||||
)
|
||||
]),
|
||||
enabled: _currentPin.length >= 4 && _newPin.length >= 6,
|
||||
),
|
||||
textInputAction: TextInputAction.done,
|
||||
|
Loading…
Reference in New Issue
Block a user