Line data Source code
1 : import 'package:basf_flutter_components/basf_flutter_components.dart';
2 : import 'package:flutter/material.dart';
3 : import 'package:flutter/services.dart';
4 :
5 : /// {@template basf_text_field}
6 : /// A BASF-styled text field input
7 : /// {@endtemplate}
8 : class BasfTextField extends StatefulWidget {
9 : /// {@macro basf_text_field}
10 1 : const BasfTextField({
11 : super.key,
12 : required this.controller,
13 : this.formKey,
14 : this.initialValue,
15 : this.focusNode,
16 : this.decoration,
17 : this.keyboardType,
18 : this.textCapitalization = TextCapitalization.none,
19 : this.textInputAction,
20 : this.style,
21 : this.strutStyle,
22 : this.textDirection,
23 : this.textAlign = TextAlign.start,
24 : this.textAlignVertical,
25 : this.autofocus = false,
26 : this.readOnly = false,
27 : this.toolbarOptions,
28 : this.showCursor,
29 : this.obscuringCharacter = '•',
30 : this.obscureText = false,
31 : this.autocorrect = true,
32 : this.smartDashesType,
33 : this.smartQuotesType,
34 : this.enableSuggestions = true,
35 : this.maxLengthEnforcement,
36 : this.maxLines = 1,
37 : this.minLines,
38 : this.expands = false,
39 : this.maxLength,
40 : this.onChanged,
41 : this.onTap,
42 : this.onEditingComplete,
43 : this.onFieldSubmitted,
44 : this.onSaved,
45 : this.validator,
46 : this.inputFormatters,
47 : this.enabled,
48 : this.cursorWidth = 2.0,
49 : this.cursorHeight,
50 : this.cursorRadius,
51 : this.cursorColor,
52 : this.keyboardAppearance,
53 : this.scrollPadding = const EdgeInsets.all(30),
54 : this.enableInteractiveSelection = true,
55 : this.selectionControls,
56 : this.buildCounter,
57 : this.scrollPhysics,
58 : this.autofillHints,
59 : this.autovalidateMode,
60 : this.scrollController,
61 : this.restorationId,
62 : this.enableIMEPersonalizedLearning = true,
63 : });
64 :
65 : /// Form key
66 : final GlobalKey<FormState>? formKey;
67 :
68 : /// Text field controller
69 : final TextEditingController? controller;
70 :
71 : /// Initial value
72 : final String? initialValue;
73 :
74 : /// Current focus node
75 : final FocusNode? focusNode;
76 :
77 : /// Input decoration
78 : final InputDecoration? decoration;
79 :
80 : /// Keyboard type
81 : final TextInputType? keyboardType;
82 :
83 : /// Text capitalization
84 : final TextCapitalization textCapitalization;
85 :
86 : /// Text input action
87 : final TextInputAction? textInputAction;
88 :
89 : /// Text style
90 : final TextStyle? style;
91 :
92 : /// Text strut style
93 : final StrutStyle? strutStyle;
94 :
95 : /// Text direction
96 : final TextDirection? textDirection;
97 :
98 : /// Text alignment
99 : final TextAlign textAlign;
100 :
101 : /// Text alignment vertical
102 : final TextAlignVertical? textAlignVertical;
103 :
104 : /// Autofocus
105 : final bool autofocus;
106 :
107 : /// Read-only
108 : final bool readOnly;
109 :
110 : /// Toolbar options
111 : final ToolbarOptions? toolbarOptions;
112 :
113 : /// Whether or not to show the cursor
114 : final bool? showCursor;
115 :
116 : /// Obscuring character
117 : final String obscuringCharacter;
118 :
119 : /// Wheter or not to hide the text
120 : final bool obscureText;
121 :
122 : /// Wheter or not to correct the text automatically
123 : final bool autocorrect;
124 :
125 : /// Smart dashes type
126 : final SmartDashesType? smartDashesType;
127 :
128 : /// Smart quotes type
129 : final SmartQuotesType? smartQuotesType;
130 :
131 : /// Wheter or not to show suggestions
132 : final bool enableSuggestions;
133 :
134 : /// Max length setter
135 : final MaxLengthEnforcement? maxLengthEnforcement;
136 :
137 : /// Max lines for the input
138 : final int? maxLines;
139 :
140 : /// Min lines for the input
141 : final int? minLines;
142 :
143 : /// Wheter or not it expands
144 : final bool expands;
145 :
146 : /// Max character length
147 : final int? maxLength;
148 :
149 : /// Action to be performed when the value changes
150 : final ValueChanged<String>? onChanged;
151 :
152 : /// On tap callback performed on tap
153 : final GestureTapCallback? onTap;
154 :
155 : /// Void callback when editing is completed
156 : final VoidCallback? onEditingComplete;
157 :
158 : /// Field submitted value
159 : final ValueChanged<String>? onFieldSubmitted;
160 :
161 : /// Field submitted on saved
162 : final FormFieldSetter<String>? onSaved;
163 :
164 : /// Field validator
165 : final FormFieldValidator<String>? validator;
166 :
167 : /// Input formatters
168 : final List<TextInputFormatter>? inputFormatters;
169 :
170 : /// Wheter or not it is enabled
171 : final bool? enabled;
172 :
173 : /// Cursor width
174 : final double cursorWidth;
175 :
176 : /// Cursor height
177 : final double? cursorHeight;
178 :
179 : /// Cursor radius
180 : final Radius? cursorRadius;
181 :
182 : /// Cursor color
183 : final Color? cursorColor;
184 :
185 : /// Keyboard appearance
186 : final Brightness? keyboardAppearance;
187 :
188 : /// Scroll padding
189 : final EdgeInsets scrollPadding;
190 :
191 : /// Enable interactive selection
192 : final bool enableInteractiveSelection;
193 :
194 : /// Controls
195 : final TextSelectionControls? selectionControls;
196 :
197 : /// Counter widget
198 : final InputCounterWidgetBuilder? buildCounter;
199 :
200 : /// Physics
201 : final ScrollPhysics? scrollPhysics;
202 :
203 : /// Auto fill hints
204 : final Iterable<String>? autofillHints;
205 :
206 : /// Auto validate
207 : final AutovalidateMode? autovalidateMode;
208 :
209 : /// Scroll controller
210 : final ScrollController? scrollController;
211 :
212 : /// Restoration ID
213 : final String? restorationId;
214 :
215 : /// Enable IMEPErsonalized learning
216 : final bool enableIMEPersonalizedLearning;
217 :
218 1 : @override
219 1 : State<BasfTextField> createState() => _BasfTextFieldState();
220 : }
221 :
222 : class _BasfTextFieldState extends State<BasfTextField> {
223 1 : @override
224 : void initState() {
225 2 : if (widget.validator != null) {
226 4 : widget.controller?.addListener(redrawToChangeThemeBasedOnState);
227 1 : redrawToChangeThemeBasedOnState();
228 : }
229 1 : super.initState();
230 : }
231 :
232 1 : void redrawToChangeThemeBasedOnState() {
233 3 : WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
234 2 : setState(() {});
235 : });
236 : }
237 :
238 1 : @override
239 : Widget build(BuildContext context) {
240 1 : final theme = Theme.of(context);
241 :
242 1 : return Theme(
243 1 : data: _getTheme(theme),
244 3 : child: widget.decoration?.labelText == null
245 1 : ? inputForm(theme)
246 1 : : inputFormWithTitle(theme),
247 : );
248 : }
249 :
250 1 : Widget inputFormWithTitle(ThemeData theme) {
251 1 : return Column(
252 : mainAxisSize: MainAxisSize.min,
253 : crossAxisAlignment: CrossAxisAlignment.start,
254 1 : children: [
255 1 : title(),
256 1 : VerticalSpacer.semi(),
257 2 : if (widget.validator != null)
258 1 : validationFormField(theme)
259 : else
260 1 : textField(theme), //verde
261 : ],
262 : );
263 : }
264 :
265 1 : Widget inputForm(ThemeData theme) {
266 2 : return widget.validator != null
267 1 : ? validationFormField(theme)
268 0 : : textField(theme);
269 : }
270 :
271 1 : Widget title() {
272 1 : return Text(
273 3 : widget.decoration?.labelText ?? '',
274 : maxLines: 2,
275 2 : style: Theme.of(context)
276 1 : .textTheme
277 1 : .overline!
278 1 : .copyWith(color: BasfColors.black),
279 : );
280 : }
281 :
282 1 : Widget? _getThemedPrefixIcon(ThemeData theme) {
283 3 : if (widget.decoration?.prefixIcon != null) {
284 1 : return Theme(
285 1 : data: _getTheme(theme),
286 3 : child: widget.decoration!.prefixIcon!,
287 : );
288 : } else {
289 : return null;
290 : }
291 : }
292 :
293 1 : ThemeData _getTheme(ThemeData theme) {
294 4 : if (widget.formKey?.currentState?.validate() == false) {
295 0 : return BasfInputThemes.errorInputTheme(theme);
296 1 : } else if (!isEnabled()) {
297 1 : return BasfInputThemes.disabledInputTheme(theme);
298 : } else {
299 2 : return Theme.of(context);
300 : }
301 : }
302 :
303 1 : Widget validationFormField(ThemeData theme) {
304 1 : return Form(
305 2 : key: widget.formKey,
306 2 : autovalidateMode: widget.autovalidateMode,
307 1 : child: textFormField(theme),
308 : );
309 : }
310 :
311 1 : TextStyle _getTextStyle() {
312 3 : return widget.style?.copyWith(
313 1 : color: isEnabled() ? BasfColors.darkBlue : BasfColors.darkGrey,
314 : ) ??
315 1 : TextStyle(
316 1 : color: isEnabled() ? BasfColors.darkBlue : BasfColors.darkGrey,
317 : );
318 : }
319 :
320 1 : bool isEnabled() {
321 5 : return widget.enabled ?? widget.decoration?.enabled ?? true;
322 : }
323 :
324 1 : Widget textFormField(ThemeData theme) {
325 1 : return TextFormField(
326 2 : key: widget.key,
327 2 : focusNode: widget.focusNode,
328 2 : controller: widget.controller,
329 2 : initialValue: widget.initialValue,
330 3 : decoration: widget.decoration?.copyWith(
331 1 : prefixIcon: _getThemedPrefixIcon(theme),
332 3 : hintText: widget.decoration?.hintText,
333 3 : labelStyle: widget.decoration?.labelStyle ??
334 2 : BasfThemes.mainTextTheme.bodyText1
335 1 : ?.copyWith(color: BasfColors.darkGrey),
336 : floatingLabelBehavior: FloatingLabelBehavior.never,
337 : ),
338 2 : keyboardType: widget.keyboardType,
339 2 : textCapitalization: widget.textCapitalization,
340 2 : textInputAction: widget.textInputAction,
341 1 : style: _getTextStyle(),
342 2 : strutStyle: widget.strutStyle,
343 2 : textDirection: widget.textDirection,
344 2 : textAlign: widget.textAlign,
345 2 : textAlignVertical: widget.textAlignVertical,
346 2 : autofocus: widget.autofocus,
347 2 : readOnly: widget.readOnly,
348 2 : toolbarOptions: widget.toolbarOptions,
349 2 : showCursor: widget.showCursor,
350 2 : obscuringCharacter: widget.obscuringCharacter,
351 2 : obscureText: widget.obscureText,
352 2 : autocorrect: widget.autocorrect,
353 2 : smartDashesType: widget.smartDashesType,
354 2 : smartQuotesType: widget.smartQuotesType,
355 2 : enableSuggestions: widget.enableSuggestions,
356 2 : maxLengthEnforcement: widget.maxLengthEnforcement,
357 2 : maxLines: widget.maxLines,
358 2 : minLines: widget.minLines,
359 2 : expands: widget.expands,
360 2 : maxLength: widget.maxLength,
361 2 : onChanged: widget.onChanged,
362 2 : onTap: widget.onTap,
363 2 : onEditingComplete: widget.onEditingComplete,
364 2 : onFieldSubmitted: widget.onFieldSubmitted,
365 2 : onSaved: widget.onSaved,
366 2 : validator: widget.validator,
367 2 : inputFormatters: widget.inputFormatters,
368 2 : enabled: widget.enabled,
369 2 : cursorWidth: widget.cursorWidth,
370 2 : cursorHeight: widget.cursorHeight,
371 2 : cursorRadius: widget.cursorRadius,
372 2 : cursorColor: widget.cursorColor,
373 2 : keyboardAppearance: widget.keyboardAppearance,
374 2 : scrollPadding: widget.scrollPadding,
375 2 : enableInteractiveSelection: widget.enableInteractiveSelection,
376 2 : selectionControls: widget.selectionControls,
377 2 : buildCounter: widget.buildCounter,
378 2 : scrollPhysics: widget.scrollPhysics,
379 2 : autofillHints: widget.autofillHints,
380 2 : autovalidateMode: widget.autovalidateMode,
381 2 : scrollController: widget.scrollController,
382 2 : restorationId: widget.restorationId,
383 2 : enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
384 : );
385 : }
386 :
387 1 : Widget textField(ThemeData theme) {
388 1 : return TextField(
389 2 : focusNode: widget.focusNode,
390 2 : controller: widget.controller,
391 3 : decoration: widget.decoration?.copyWith(
392 1 : prefixIcon: _getThemedPrefixIcon(theme),
393 3 : hintText: widget.decoration?.hintText,
394 3 : labelStyle: widget.decoration?.labelStyle ??
395 2 : BasfThemes.mainTextTheme.bodyText1
396 1 : ?.copyWith(color: BasfColors.darkGrey),
397 : floatingLabelBehavior: FloatingLabelBehavior.never,
398 : ),
399 2 : keyboardType: widget.keyboardType,
400 2 : textCapitalization: widget.textCapitalization,
401 2 : textInputAction: widget.textInputAction,
402 1 : style: _getTextStyle(),
403 2 : strutStyle: widget.strutStyle,
404 2 : textDirection: widget.textDirection,
405 2 : textAlign: widget.textAlign,
406 2 : textAlignVertical: widget.textAlignVertical,
407 2 : autofocus: widget.autofocus,
408 2 : readOnly: widget.readOnly,
409 2 : toolbarOptions: widget.toolbarOptions,
410 2 : showCursor: widget.showCursor,
411 2 : obscuringCharacter: widget.obscuringCharacter,
412 2 : obscureText: widget.obscureText,
413 2 : autocorrect: widget.autocorrect,
414 2 : smartDashesType: widget.smartDashesType,
415 2 : smartQuotesType: widget.smartQuotesType,
416 2 : enableSuggestions: widget.enableSuggestions,
417 2 : maxLengthEnforcement: widget.maxLengthEnforcement,
418 2 : maxLines: widget.maxLines,
419 2 : minLines: widget.minLines,
420 2 : expands: widget.expands,
421 2 : maxLength: widget.maxLength,
422 2 : onChanged: widget.onChanged,
423 2 : onTap: widget.onTap,
424 2 : onEditingComplete: widget.onEditingComplete,
425 2 : inputFormatters: widget.inputFormatters,
426 2 : enabled: widget.enabled,
427 2 : cursorWidth: widget.cursorWidth,
428 2 : cursorHeight: widget.cursorHeight,
429 2 : cursorRadius: widget.cursorRadius,
430 2 : cursorColor: widget.cursorColor,
431 2 : keyboardAppearance: widget.keyboardAppearance,
432 2 : scrollPadding: widget.scrollPadding,
433 2 : enableInteractiveSelection: widget.enableInteractiveSelection,
434 2 : selectionControls: widget.selectionControls,
435 2 : buildCounter: widget.buildCounter,
436 2 : scrollPhysics: widget.scrollPhysics,
437 2 : autofillHints: widget.autofillHints,
438 2 : scrollController: widget.scrollController,
439 2 : restorationId: widget.restorationId,
440 2 : enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
441 : );
442 : }
443 : }
|