- Backend: mail après inscription parent avec n° dossier, UPLOAD_PHOTOS_DIR, réponse API - Frontend: imageBytes + payload photo, utils email/code postal/téléphone, champs dédiés - Formulaires admin, login (focus), personal_info, child_card, custom_app_text_field Made-with: Cursor
128 lines
3.6 KiB
Dart
128 lines
3.6 KiB
Dart
import 'package:flutter/material.dart';
|
||
|
||
import '../utils/phone_utils.dart';
|
||
import 'custom_app_text_field.dart';
|
||
|
||
/// [TextFormField] téléphone France : formatage (0 automatique si 1–7, etc.) + validation optionnelle.
|
||
///
|
||
/// Préférer ce widget ou [frenchPhoneInputFormatters] + [validateFrenchNationalPhone] pour tout nouveau formulaire.
|
||
class FrenchPhoneTextFormField extends StatelessWidget {
|
||
const FrenchPhoneTextFormField({
|
||
super.key,
|
||
required this.controller,
|
||
this.decoration,
|
||
this.label,
|
||
this.hint,
|
||
this.allowEmpty = false,
|
||
this.readOnly = false,
|
||
this.focusNode,
|
||
this.autovalidateMode,
|
||
this.validator,
|
||
});
|
||
|
||
final TextEditingController controller;
|
||
final InputDecoration? decoration;
|
||
final String? label;
|
||
final String? hint;
|
||
final bool allowEmpty;
|
||
final bool readOnly;
|
||
final FocusNode? focusNode;
|
||
final AutovalidateMode? autovalidateMode;
|
||
final String? Function(String?)? validator;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final deco = decoration ??
|
||
InputDecoration(
|
||
labelText: label,
|
||
hintText: hint,
|
||
border: const OutlineInputBorder(),
|
||
);
|
||
|
||
return TextFormField(
|
||
controller: controller,
|
||
focusNode: focusNode,
|
||
readOnly: readOnly,
|
||
keyboardType: TextInputType.phone,
|
||
inputFormatters: frenchPhoneInputFormatters,
|
||
autovalidateMode: autovalidateMode,
|
||
decoration: deco,
|
||
validator: readOnly
|
||
? null
|
||
: (validator ??
|
||
(value) => validateFrenchNationalPhone(value, allowEmpty: allowEmpty)),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// Même logique que [FrenchPhoneTextFormField], avec le rendu [CustomAppTextField] (inscription, cartes, etc.).
|
||
class FrenchPhoneCustomTextField extends StatelessWidget {
|
||
const FrenchPhoneCustomTextField({
|
||
super.key,
|
||
required this.controller,
|
||
required this.labelText,
|
||
this.hintText = '',
|
||
this.focusNode,
|
||
this.fieldWidth = double.infinity,
|
||
this.fieldHeight = 53.0,
|
||
this.labelFontSize = 22.0,
|
||
this.inputFontSize = 20.0,
|
||
this.enabled = true,
|
||
this.readOnly = false,
|
||
this.allowEmpty = false,
|
||
this.style = CustomAppTextFieldStyle.beige,
|
||
this.validator,
|
||
this.suffixIcon,
|
||
this.onTap,
|
||
this.autofillHints,
|
||
this.textInputAction,
|
||
this.onFieldSubmitted,
|
||
});
|
||
|
||
final TextEditingController controller;
|
||
final String labelText;
|
||
final String hintText;
|
||
final FocusNode? focusNode;
|
||
final double fieldWidth;
|
||
final double fieldHeight;
|
||
final double labelFontSize;
|
||
final double inputFontSize;
|
||
final bool enabled;
|
||
final bool readOnly;
|
||
final bool allowEmpty;
|
||
final CustomAppTextFieldStyle style;
|
||
final String? Function(String?)? validator;
|
||
final IconData? suffixIcon;
|
||
final VoidCallback? onTap;
|
||
final Iterable<String>? autofillHints;
|
||
final TextInputAction? textInputAction;
|
||
final ValueChanged<String>? onFieldSubmitted;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return CustomAppTextField(
|
||
controller: controller,
|
||
focusNode: focusNode,
|
||
labelText: labelText,
|
||
hintText: hintText,
|
||
style: style,
|
||
fieldWidth: fieldWidth,
|
||
fieldHeight: fieldHeight,
|
||
labelFontSize: labelFontSize,
|
||
inputFontSize: inputFontSize,
|
||
keyboardType: TextInputType.phone,
|
||
enabled: enabled,
|
||
readOnly: readOnly,
|
||
onTap: onTap,
|
||
suffixIcon: suffixIcon,
|
||
inputFormatters: frenchPhoneInputFormatters,
|
||
autofillHints: autofillHints,
|
||
textInputAction: textInputAction,
|
||
onFieldSubmitted: onFieldSubmitted,
|
||
validator: validator ??
|
||
((v) => validateFrenchNationalPhone(v, allowEmpty: allowEmpty)),
|
||
isRequired: false,
|
||
);
|
||
}
|
||
}
|