password_textformfield.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle;
  2. import 'package:flutter/gestures.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/services.dart';
  5. import 'package:lszlgl/widget/password_textfield.dart';
  6. /// A [FormField] that contains a [PasswordTextField].
  7. /// If you want to see the details of the API, check the [TextFormField].
  8. ///
  9. /// It has almost the same API as [TextFormField], so it can be replaced.
  10. class PasswordTextFormField extends FormField<String> {
  11. /// Creates a [FormField] that contains a [PasswordTextField].
  12. PasswordTextFormField({
  13. super.key,
  14. IconData visibleIcon = Icons.remove_red_eye_outlined,
  15. IconData inVisibleIcon = Icons.remove_red_eye_outlined,
  16. bool initialObscurity = true,
  17. this.controller,
  18. String? initialValue,
  19. FocusNode? focusNode,
  20. InputDecoration? decoration = const InputDecoration(),
  21. TextInputType? keyboardType,
  22. TextCapitalization textCapitalization = TextCapitalization.none,
  23. TextInputAction? textInputAction,
  24. TextStyle? style,
  25. StrutStyle? strutStyle,
  26. TextDirection? textDirection,
  27. TextAlign textAlign = TextAlign.start,
  28. TextAlignVertical? textAlignVertical,
  29. bool autofocus = false,
  30. bool readOnly = false,
  31. bool? showCursor,
  32. String obscuringCharacter = '•',
  33. bool obscureText = false,
  34. bool autocorrect = true,
  35. SmartDashesType? smartDashesType,
  36. SmartQuotesType? smartQuotesType,
  37. bool enableSuggestions = true,
  38. MaxLengthEnforcement? maxLengthEnforcement,
  39. int? maxLines = 1,
  40. int? minLines,
  41. bool expands = false,
  42. int? maxLength,
  43. ValueChanged<String>? onChanged,
  44. GestureTapCallback? onTap,
  45. TapRegionCallback? onTapOutside,
  46. VoidCallback? onEditingComplete,
  47. ValueChanged<String>? onFieldSubmitted,
  48. super.onSaved,
  49. super.validator,
  50. List<TextInputFormatter>? inputFormatters,
  51. bool? enabled,
  52. double cursorWidth = 2.0,
  53. double? cursorHeight,
  54. Radius? cursorRadius,
  55. Color? cursorColor,
  56. Brightness? keyboardAppearance,
  57. EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
  58. bool? enableInteractiveSelection,
  59. TextSelectionControls? selectionControls,
  60. InputCounterWidgetBuilder? buildCounter,
  61. ScrollPhysics? scrollPhysics,
  62. Iterable<String>? autofillHints,
  63. AutovalidateMode? autovalidateMode,
  64. ScrollController? scrollController,
  65. super.restorationId,
  66. bool enableIMEPersonalizedLearning = true,
  67. MouseCursor? mouseCursor,
  68. EditableTextContextMenuBuilder? contextMenuBuilder =
  69. _defaultContextMenuBuilder,
  70. SpellCheckConfiguration? spellCheckConfiguration,
  71. TextMagnifierConfiguration? magnifierConfiguration,
  72. UndoHistoryController? undoController,
  73. AppPrivateCommandCallback? onAppPrivateCommand,
  74. bool? cursorOpacityAnimates,
  75. ui.BoxHeightStyle selectionHeightStyle = ui.BoxHeightStyle.tight,
  76. ui.BoxWidthStyle selectionWidthStyle = ui.BoxWidthStyle.tight,
  77. DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  78. ContentInsertionConfiguration? contentInsertionConfiguration,
  79. Clip clipBehavior = Clip.hardEdge,
  80. bool scribbleEnabled = true,
  81. bool canRequestFocus = true,
  82. }) : super(
  83. initialValue:
  84. controller != null ? controller.text : (initialValue ?? ''),
  85. enabled: enabled ?? decoration?.enabled ?? true,
  86. autovalidateMode: autovalidateMode ?? AutovalidateMode.disabled,
  87. builder: (FormFieldState<String> field) {
  88. final _PasswordTextFormFieldState state =
  89. field as _PasswordTextFormFieldState;
  90. final InputDecoration effectiveDecoration = (decoration ??
  91. const InputDecoration())
  92. .applyDefaults(Theme.of(field.context).inputDecorationTheme);
  93. void onChangedHandler(String value) {
  94. field.didChange(value);
  95. if (onChanged != null) {
  96. onChanged(value);
  97. }
  98. }
  99. return UnmanagedRestorationScope(
  100. bucket: field.bucket,
  101. child: PasswordTextField(
  102. visibleIcon: visibleIcon,
  103. inVisibleIcon: inVisibleIcon,
  104. initialObscurity: initialObscurity,
  105. restorationId: restorationId,
  106. controller: state._effectiveController,
  107. focusNode: focusNode,
  108. decoration:
  109. effectiveDecoration.copyWith(errorText: field.errorText),
  110. keyboardType: keyboardType,
  111. textInputAction: textInputAction,
  112. style: style,
  113. strutStyle: strutStyle,
  114. textAlign: textAlign,
  115. textAlignVertical: textAlignVertical,
  116. textDirection: textDirection,
  117. textCapitalization: textCapitalization,
  118. autofocus: autofocus,
  119. readOnly: readOnly,
  120. showCursor: showCursor,
  121. obscuringCharacter: obscuringCharacter,
  122. autocorrect: autocorrect,
  123. enableSuggestions: enableSuggestions,
  124. maxLengthEnforcement: maxLengthEnforcement,
  125. maxLines: maxLines,
  126. minLines: minLines,
  127. expands: expands,
  128. maxLength: maxLength,
  129. onChanged: onChangedHandler,
  130. onTap: onTap,
  131. onTapOutside: onTapOutside,
  132. onEditingComplete: onEditingComplete,
  133. onSubmitted: onFieldSubmitted,
  134. inputFormatters: inputFormatters,
  135. enabled: enabled ?? decoration?.enabled ?? true,
  136. cursorWidth: cursorWidth,
  137. cursorHeight: cursorHeight,
  138. cursorRadius: cursorRadius,
  139. cursorColor: cursorColor,
  140. scrollPadding: scrollPadding,
  141. scrollPhysics: scrollPhysics,
  142. keyboardAppearance: keyboardAppearance,
  143. enableInteractiveSelection:
  144. enableInteractiveSelection ?? (!obscureText || !readOnly),
  145. selectionControls: selectionControls,
  146. buildCounter: buildCounter,
  147. autofillHints: autofillHints,
  148. scrollController: scrollController,
  149. enableIMEPersonalizedLearning: enableIMEPersonalizedLearning,
  150. mouseCursor: mouseCursor,
  151. contextMenuBuilder: contextMenuBuilder,
  152. spellCheckConfiguration: spellCheckConfiguration,
  153. magnifierConfiguration: magnifierConfiguration,
  154. undoController: undoController,
  155. onAppPrivateCommand: onAppPrivateCommand,
  156. cursorOpacityAnimates: cursorOpacityAnimates,
  157. selectionHeightStyle: selectionHeightStyle,
  158. selectionWidthStyle: selectionWidthStyle,
  159. dragStartBehavior: dragStartBehavior,
  160. contentInsertionConfiguration: contentInsertionConfiguration,
  161. clipBehavior: clipBehavior,
  162. scribbleEnabled: scribbleEnabled,
  163. canRequestFocus: canRequestFocus,
  164. ),
  165. );
  166. },
  167. );
  168. /// Controls the text being edited.
  169. ///
  170. /// If null, this widget will create its own [TextEditingController] and
  171. /// initialize its [TextEditingController.text] with [initialValue].
  172. final TextEditingController? controller;
  173. static Widget _defaultContextMenuBuilder(
  174. BuildContext context, EditableTextState editableTextState) {
  175. return AdaptiveTextSelectionToolbar.editableText(
  176. editableTextState: editableTextState,
  177. );
  178. }
  179. @override
  180. FormFieldState<String> createState() => _PasswordTextFormFieldState();
  181. }
  182. /// see [TextFormField] & [_TextFormFieldState]
  183. class _PasswordTextFormFieldState extends FormFieldState<String> {
  184. RestorableTextEditingController? _controller;
  185. TextEditingController get _effectiveController =>
  186. _textFormField.controller ?? _controller!.value;
  187. PasswordTextFormField get _textFormField =>
  188. super.widget as PasswordTextFormField;
  189. @override
  190. void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
  191. super.restoreState(oldBucket, initialRestore);
  192. if (_controller != null) {
  193. _registerController();
  194. }
  195. // Make sure to update the internal [FormFieldState] value to sync up with
  196. // text editing controller value.
  197. setValue(_effectiveController.text);
  198. }
  199. void _registerController() {
  200. assert(_controller != null);
  201. registerForRestoration(_controller!, 'controller');
  202. }
  203. void _createLocalController([TextEditingValue? value]) {
  204. assert(_controller == null);
  205. _controller = value == null
  206. ? RestorableTextEditingController()
  207. : RestorableTextEditingController.fromValue(value);
  208. if (!restorePending) {
  209. _registerController();
  210. }
  211. }
  212. @override
  213. void initState() {
  214. super.initState();
  215. if (_textFormField.controller == null) {
  216. _createLocalController(widget.initialValue != null
  217. ? TextEditingValue(text: widget.initialValue!)
  218. : null);
  219. } else {
  220. _textFormField.controller!.addListener(_handleControllerChanged);
  221. }
  222. }
  223. @override
  224. void didUpdateWidget(PasswordTextFormField oldWidget) {
  225. super.didUpdateWidget(oldWidget);
  226. if (_textFormField.controller != oldWidget.controller) {
  227. oldWidget.controller?.removeListener(_handleControllerChanged);
  228. _textFormField.controller?.addListener(_handleControllerChanged);
  229. if (oldWidget.controller != null && _textFormField.controller == null) {
  230. _createLocalController(oldWidget.controller!.value);
  231. }
  232. if (_textFormField.controller != null) {
  233. setValue(_textFormField.controller!.text);
  234. if (oldWidget.controller == null) {
  235. unregisterFromRestoration(_controller!);
  236. _controller!.dispose();
  237. _controller = null;
  238. }
  239. }
  240. }
  241. }
  242. @override
  243. void dispose() {
  244. _textFormField.controller?.removeListener(_handleControllerChanged);
  245. _controller?.dispose();
  246. super.dispose();
  247. }
  248. @override
  249. void didChange(String? value) {
  250. super.didChange(value);
  251. if (_effectiveController.text != value) {
  252. _effectiveController.text = value ?? '';
  253. }
  254. }
  255. @override
  256. void reset() {
  257. // setState will be called in the superclass, so even though state is being
  258. // manipulated, no setState call is needed here.
  259. _effectiveController.text = widget.initialValue ?? '';
  260. super.reset();
  261. }
  262. void _handleControllerChanged() {
  263. // Suppress changes that originated from within this class.
  264. //
  265. // In the case where a controller has been passed in to this widget, we
  266. // register this change listener. In these cases, we'll also receive change
  267. // notifications for changes originating from within this class -- for
  268. // example, the reset() method. In such cases, the FormField value will
  269. // already have been set.
  270. if (_effectiveController.text != value) {
  271. didChange(_effectiveController.text);
  272. }
  273. }
  274. }