From 339aabda3f3d9aab0b441b391e8b9a3c410927d2 Mon Sep 17 00:00:00 2001 From: problematicconsumer Date: Mon, 11 Dec 2023 19:06:05 +0330 Subject: [PATCH] Fix text input traversal --- .../widgets/settings_input_dialog.dart | 113 ++++++++++-------- lib/utils/custom_text_form_field.dart | 9 +- 2 files changed, 73 insertions(+), 49 deletions(-) diff --git a/lib/features/settings/widgets/settings_input_dialog.dart b/lib/features/settings/widgets/settings_input_dialog.dart index 84a552be6..fdc522fed 100644 --- a/lib/features/settings/widgets/settings_input_dialog.dart +++ b/lib/features/settings/widgets/settings_input_dialog.dart @@ -45,55 +45,74 @@ class SettingsInputDialog extends HookConsumerWidget with PresLogger { text: initialValue?.toString(), ); - return AlertDialog( - title: Text(title), - icon: icon != null ? Icon(icon) : null, - content: TextFormField( - controller: textController, - inputFormatters: [ - FilteringTextInputFormatter.singleLineFormatter, - if (digitsOnly) FilteringTextInputFormatter.digitsOnly, - ], - autovalidateMode: AutovalidateMode.always, - ), - actions: [ - if (optionalAction != null) - TextButton( - onPressed: () async { - optionalAction!.$2(); - await Navigator.of(context) - .maybePop(T == String ? textController.value.text : null); - }, - child: Text(optionalAction!.$1.toUpperCase()), + return FocusTraversalGroup( + policy: OrderedTraversalPolicy(), + child: AlertDialog( + title: Text(title), + icon: icon != null ? Icon(icon) : null, + content: FocusTraversalOrder( + order: const NumericFocusOrder(1), + child: CustomTextFormField( + controller: textController, + inputFormatters: [ + FilteringTextInputFormatter.singleLineFormatter, + if (digitsOnly) FilteringTextInputFormatter.digitsOnly, + ], + autoCorrect: true, + hint: title, ), - if (resetValue != null) - TextButton( - onPressed: () async { - await Navigator.of(context).maybePop(resetValue); - }, - child: Text(t.general.reset.toUpperCase()), - ), - TextButton( - onPressed: () async { - await Navigator.of(context).maybePop(); - }, - child: Text(localizations.cancelButtonLabel.toUpperCase()), - ), - TextButton( - onPressed: () async { - if (validator?.call(textController.value.text) == false) { - await Navigator.of(context).maybePop(null); - } else if (mapTo != null) { - await Navigator.of(context) - .maybePop(mapTo!.call(textController.value.text)); - } else { - await Navigator.of(context) - .maybePop(T == String ? textController.value.text : null); - } - }, - child: Text(localizations.okButtonLabel.toUpperCase()), ), - ], + actions: [ + if (optionalAction != null) + FocusTraversalOrder( + order: const NumericFocusOrder(5), + child: TextButton( + onPressed: () async { + optionalAction!.$2(); + await Navigator.of(context) + .maybePop(T == String ? textController.value.text : null); + }, + child: Text(optionalAction!.$1.toUpperCase()), + ), + ), + if (resetValue != null) + FocusTraversalOrder( + order: const NumericFocusOrder(4), + child: TextButton( + onPressed: () async { + await Navigator.of(context).maybePop(resetValue); + }, + child: Text(t.general.reset.toUpperCase()), + ), + ), + FocusTraversalOrder( + order: const NumericFocusOrder(3), + child: TextButton( + onPressed: () async { + await Navigator.of(context).maybePop(); + }, + child: Text(localizations.cancelButtonLabel.toUpperCase()), + ), + ), + FocusTraversalOrder( + order: const NumericFocusOrder(2), + child: TextButton( + onPressed: () async { + if (validator?.call(textController.value.text) == false) { + await Navigator.of(context).maybePop(null); + } else if (mapTo != null) { + await Navigator.of(context) + .maybePop(mapTo!.call(textController.value.text)); + } else { + await Navigator.of(context) + .maybePop(T == String ? textController.value.text : null); + } + }, + child: Text(localizations.okButtonLabel.toUpperCase()), + ), + ), + ], + ), ); } } diff --git a/lib/utils/custom_text_form_field.dart b/lib/utils/custom_text_form_field.dart index 32c980604..98565a55b 100644 --- a/lib/utils/custom_text_form_field.dart +++ b/lib/utils/custom_text_form_field.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hiddify/utils/text_utils.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -6,9 +7,10 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; class CustomTextFormField extends HookConsumerWidget { const CustomTextFormField({ super.key, - required this.onChanged, + this.onChanged, this.validator, this.controller, + this.inputFormatters, this.initialValue = '', this.suffixIcon, this.label, @@ -19,9 +21,10 @@ class CustomTextFormField extends HookConsumerWidget { this.autoCorrect = false, }); - final ValueChanged onChanged; + final ValueChanged? onChanged; final String? Function(String? value)? validator; final TextEditingController? controller; + final List? inputFormatters; final String initialValue; final Widget? suffixIcon; final String? label; @@ -51,6 +54,8 @@ class CustomTextFormField extends HookConsumerWidget { onChanged: onChanged, textDirection: textController.textDirection, validator: validator, + textInputAction: TextInputAction.next, + inputFormatters: inputFormatters, autovalidateMode: autoValidate ? AutovalidateMode.always : AutovalidateMode.disabled, autocorrect: autoCorrect,