feat(984): enable Enter key submission on desktop wallet unlock (#3137)
What changed, and why it matters
This commit adds the ability to press the Enter/Return key to submit a wallet unlock password on desktop, instead of only being able to tap the unlock button. It also cleans up the unlock logic into one shared method and properly disposes of the password text controller. There is no security vulnerability here; it is a normal user-experience improvement.
No security action needed. Review as a normal UX/code-quality change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors wallet unlock submission: a new _unlockWallet() async method is introduced and used both by the unlock button’s onPressed and by the password field’s new onSubmit callback. BaseTextFormField is updated so onFieldSubmitted uses an explicitly passed handler if provided, falling back to onSubmit. Additionally, _passwordController.dispose() is added in dispose(). These are code-quality and UX changes, not security fixes.
Changed components
lib/src/screens/wallet_unlock/wallet_unlock_page.dartlib/src/widgets/base_text_form_field.dartInspect captured patch +28 / −15
diff --git a/lib/src/screens/wallet_unlock/wallet_unlock_page.dart b/lib/src/screens/wallet_unlock/wallet_unlock_page.dart
index 958bdfcc..abec4a42 100644
--- a/lib/src/screens/wallet_unlock/wallet_unlock_page.dart
+++ b/lib/src/screens/wallet_unlock/wallet_unlock_page.dart
@@ -84,6 +84,8 @@ class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> {
_passwordController.removeListener(_passwordControllerListener!);
}
+ _passwordController.dispose();
+
super.dispose();
}
@@ -105,6 +107,26 @@ class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> {
});
}
+ Future<void> _unlockWallet() async {
+ if (widget.walletUnlockViewModel.state is IsExecutingState) {
+ return;
+ }
+
+ FocusScope.of(context).unfocus();
+
+ if (widget.authPasswordHandler != null) {
+ try {
+ await widget.authPasswordHandler!(widget.walletUnlockViewModel.password);
+ widget.walletUnlockViewModel.success();
+ } catch (e) {
+ widget.walletUnlockViewModel.failure(e);
+ }
+ return;
+ }
+
+ await widget.walletUnlockViewModel.unlock();
+ }
+
@override
Future<void> close({String? route, arguments}) async {
if (_key.currentContext == null) {
@@ -176,6 +198,9 @@ class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> {
child: BaseTextFormField(
key: ValueKey('enter_wallet_password'),
onChanged: (value) => null,
+ onSubmit: (_) async {
+ await _unlockWallet();
+ },
controller: _passwordController,
textAlign: TextAlign.center,
obscureText: true,
@@ -187,7 +212,7 @@ class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> {
fontSize: 18.0,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurfaceVariant,
- ),
+ ),
hintText: S.of(context).enter_wallet_password,
),
),
@@ -199,19 +224,7 @@ class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> {
padding: EdgeInsets.only(bottom: 24),
child: Observer(
builder: (_) => LoadingPrimaryButton(
- onPressed: () async {
- if (widget.authPasswordHandler != null) {
- try {
- await widget.authPasswordHandler!(widget.walletUnlockViewModel.password);
- widget.walletUnlockViewModel.success();
- } catch (e) {
- widget.walletUnlockViewModel.failure(e);
- }
- return;
- }
-
- widget.walletUnlockViewModel.unlock();
- },
+ onPressed: _unlockWallet,
text: S.of(context).unlock,
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary,
diff --git a/lib/src/widgets/base_text_form_field.dart b/lib/src/widgets/base_text_form_field.dart
index e605a83f..f6402bea 100644
--- a/lib/src/widgets/base_text_form_field.dart
+++ b/lib/src/widgets/base_text_form_field.dart
@@ -121,7 +121,7 @@ class BaseTextFormField extends StatelessWidget {
inputFormatters: inputFormatters,
enabled: enabled,
maxLength: maxLength,
- onFieldSubmitted: onSubmit,
+ onFieldSubmitted: onFieldSubmitted ?? onSubmit,
style: textStyle ??
Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: 16.0, color: textColor ?? Theme.of(context).colorScheme.onSurface),
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.