mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-23 10:11:52 +03:00
Add AppInputDecoration
.
This commit is contained in:
parent
ce5b8abe81
commit
dc5d3ce9dc
@ -166,36 +166,23 @@ class _PinEntryFormState extends ConsumerState<_PinEntryForm> {
|
||||
obscureText: _isObscure,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
controller: _pinController,
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_pin,
|
||||
helperText: '', // Prevents dialog resizing
|
||||
errorText: _pinIsWrong ? _getErrorText() : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.pin_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_isObscure ? Icons.visibility : Icons.visibility_off,
|
||||
color: !_pinIsWrong
|
||||
? IconTheme.of(context).color
|
||||
: null),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
if (_pinIsWrong) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_isObscure ? Icons.visibility : Icons.visibility_off,
|
||||
color: !_pinIsWrong ? IconTheme.of(context).color : null),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
),
|
||||
onChanged: (value) {
|
||||
|
@ -363,7 +363,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
limitBytesLength(issuerRemaining),
|
||||
],
|
||||
buildCounter: buildByteCounterFor(issuerText),
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_issuer_optional,
|
||||
helperText:
|
||||
@ -395,7 +395,7 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
maxLength: nameMaxLength,
|
||||
buildCounter: buildByteCounterFor(nameText),
|
||||
inputFormatters: [limitBytesLength(nameRemaining)],
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_account_name,
|
||||
helperText: '',
|
||||
@ -429,45 +429,33 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
// would hint to use saved passwords for this field
|
||||
autofillHints:
|
||||
isAndroid ? [] : const [AutofillHints.password],
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_secret_key,
|
||||
errorText: _validateSecret && !secretLengthValid
|
||||
? l10n.s_invalid_length
|
||||
: _validateSecret && !secretFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.base32.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_isObscure
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
color: !_validateSecret
|
||||
? IconTheme.of(context).color
|
||||
: null),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure
|
||||
? l10n.s_show_secret_key
|
||||
: l10n.s_hide_secret_key,
|
||||
),
|
||||
if (_validateSecret) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_secret_key,
|
||||
errorText: _validateSecret && !secretLengthValid
|
||||
? l10n.s_invalid_length
|
||||
: _validateSecret && !secretFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.base32.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_isObscure
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
color: !_validateSecret
|
||||
? IconTheme.of(context).color
|
||||
: null),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure
|
||||
? l10n.s_show_secret_key
|
||||
: l10n.s_hide_secret_key,
|
||||
)),
|
||||
readOnly: _dataLoaded,
|
||||
textInputAction: TextInputAction.done,
|
||||
onChanged: (value) {
|
||||
|
@ -91,35 +91,25 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
obscureText: _isObscureCurrent,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
key: keys.currentPasswordField,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_current_password,
|
||||
errorText: _currentIsWrong ? l10n.s_wrong_password : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
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,
|
||||
)
|
||||
]
|
||||
],
|
||||
)),
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_current_password,
|
||||
errorText: _currentIsWrong ? l10n.s_wrong_password : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_isObscureCurrent
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureCurrent = !_isObscureCurrent;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureCurrent
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
@ -173,26 +163,22 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
autofocus: !widget.state.hasKey,
|
||||
obscureText: _isObscureNew,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
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),
|
||||
]),
|
||||
suffixIcon: 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,
|
||||
@ -211,27 +197,22 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
key: keys.confirmPasswordField,
|
||||
obscureText: _isObscureConfirm,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
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)
|
||||
],
|
||||
),
|
||||
suffixIcon: 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,
|
||||
|
@ -79,39 +79,26 @@ class _UnlockFormState extends ConsumerState<UnlockForm> {
|
||||
autofocus: true,
|
||||
obscureText: _isObscure,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_password,
|
||||
errorText: _passwordIsWrong ? l10n.s_wrong_password : null,
|
||||
helperText: '', // Prevents resizing when errorText shown
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_isObscure
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
color: !_passwordIsWrong
|
||||
? IconTheme.of(context).color
|
||||
: null),
|
||||
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,
|
||||
)
|
||||
]
|
||||
],
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_isObscure ? Icons.visibility : Icons.visibility_off,
|
||||
color: !_passwordIsWrong
|
||||
? IconTheme.of(context).color
|
||||
: null),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password,
|
||||
),
|
||||
),
|
||||
onChanged: (_) => setState(() {
|
||||
|
@ -129,46 +129,34 @@ class _ConfigureChalrespDialogState
|
||||
controller: _secretController,
|
||||
autofillHints: isAndroid ? [] : const [AutofillHints.password],
|
||||
maxLength: secretMaxLength,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_secret_key,
|
||||
errorText: _validateSecret && !secretLengthValid
|
||||
? l10n.s_invalid_length
|
||||
: _validateSecret && !secretFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.hex.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_secret_key,
|
||||
errorText: _validateSecret && !secretLengthValid
|
||||
? l10n.s_invalid_length
|
||||
: _validateSecret && !secretFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.hex.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
final random = Random.secure();
|
||||
final key = List.generate(
|
||||
20,
|
||||
(_) => random
|
||||
.nextInt(256)
|
||||
.toRadixString(16)
|
||||
.padLeft(2, '0')).join();
|
||||
setState(() {
|
||||
final random = Random.secure();
|
||||
final key = List.generate(
|
||||
20,
|
||||
(_) => random
|
||||
.nextInt(256)
|
||||
.toRadixString(16)
|
||||
.padLeft(2, '0')).join();
|
||||
setState(() {
|
||||
_secretController.text = key;
|
||||
});
|
||||
_secretController.text = key;
|
||||
});
|
||||
},
|
||||
tooltip: l10n.s_generate_random,
|
||||
),
|
||||
if (_validateSecret) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
});
|
||||
},
|
||||
tooltip: l10n.s_generate_random,
|
||||
)),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
|
@ -126,44 +126,32 @@ class _ConfigureHotpDialogState extends ConsumerState<ConfigureHotpDialog> {
|
||||
controller: _secretController,
|
||||
obscureText: _isObscure,
|
||||
autofillHints: isAndroid ? [] : const [AutofillHints.password],
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_secret_key,
|
||||
helperText: '', // Prevents resizing when errorText shown
|
||||
errorText: _validateSecret && !secretLengthValid
|
||||
? l10n.s_invalid_length
|
||||
: _validateSecret && !secretFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.base32.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_isObscure ? Icons.visibility : Icons.visibility_off,
|
||||
color: !_validateSecret
|
||||
? IconTheme.of(context).color
|
||||
: null),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure
|
||||
? l10n.s_show_secret_key
|
||||
: l10n.s_hide_secret_key,
|
||||
),
|
||||
if (_validateSecret) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_secret_key,
|
||||
helperText: '', // Prevents resizing when errorText shown
|
||||
errorText: _validateSecret && !secretLengthValid
|
||||
? l10n.s_invalid_length
|
||||
: _validateSecret && !secretFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.base32.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_isObscure ? Icons.visibility : Icons.visibility_off,
|
||||
color: !_validateSecret
|
||||
? IconTheme.of(context).color
|
||||
: null),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure
|
||||
? l10n.s_show_secret_key
|
||||
: l10n.s_hide_secret_key,
|
||||
)),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
|
@ -149,41 +149,29 @@ class _ConfigureStaticDialogState extends ConsumerState<ConfigureStaticDialog> {
|
||||
controller: _passwordController,
|
||||
autofillHints: isAndroid ? [] : const [AutofillHints.password],
|
||||
maxLength: passwordMaxLength,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_password,
|
||||
errorText: _validatePassword && !passwordLengthValid
|
||||
? l10n.s_invalid_length
|
||||
: _validatePassword && !passwordFormatValid
|
||||
? l10n.l_invalid_keyboard_character
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
tooltip: l10n.s_generate_passowrd,
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () async {
|
||||
final password = await ref
|
||||
.read(otpStateProvider(widget.devicePath).notifier)
|
||||
.generateStaticPassword(
|
||||
passwordMaxLength, _keyboardLayout);
|
||||
setState(() {
|
||||
_validatePassword = false;
|
||||
_passwordController.text = password;
|
||||
});
|
||||
},
|
||||
),
|
||||
if (_validatePassword) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_password,
|
||||
errorText: _validatePassword && !passwordLengthValid
|
||||
? l10n.s_invalid_length
|
||||
: _validatePassword && !passwordFormatValid
|
||||
? l10n.l_invalid_keyboard_character
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: IconButton(
|
||||
tooltip: l10n.s_generate_passowrd,
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () async {
|
||||
final password = await ref
|
||||
.read(otpStateProvider(widget.devicePath).notifier)
|
||||
.generateStaticPassword(
|
||||
passwordMaxLength, _keyboardLayout);
|
||||
setState(() {
|
||||
_validatePassword = false;
|
||||
_passwordController.text = password;
|
||||
});
|
||||
},
|
||||
)),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
|
@ -205,41 +205,29 @@ class _ConfigureYubiOtpDialogState
|
||||
controller: _publicIdController,
|
||||
autofillHints: isAndroid ? [] : const [AutofillHints.password],
|
||||
maxLength: publicIdLength,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_public_id,
|
||||
errorText: _validatePublicIdFormat && !publicIdFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.modhex.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.public_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
tooltip: l10n.s_use_serial,
|
||||
icon: const Icon(Icons.auto_awesome_outlined),
|
||||
onPressed: (info?.serial != null)
|
||||
? () async {
|
||||
final publicId = await ref
|
||||
.read(otpStateProvider(widget.devicePath)
|
||||
.notifier)
|
||||
.modhexEncodeSerial(info!.serial!);
|
||||
setState(() {
|
||||
_publicIdController.text = publicId;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
if (_validatePublicIdFormat) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_public_id,
|
||||
errorText: _validatePublicIdFormat && !publicIdFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.modhex.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.public_outlined),
|
||||
suffixIcon: IconButton(
|
||||
tooltip: l10n.s_use_serial,
|
||||
icon: const Icon(Icons.auto_awesome_outlined),
|
||||
onPressed: (info?.serial != null)
|
||||
? () async {
|
||||
final publicId = await ref
|
||||
.read(otpStateProvider(widget.devicePath)
|
||||
.notifier)
|
||||
.modhexEncodeSerial(info!.serial!);
|
||||
setState(() {
|
||||
_publicIdController.text = publicId;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
)),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
@ -252,42 +240,30 @@ class _ConfigureYubiOtpDialogState
|
||||
controller: _privateIdController,
|
||||
autofillHints: isAndroid ? [] : const [AutofillHints.password],
|
||||
maxLength: privateIdLength,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_private_id,
|
||||
errorText: _validatePrivateIdFormat && !privatedIdFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.hex.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
tooltip: l10n.s_generate_random,
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
final random = Random.secure();
|
||||
final key = List.generate(
|
||||
6,
|
||||
(_) => random
|
||||
.nextInt(256)
|
||||
.toRadixString(16)
|
||||
.padLeft(2, '0')).join();
|
||||
setState(() {
|
||||
_privateIdController.text = key;
|
||||
});
|
||||
},
|
||||
),
|
||||
if (_validatePrivateIdFormat) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_private_id,
|
||||
errorText: _validatePrivateIdFormat && !privatedIdFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.hex.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: IconButton(
|
||||
tooltip: l10n.s_generate_random,
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
final random = Random.secure();
|
||||
final key = List.generate(
|
||||
6,
|
||||
(_) => random
|
||||
.nextInt(256)
|
||||
.toRadixString(16)
|
||||
.padLeft(2, '0')).join();
|
||||
setState(() {
|
||||
_privateIdController.text = key;
|
||||
});
|
||||
},
|
||||
)),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
@ -300,42 +276,30 @@ class _ConfigureYubiOtpDialogState
|
||||
controller: _secretController,
|
||||
autofillHints: isAndroid ? [] : const [AutofillHints.password],
|
||||
maxLength: secretLength,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_secret_key,
|
||||
errorText: _validateSecretFormat && !secretFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.hex.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
tooltip: l10n.s_generate_random,
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
final random = Random.secure();
|
||||
final key = List.generate(
|
||||
16,
|
||||
(_) => random
|
||||
.nextInt(256)
|
||||
.toRadixString(16)
|
||||
.padLeft(2, '0')).join();
|
||||
setState(() {
|
||||
_secretController.text = key;
|
||||
});
|
||||
},
|
||||
),
|
||||
if (_validateSecretFormat) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_secret_key,
|
||||
errorText: _validateSecretFormat && !secretFormatValid
|
||||
? l10n.l_invalid_format_allowed_chars(
|
||||
Format.hex.allowedCharacters)
|
||||
: null,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: IconButton(
|
||||
tooltip: l10n.s_generate_random,
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
final random = Random.secure();
|
||||
final key = List.generate(
|
||||
16,
|
||||
(_) => random
|
||||
.nextInt(256)
|
||||
.toRadixString(16)
|
||||
.padLeft(2, '0')).join();
|
||||
setState(() {
|
||||
_secretController.text = key;
|
||||
});
|
||||
},
|
||||
)),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
|
@ -109,7 +109,7 @@ class _AuthenticationDialogState extends ConsumerState<AuthenticationDialog> {
|
||||
controller: _keyController,
|
||||
readOnly: _defaultKeyUsed,
|
||||
maxLength: !_defaultKeyUsed ? keyLen : null,
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_management_key,
|
||||
helperText: _defaultKeyUsed ? l10n.l_default_key_used : null,
|
||||
@ -125,34 +125,22 @@ class _AuthenticationDialogState extends ConsumerState<AuthenticationDialog> {
|
||||
? null
|
||||
: hasMetadata && (_keyIsWrong || _keyFormatInvalid)
|
||||
? const Icon(Icons.error)
|
||||
: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(_defaultKeyUsed
|
||||
? Icons.auto_awesome
|
||||
: Icons.auto_awesome_outlined),
|
||||
tooltip: l10n.s_use_default,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_keyFormatInvalid = false;
|
||||
_defaultKeyUsed = !_defaultKeyUsed;
|
||||
if (_defaultKeyUsed) {
|
||||
_keyController.text =
|
||||
defaultManagementKey;
|
||||
} else {
|
||||
_keyController.clear();
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
if (_keyIsWrong || _keyFormatInvalid) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
: IconButton(
|
||||
icon: Icon(_defaultKeyUsed
|
||||
? Icons.auto_awesome
|
||||
: Icons.auto_awesome_outlined),
|
||||
tooltip: l10n.s_use_default,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_keyFormatInvalid = false;
|
||||
_defaultKeyUsed = !_defaultKeyUsed;
|
||||
if (_defaultKeyUsed) {
|
||||
_keyController.text = defaultManagementKey;
|
||||
} else {
|
||||
_keyController.clear();
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
|
@ -161,7 +161,7 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
AppTextField(
|
||||
autofocus: true,
|
||||
key: keys.subjectField,
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_subject,
|
||||
errorText: _subject.isNotEmpty && _invalidSubject
|
||||
|
@ -129,34 +129,23 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
obscureText: _isObscure,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
key: keys.managementKeyField,
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_password,
|
||||
errorText: _passwordIsWrong ? l10n.s_wrong_password : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
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,
|
||||
)
|
||||
]
|
||||
]),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_isObscure ? Icons.visibility : Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
|
@ -173,7 +173,7 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
key: keys.pinPukField,
|
||||
maxLength: 8,
|
||||
controller: _currentController,
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_pin,
|
||||
errorText: _currentIsWrong
|
||||
@ -184,27 +184,15 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
: null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.pin_outlined),
|
||||
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,
|
||||
)
|
||||
]
|
||||
]),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_isObscure ? Icons.visibility : Icons.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure ? l10n.s_show_pin : l10n.s_hide_pin),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
@ -284,7 +272,7 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
maxLength: hexLength,
|
||||
controller: _keyController,
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_new_management_key,
|
||||
errorText: _newInvalidFormat
|
||||
@ -293,35 +281,24 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
: null,
|
||||
enabled: currentLenOk,
|
||||
prefixIcon: const Icon(Icons.key_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
tooltip: l10n.s_generate_random,
|
||||
onPressed: currentLenOk
|
||||
? () {
|
||||
final random = Random.secure();
|
||||
final key = List.generate(
|
||||
_keyType.keyLength,
|
||||
(_) => random
|
||||
.nextInt(256)
|
||||
.toRadixString(16)
|
||||
.padLeft(2, '0')).join();
|
||||
setState(() {
|
||||
_keyController.text = key;
|
||||
_newInvalidFormat = false;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
if (_newInvalidFormat) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
tooltip: l10n.s_generate_random,
|
||||
onPressed: currentLenOk
|
||||
? () {
|
||||
final random = Random.secure();
|
||||
final key = List.generate(
|
||||
_keyType.keyLength,
|
||||
(_) => random
|
||||
.nextInt(256)
|
||||
.toRadixString(16)
|
||||
.padLeft(2, '0')).join();
|
||||
setState(() {
|
||||
_keyController.text = key;
|
||||
_newInvalidFormat = false;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
|
@ -111,48 +111,34 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
maxLength: 8,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
key: keys.pinPukField,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: widget.target == ManageTarget.pin
|
||||
? l10n.s_current_pin
|
||||
: l10n.s_current_puk,
|
||||
errorText: _currentIsWrong
|
||||
? (widget.target == ManageTarget.pin
|
||||
? l10n.l_wrong_pin_attempts_remaining(
|
||||
_attemptsRemaining)
|
||||
: l10n.l_wrong_puk_attempts_remaining(
|
||||
_attemptsRemaining))
|
||||
: null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
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,
|
||||
)
|
||||
]
|
||||
],
|
||||
)),
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: widget.target == ManageTarget.pin
|
||||
? l10n.s_current_pin
|
||||
: l10n.s_current_puk,
|
||||
errorText: _currentIsWrong
|
||||
? (widget.target == ManageTarget.pin
|
||||
? l10n
|
||||
.l_wrong_pin_attempts_remaining(_attemptsRemaining)
|
||||
: l10n
|
||||
.l_wrong_puk_attempts_remaining(_attemptsRemaining))
|
||||
: null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.password_outlined),
|
||||
suffixIcon: 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),
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
@ -168,33 +154,24 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
obscureText: _isObscureNew,
|
||||
maxLength: 8,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: widget.target == ManageTarget.puk
|
||||
? 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),
|
||||
),
|
||||
]),
|
||||
suffixIcon: 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,
|
||||
),
|
||||
@ -215,33 +192,25 @@ class _ManagePinPukDialogState extends ConsumerState<ManagePinPukDialog> {
|
||||
obscureText: _isObscureConfirm,
|
||||
maxLength: 8,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: widget.target == ManageTarget.puk
|
||||
? 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),
|
||||
)
|
||||
]),
|
||||
suffixIcon: 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,
|
||||
|
@ -93,7 +93,7 @@ class _PinDialogState extends ConsumerState<PinDialog> {
|
||||
autofillHints: const [AutofillHints.password],
|
||||
key: keys.managementKeyField,
|
||||
controller: _pinController,
|
||||
decoration: InputDecoration(
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_pin,
|
||||
errorText: _pinIsWrong
|
||||
@ -101,29 +101,16 @@ class _PinDialogState extends ConsumerState<PinDialog> {
|
||||
: null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Icons.pin_outlined),
|
||||
suffixIcon: Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
_isObscure ? Icons.visibility : Icons.visibility_off,
|
||||
color: !_pinIsWrong
|
||||
? IconTheme.of(context).color
|
||||
: null),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
if (_pinIsWrong) ...[
|
||||
const Icon(Icons.error_outlined),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
)
|
||||
]
|
||||
],
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_isObscure ? Icons.visibility : Icons.visibility_off,
|
||||
color: !_pinIsWrong ? IconTheme.of(context).color : null),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscure = !_isObscure;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscure ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
|
@ -16,6 +16,91 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppInputDecoration extends InputDecoration {
|
||||
final List<Widget>? suffixIcons;
|
||||
|
||||
const AppInputDecoration({
|
||||
// allow multiple suffixIcons
|
||||
this.suffixIcons,
|
||||
// forward other TextField parameters
|
||||
super.icon,
|
||||
super.iconColor,
|
||||
super.label,
|
||||
super.labelText,
|
||||
super.labelStyle,
|
||||
super.floatingLabelStyle,
|
||||
super.helperText,
|
||||
super.helperStyle,
|
||||
super.helperMaxLines,
|
||||
super.hintText,
|
||||
super.hintStyle,
|
||||
super.hintTextDirection,
|
||||
super.hintMaxLines,
|
||||
super.hintFadeDuration,
|
||||
super.error,
|
||||
super.errorText,
|
||||
super.errorStyle,
|
||||
super.errorMaxLines,
|
||||
super.floatingLabelBehavior,
|
||||
super.floatingLabelAlignment,
|
||||
super.isCollapsed,
|
||||
super.isDense,
|
||||
super.contentPadding,
|
||||
super.prefixIcon,
|
||||
super.prefixIconConstraints,
|
||||
super.prefix,
|
||||
super.prefixText,
|
||||
super.prefixStyle,
|
||||
super.prefixIconColor,
|
||||
super.suffixIcon,
|
||||
super.suffix,
|
||||
super.suffixText,
|
||||
super.suffixStyle,
|
||||
super.suffixIconColor,
|
||||
super.suffixIconConstraints,
|
||||
super.counter,
|
||||
super.counterText,
|
||||
super.counterStyle,
|
||||
super.filled,
|
||||
super.fillColor,
|
||||
super.focusColor,
|
||||
super.hoverColor,
|
||||
super.errorBorder,
|
||||
super.focusedBorder,
|
||||
super.focusedErrorBorder,
|
||||
super.disabledBorder,
|
||||
super.enabledBorder,
|
||||
super.border,
|
||||
super.enabled = true,
|
||||
super.semanticCounterText,
|
||||
super.alignLabelWithHint,
|
||||
super.constraints,
|
||||
}) : assert(!(suffixIcon != null && suffixIcons != null),
|
||||
'Declaring both suffixIcon and suffixIcons is not supported.');
|
||||
|
||||
@override
|
||||
Widget? get suffixIcon {
|
||||
final hasError = errorText != null;
|
||||
|
||||
if (hasError || suffixIcons != null) {
|
||||
final errorIcon = hasError ? const Icon(Icons.error_outlined) : null;
|
||||
|
||||
final existingSuffixIcon = super.suffixIcon;
|
||||
|
||||
return Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
if (suffixIcons != null) ...suffixIcons!,
|
||||
if (existingSuffixIcon != null) existingSuffixIcon,
|
||||
if (errorIcon != null) ...[errorIcon, const SizedBox(width: 8.0)],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return super.suffixIcon;
|
||||
}
|
||||
}
|
||||
|
||||
/// TextField without autocorrect and suggestions
|
||||
class AppTextField extends TextField {
|
||||
const AppTextField({
|
||||
@ -28,7 +113,7 @@ class AppTextField extends TextField {
|
||||
super.controller,
|
||||
super.focusNode,
|
||||
super.undoController,
|
||||
super.decoration,
|
||||
AppInputDecoration? decoration,
|
||||
super.textInputAction,
|
||||
super.textCapitalization,
|
||||
super.style,
|
||||
@ -83,5 +168,5 @@ class AppTextField extends TextField {
|
||||
super.canRequestFocus,
|
||||
super.spellCheckConfiguration,
|
||||
super.magnifierConfiguration,
|
||||
});
|
||||
}) : super(decoration: decoration);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user