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