mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-22 00:12:09 +03:00
Merge PR #1595
This commit is contained in:
commit
72a1dc511f
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Yubico.
|
||||
* Copyright (C) 2022-2024 Yubico.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -255,7 +255,11 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
|
||||
});
|
||||
},
|
||||
onFieldSubmitted: (_) {
|
||||
_submit();
|
||||
if (_label.isNotEmpty) {
|
||||
_submit();
|
||||
} else {
|
||||
_nameFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
)
|
||||
|
@ -52,6 +52,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
final _currentPinFocus = FocusNode();
|
||||
final _newPinController = TextEditingController();
|
||||
final _newPinFocus = FocusNode();
|
||||
final _confirmPinFocus = FocusNode();
|
||||
String _confirmPin = '';
|
||||
String? _currentPinError;
|
||||
String? _newPinError;
|
||||
@ -68,6 +69,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
_currentPinFocus.dispose();
|
||||
_newPinController.dispose();
|
||||
_newPinFocus.dispose();
|
||||
_confirmPinFocus.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -86,6 +88,9 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
final isValid =
|
||||
currentPinLenOk && newPinLenOk && _newPinController.text == _confirmPin;
|
||||
|
||||
final newPinEnabled = !_isBlocked && currentPinLenOk;
|
||||
final confirmPinEnabled = !_isBlocked && currentPinLenOk && newPinLenOk;
|
||||
|
||||
final deviceData = ref.read(currentDeviceDataProvider).valueOrNull;
|
||||
|
||||
final hasPinComplexity = deviceData?.info.pinComplexity ?? false;
|
||||
@ -148,11 +153,19 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
_isObscureCurrent ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_currentIsWrong = false;
|
||||
});
|
||||
},
|
||||
onFieldSubmitted: (_) {
|
||||
if (_currentPinController.text.length < minPinLength) {
|
||||
_currentPinFocus.requestFocus();
|
||||
} else {
|
||||
_newPinFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
],
|
||||
Text(hasPinComplexity
|
||||
@ -172,31 +185,43 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_new_pin,
|
||||
enabled: !_isBlocked && currentPinLenOk,
|
||||
enabled: newPinEnabled,
|
||||
errorText: _newIsWrong ? _newPinError : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Symbols.pin),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureNew ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
suffixIcon: ExcludeFocusTraversal(
|
||||
excluding: !newPinEnabled,
|
||||
child: IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureNew ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_newIsWrong = false;
|
||||
});
|
||||
},
|
||||
onFieldSubmitted: (_) {
|
||||
if (_newPinController.text.length < minPinLength) {
|
||||
_newPinFocus.requestFocus();
|
||||
} else {
|
||||
_confirmPinFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
AppTextFormField(
|
||||
key: confirmPin,
|
||||
initialValue: _confirmPin,
|
||||
focusNode: _confirmPinFocus,
|
||||
maxLength: maxPinLength,
|
||||
inputFormatters: [limitBytesLength(maxPinLength)],
|
||||
buildCounter: buildByteCounterFor(_confirmPin),
|
||||
@ -206,19 +231,22 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_confirm_pin,
|
||||
prefixIcon: const Icon(Symbols.pin),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip:
|
||||
_isObscureConfirm ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
suffixIcon: ExcludeFocusTraversal(
|
||||
excluding: !confirmPinEnabled,
|
||||
child: IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip:
|
||||
_isObscureConfirm ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
),
|
||||
enabled: !_isBlocked && currentPinLenOk && newPinLenOk,
|
||||
enabled: confirmPinEnabled,
|
||||
errorText:
|
||||
_newPinController.text.length == _confirmPin.length &&
|
||||
_newPinController.text != _confirmPin
|
||||
@ -226,6 +254,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
: null,
|
||||
helperText: '', // Prevents resizing when errorText shown
|
||||
),
|
||||
textInputAction: TextInputAction.done,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_confirmPin = value;
|
||||
@ -234,6 +263,8 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
onFieldSubmitted: (_) {
|
||||
if (isValid) {
|
||||
_submit();
|
||||
} else {
|
||||
_confirmPinFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Yubico.
|
||||
* Copyright (C) 2022-2024 Yubico.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -41,12 +41,20 @@ class RenameFingerprintDialog extends ConsumerStatefulWidget {
|
||||
|
||||
class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
late String _label;
|
||||
late FocusNode _labelFocus;
|
||||
_RenameAccountDialogState();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_label = widget.fingerprint.name ?? '';
|
||||
_labelFocus = FocusNode();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_labelFocus.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
_submit() async {
|
||||
@ -93,7 +101,9 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
Text(l10n.q_rename_target(widget.fingerprint.label)),
|
||||
Text(l10n.p_will_change_label_fp),
|
||||
AppTextFormField(
|
||||
autofocus: true,
|
||||
initialValue: _label,
|
||||
focusNode: _labelFocus,
|
||||
maxLength: 15,
|
||||
inputFormatters: [limitBytesLength(15)],
|
||||
buildCounter: buildByteCounterFor(_label),
|
||||
@ -110,6 +120,8 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
onFieldSubmitted: (_) {
|
||||
if (_label.isNotEmpty) {
|
||||
_submit();
|
||||
} else {
|
||||
_labelFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Yubico.
|
||||
* Copyright (C) 2022-2024 Yubico.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -34,6 +34,7 @@ import '../state.dart';
|
||||
class ManagePasswordDialog extends ConsumerStatefulWidget {
|
||||
final DevicePath path;
|
||||
final OathState state;
|
||||
|
||||
const ManagePasswordDialog(this.path, this.state, {super.key});
|
||||
|
||||
@override
|
||||
@ -44,6 +45,8 @@ class ManagePasswordDialog extends ConsumerStatefulWidget {
|
||||
class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
final _currentPasswordController = TextEditingController();
|
||||
final _currentPasswordFocus = FocusNode();
|
||||
final _newPasswordFocus = FocusNode();
|
||||
final _confirmPasswordFocus = FocusNode();
|
||||
String _newPassword = '';
|
||||
String _confirmPassword = '';
|
||||
bool _currentIsWrong = false;
|
||||
@ -55,6 +58,8 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
void dispose() {
|
||||
_currentPasswordController.dispose();
|
||||
_currentPasswordFocus.dispose();
|
||||
_newPasswordFocus.dispose();
|
||||
_confirmPasswordFocus.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -92,6 +97,13 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
_newPassword == _confirmPassword &&
|
||||
(!widget.state.hasKey || _currentPasswordController.text.isNotEmpty);
|
||||
|
||||
final newPasswordEnabled =
|
||||
!widget.state.hasKey || _currentPasswordController.text.isNotEmpty;
|
||||
|
||||
final confirmPasswordEnabled =
|
||||
(!widget.state.hasKey || _currentPasswordController.text.isNotEmpty) &&
|
||||
_newPassword.isNotEmpty;
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(
|
||||
widget.state.hasKey ? l10n.s_manage_password : l10n.s_set_password),
|
||||
@ -141,6 +153,13 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
_currentIsWrong = false;
|
||||
});
|
||||
},
|
||||
onSubmitted: (_) {
|
||||
if (_currentPasswordController.text.isEmpty) {
|
||||
_currentPasswordFocus.requestFocus();
|
||||
} else {
|
||||
_newPasswordFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
Wrap(
|
||||
spacing: 4.0,
|
||||
@ -204,24 +223,27 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
autofocus: !widget.state.hasKey,
|
||||
obscureText: _isObscureNew,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
focusNode: _newPasswordFocus,
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_new_password,
|
||||
prefixIcon: const Icon(Symbols.password),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureNew
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
enabled: !widget.state.hasKey ||
|
||||
_currentPasswordController.text.isNotEmpty,
|
||||
suffixIcon: ExcludeFocusTraversal(
|
||||
excluding: !newPasswordEnabled,
|
||||
child: IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureNew
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
),
|
||||
enabled: newPasswordEnabled,
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
@ -230,34 +252,38 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
});
|
||||
},
|
||||
onSubmitted: (_) {
|
||||
if (isValid) {
|
||||
_submit();
|
||||
if (_newPassword.isNotEmpty) {
|
||||
_confirmPasswordFocus.requestFocus();
|
||||
} else if (_newPassword.isEmpty) {
|
||||
_newPasswordFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
AppTextField(
|
||||
key: keys.confirmPasswordField,
|
||||
obscureText: _isObscureConfirm,
|
||||
focusNode: _confirmPasswordFocus,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_confirm_password,
|
||||
prefixIcon: const Icon(Symbols.password),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureConfirm
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
enabled: (!widget.state.hasKey ||
|
||||
_currentPasswordController.text.isNotEmpty) &&
|
||||
_newPassword.isNotEmpty,
|
||||
suffixIcon: ExcludeFocusTraversal(
|
||||
excluding: !confirmPasswordEnabled,
|
||||
child: IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureConfirm
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
),
|
||||
enabled: confirmPasswordEnabled,
|
||||
errorText: _newPassword.length == _confirmPassword.length &&
|
||||
_newPassword != _confirmPassword
|
||||
? l10n.l_password_mismatch
|
||||
@ -273,6 +299,8 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
onSubmitted: (_) {
|
||||
if (isValid) {
|
||||
_submit();
|
||||
} else {
|
||||
_confirmPasswordFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
|
Loading…
Reference in New Issue
Block a user