import 'package:flutter/material.dart'; import 'package:intl_phone_field/intl_phone_field.dart'; import 'package:intl_phone_field/phone_number.dart'; import 'package:provider/provider.dart'; import '../Provider/language_provider.dart'; import '../config/country_list_beem.dart'; import '../utils/colors.dart'; import 'custom_text.dart'; class CustomPhoneInputField extends StatefulWidget { final TextEditingController? controller; final bool isArabic; final bool test; final Function(PhoneNumber)? onNumberChange; final String? Function(PhoneNumber?)? validator; final bool? isRequired; const CustomPhoneInputField({ Key? key, this.controller, this.isArabic = false, this.test = false, this.onNumberChange, this.validator, this.isRequired, }) : super(key: key); @override State createState() => _CustomPhoneInputFieldState(); } class _CustomPhoneInputFieldState extends State with SingleTickerProviderStateMixin { bool _isFocused = false; bool _hasContent = false; late AnimationController _animationController; late Animation _scaleAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 200), vsync: this, ); _scaleAnimation = Tween(begin: 1.0, end: 1.02).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); widget.controller?.addListener(() { setState(() { _hasContent = widget.controller!.text.isNotEmpty; }); }); } @override void dispose() { _animationController.dispose(); super.dispose(); } // Custom validator function // Custom validator function // Custom validator function String? _customValidator(PhoneNumber? phoneNumber) { // If a custom validator is provided, use it if (widget.validator != null) { final customResult = widget.validator!(phoneNumber); if (customResult != null) { return customResult; } } // If field is optional and empty, return null (no error) if (widget.isRequired == false && (phoneNumber == null || phoneNumber.number.isEmpty)) { return null; } // If field is required and empty, return error if ((widget.isRequired == null || widget.isRequired == true) && (phoneNumber == null || phoneNumber.number.isEmpty)) { return 'Phone number is required'; } // For test mode, skip the digit count validation if (widget.test) { return null; } // Normal validation - check if phone number has exactly 8 digits if (phoneNumber != null && phoneNumber.number.length != 8) { return 'Phone number must be 8 digits'; } return null; } @override Widget build(BuildContext context) { final languageProvider = context.watch(); final theme = Theme.of(context); final isDarkMode = theme.brightness == Brightness.dark; final Color activeColor = theme.primaryColor; return Padding( padding: const EdgeInsets.symmetric(horizontal: 5.0), child: AnimatedBuilder( animation: _scaleAnimation, builder: (context, child) { return Transform.scale( scale: _scaleAnimation.value, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), boxShadow: _isFocused ? [ BoxShadow( color: activeColor.withOpacity(0.2), blurRadius: 8, offset: const Offset(0, 4), ), ] : [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: IntlPhoneField( controller: widget.controller, validator: _customValidator, // Use our custom validator keyboardType: TextInputType.number, languageCode: widget.isArabic ? 'ar' : 'en', onChanged: (phoneNumber) { setState(() { _hasContent = phoneNumber.number.isNotEmpty; }); if (widget.onNumberChange != null) { widget.onNumberChange!(phoneNumber); } }, onTap: () { setState(() { _isFocused = true; }); _animationController.forward(); }, countries: countries, initialCountryCode: 'TN', dropdownIcon: Icon( Icons.expand_more, color: _isFocused || _hasContent ? activeColor : isDarkMode ? AppColors.whiteBackgroundColor : AppColors.blackBackgroundColor, size: 22, ), style: TextStyle( fontFamily: 'Poppins', fontSize: 16, color: isDarkMode ? AppColors.whiteBackgroundColor : AppColors.blackBackgroundColor, fontWeight: FontWeight.w500, ), flagsButtonPadding: const EdgeInsets.symmetric(horizontal: 12), dropdownTextStyle: TextStyle( fontFamily: 'Poppins', fontSize: 14, color: isDarkMode ? AppColors.whiteBackgroundColor : AppColors.blackBackgroundColor, ), textAlign: widget.isArabic ? TextAlign.right : TextAlign.left, textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( filled: true, fillColor: _isFocused ? isDarkMode ? AppColors.blackBackgroundColor : AppColors.darkSecondaryText2 : isDarkMode ? AppColors.blackBackgroundColor : AppColors.darkSecondaryText2, prefixIcon: Icon( Icons.phone, color: _isFocused || _hasContent ? activeColor : const Color(0xFFA2A2A2), size: 22, ), label: RichText( text: TextSpan( children: [ TextSpan( text: languageProvider.translate("Mobile number"), style: TextStyle( color: _isFocused || _hasContent ? activeColor : const Color(0xFFA2A2A2), fontSize: _isFocused || _hasContent ? 11 : 14, fontFamily: 'Poppins', fontWeight: _isFocused || _hasContent ? FontWeight.w600 : FontWeight.w400, ), ), if (widget.isRequired != null) ...[ if (widget.isRequired!) TextSpan( text: ' *', style: TextStyle( color: Colors.red, fontSize: _isFocused || _hasContent ? 11 : 14, fontFamily: 'Poppins', fontWeight: FontWeight.w600, ), ) else TextSpan( text: ' (Optional)', style: TextStyle( color: isDarkMode ? AppColors.darkSecondaryText.withOpacity(0.7) : const Color(0xFF999999), fontSize: _isFocused || _hasContent ? 10 : 12, fontFamily: 'Poppins', fontWeight: FontWeight.w400, fontStyle: FontStyle.italic, ), ), ], ], ), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.grey.shade200, width: 1.5, ), borderRadius: BorderRadius.circular(12), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: activeColor, width: 2.0, ), borderRadius: BorderRadius.circular(12), ), errorBorder: OutlineInputBorder( borderSide: const BorderSide( color: Colors.red, width: 1.5, ), borderRadius: BorderRadius.circular(12), ), focusedErrorBorder: OutlineInputBorder( borderSide: const BorderSide( color: Colors.red, width: 2.0, ), borderRadius: BorderRadius.circular(12), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 18, ), counterText: '', ), onSubmitted: (value) { setState(() { _isFocused = false; }); _animationController.reverse(); }, ), ), ); }, ), ); } }