import 'package:flutter/services.dart'; /// Format français : 10 chiffres affichés par paires (ex. 06 12 34 56 78). /// Ne garde que les chiffres (max 10). String normalizePhone(String raw) { final digits = raw.replaceAll(RegExp(r'\D'), ''); return digits.length > 10 ? digits.substring(0, 10) : digits; } /// Retourne le numéro formaté pour l'affichage (ex. "06 12 34 56 78"). /// Si [raw] est vide après normalisation, retourne [raw] tel quel (pour afficher "–" etc.). String formatPhoneForDisplay(String raw) { if (raw.trim().isEmpty) return raw; final normalized = normalizePhone(raw); if (normalized.isEmpty) return raw; final buffer = StringBuffer(); for (var i = 0; i < normalized.length; i++) { if (i > 0 && i.isEven) buffer.write(' '); buffer.write(normalized[i]); } return buffer.toString(); } /// Formatter de saisie : uniquement chiffres, espaces automatiques toutes les 2 chiffres, max 10 chiffres. class FrenchPhoneNumberFormatter extends TextInputFormatter { const FrenchPhoneNumberFormatter(); @override TextEditingValue formatEditUpdate( TextEditingValue oldValue, TextEditingValue newValue, ) { final digits = newValue.text.replaceAll(RegExp(r'\D'), ''); final normalized = digits.length > 10 ? digits.substring(0, 10) : digits; final buffer = StringBuffer(); for (var i = 0; i < normalized.length; i++) { if (i > 0 && i.isEven) buffer.write(' '); buffer.write(normalized[i]); } final formatted = buffer.toString(); // Conserver la position du curseur : compter les chiffres avant la sélection final sel = newValue.selection; final digitsBeforeCursor = newValue.text .substring(0, sel.start.clamp(0, newValue.text.length)) .replaceAll(RegExp(r'\D'), '') .length; final newOffset = digitsBeforeCursor + (digitsBeforeCursor > 0 ? digitsBeforeCursor ~/ 2 : 0); final clampedOffset = newOffset.clamp(0, formatted.length); return TextEditingValue( text: formatted, selection: TextSelection.collapsed(offset: clampedOffset), ); } }