import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/views/widgets/animated_visibility.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:persian_number_utility/persian_number_utility.dart'; class DidvanTextField extends StatefulWidget { final void Function(String value)? onChanged; final void Function(String value)? onSubmitted; final bool enabled; final bool autoFocus; final TextAlign textAlign; final String? title; final String? hintText; final dynamic initialValue; final bool obsecureText; final bool acceptSpace; final String? Function(String value)? validator; final TextInputType? textInputType; final bool disableBorders; final bool isSmall; const DidvanTextField({ Key? key, this.onChanged, this.enabled = true, this.title, this.hintText, this.initialValue, this.validator, this.textInputType, this.textAlign = TextAlign.right, this.obsecureText = false, this.autoFocus = false, this.onSubmitted, this.acceptSpace = true, this.disableBorders = false, this.isSmall = false, }) : super(key: key); @override State createState() => _DidvanTextFieldState(); } class _DidvanTextFieldState extends State { final FocusNode _focusNode = FocusNode(); final TextEditingController _controller = TextEditingController(); bool _hideContent = false; String? _error; @override void initState() { if (widget.initialValue != null) { _controller.text = widget.initialValue; } _hideContent = widget.obsecureText; _focusNode.addListener(() { setState(() {}); }); super.initState(); } @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.title != null) DidvanText( widget.title!, color: _titleColor(), ), if (widget.title != null) const SizedBox(height: 8), Container( height: 48, padding: const EdgeInsets.symmetric(horizontal: 12).copyWith( left: widget.obsecureText ? 0 : 12, ), decoration: BoxDecoration( color: _fillColor(), borderRadius: DesignConfig.lowBorderRadius, border: widget.disableBorders ? null : Border.all(color: _borderColor()), ), child: TextFormField( inputFormatters: [ if (!widget.acceptSpace) FilteringTextInputFormatter.allow(RegExp("[0-9a-zA-Z]")), ], autofocus: widget.autoFocus, obscureText: _hideContent, textAlign: widget.textAlign, keyboardType: widget.textInputType, focusNode: _focusNode, controller: _controller, onFieldSubmitted: widget.onSubmitted, onChanged: _onChanged, validator: _validator, obscuringCharacter: '*', style: (widget.isSmall ? Theme.of(context).textTheme.bodySmall! : Theme.of(context).textTheme.bodyMedium!) .copyWith(fontFamily: DesignConfig.fontFamily.padRight(3)), decoration: InputDecoration( suffixIcon: _suffixBuilder(), enabled: widget.enabled, border: InputBorder.none, hintText: widget.hintText, errorStyle: const TextStyle(height: 0.01), hintStyle: (widget.isSmall ? Theme.of(context).textTheme.bodySmall! : Theme.of(context).textTheme.bodyMedium!) .copyWith(color: Theme.of(context).colorScheme.hint), ), ), ), AnimatedVisibility( isVisible: _error != null, duration: DesignConfig.lowAnimationDuration, child: Column( children: [ const SizedBox(height: 8), Row( children: [ Icon( DidvanIcons.lightbulb_exclamation_regular, color: Theme.of(context).colorScheme.error, size: 14, ), DidvanText( _error ?? '', style: Theme.of(context).textTheme.bodySmall, color: Theme.of(context).colorScheme.error, ), ], ), ], ), ) ], ); } Color _borderColor() { if (_focusNode.hasFocus) { return Theme.of(context).colorScheme.focusedBorder; } else if (_error != null) { return Theme.of(context).colorScheme.error; } return Theme.of(context).colorScheme.border; } Color? _titleColor() { if (!widget.enabled) { return Theme.of(context).colorScheme.hint; } if (_error != null) { return Theme.of(context).colorScheme.error; } return null; } Color _fillColor() { if (!widget.enabled) { return DesignConfig.isDark ? Theme.of(context).colorScheme.disabledBackground : Theme.of(context).colorScheme.secondCTA; } if (_focusNode.hasFocus) { return Theme.of(context).colorScheme.focused; } if (_error != null) { return Theme.of(context).colorScheme.errorBack; } return Theme.of(context).colorScheme.surface; } Widget? _suffixBuilder() { if (widget.obsecureText) { return FittedBox( fit: BoxFit.scaleDown, child: GestureDetector( onTap: () { setState(() { _hideContent = !_hideContent; }); }, child: Icon( _hideContent ? DidvanIcons.eye_solid : DidvanIcons.eye_close_solid, ), ), ); } return null; } void _onChanged(String value) { setState(() { _error = null; }); value = value.toEnglishDigit(); widget.onChanged?.call(value); } String? _validator(String? value) { if (widget.validator != null) { final String? error = widget.validator!(value!); if (error != null) { setState(() { _error = error; }); return ''; } else { setState(() { _error = null; }); } } return null; } @override void dispose() { _controller.dispose(); super.dispose(); } }