import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../core/theme.dart'; class CustomTextField extends StatefulWidget { final String label; final String? hint; final TextEditingController controller; final bool isPassword; final String? Function(String?)? validator; final String? errorText; final Widget? prefixIcon; final Widget? suffixIcon; final TextInputType keyboardType; final bool readOnly; final VoidCallback? onTap; final ValueChanged? onChanged; final int maxLines; final List? inputFormatters; const CustomTextField({ Key? key, required this.controller, required this.label, this.hint, this.isPassword = false, this.validator, this.errorText, this.prefixIcon, this.suffixIcon, this.keyboardType = TextInputType.text, this.readOnly = false, this.onTap, this.onChanged, this.maxLines = 1, this.inputFormatters, }) : super(key: key); @override State createState() => _CustomTextFieldState(); } class _CustomTextFieldState extends State { bool _obscureText = true; late FocusNode _focusNode; bool _isFocused = false; @override void initState() { super.initState(); _focusNode = FocusNode(); _focusNode.addListener(() { setState(() { _isFocused = _focusNode.hasFocus; }); }); } @override void dispose() { _focusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.label, style: AppTheme.labelMedium.copyWith(color: AppTheme.textSecondary), ), const SizedBox(height: AppTheme.spacingXs), AnimatedContainer( duration: const Duration(milliseconds: 200), decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppTheme.radiusLg), boxShadow: [ if (_isFocused) BoxShadow( color: AppTheme.primaryBlue.withValues(alpha: 0.15), blurRadius: 12, spreadRadius: 2, offset: const Offset(0, 4), ) else BoxShadow( color: AppTheme.primaryDark.withValues(alpha: 0.03), blurRadius: 6, spreadRadius: 0, offset: const Offset(0, 2), ), ], ), child: TextFormField( controller: widget.controller, focusNode: _focusNode, obscureText: widget.isPassword ? _obscureText : false, validator: widget.validator, keyboardType: widget.keyboardType, readOnly: widget.readOnly, onTap: widget.onTap, onChanged: widget.onChanged, maxLines: widget.maxLines, inputFormatters: widget.inputFormatters, style: AppTheme.bodyMedium, decoration: InputDecoration( hintText: widget.hint, hintStyle: AppTheme.bodyMedium.copyWith(color: AppTheme.textTertiary), fillColor: AppTheme.bgWhite, filled: true, contentPadding: const EdgeInsets.all(AppTheme.spacingMd), border: OutlineInputBorder( borderRadius: BorderRadius.circular(AppTheme.radiusLg), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(AppTheme.radiusLg), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(AppTheme.radiusLg), borderSide: const BorderSide(color: AppTheme.primaryBlue, width: 1.5), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(AppTheme.radiusMd), borderSide: const BorderSide(color: AppTheme.statusRed, width: 1.5), ), errorText: widget.errorText, prefixIcon: widget.prefixIcon != null ? AnimatedScale( scale: _isFocused ? 1.05 : 1.0, duration: const Duration(milliseconds: 200), child: widget.prefixIcon, ) : null, suffixIcon: widget.isPassword ? IconButton( icon: AnimatedScale( scale: _isFocused ? 1.05 : 1.0, duration: const Duration(milliseconds: 200), child: Icon( _obscureText ? Icons.visibility_off_outlined : Icons.visibility_outlined, color: _isFocused ? AppTheme.primaryBlue : AppTheme.textSecondary, ), ), onPressed: () { setState(() { _obscureText = !_obscureText; }); }, ) : widget.suffixIcon, ), ), ), ], ); } }