## Corrections Critiques ### Race Condition - Statuts de Messages - Fix : Les icônes de statut (✓, ✓✓, ✓✓ bleu) ne s'affichaient pas - Cause : WebSocket delivery confirmations arrivaient avant messages locaux - Solution : Pattern Optimistic UI dans chat_bloc.dart - Création message temporaire immédiate - Ajout à la liste AVANT requête HTTP - Remplacement par message serveur à la réponse - Fichier : lib/presentation/state_management/chat_bloc.dart ## Implémentation TODOs (13/21) ### Social (social_header_widget.dart) - ✅ Copier lien du post dans presse-papiers - ✅ Partage natif via Share.share() - ✅ Dialogue de signalement avec 5 raisons ### Partage (share_post_dialog.dart) - ✅ Interface sélection d'amis avec checkboxes - ✅ Partage externe via Share API ### Média (media_upload_service.dart) - ✅ Parsing JSON réponse backend - ✅ Méthode deleteMedia() pour suppression - ✅ Génération miniature vidéo ### Posts (create_post_dialog.dart, edit_post_dialog.dart) - ✅ Extraction URL depuis uploads - ✅ Documentation chargement médias ### Chat (conversations_screen.dart) - ✅ Navigation vers notifications - ✅ ConversationSearchDelegate pour recherche ## Nouveaux Fichiers ### Configuration - build-prod.ps1 : Script build production avec dart-define - lib/core/constants/env_config.dart : Gestion environnements ### Documentation - TODOS_IMPLEMENTED.md : Documentation complète TODOs ## Améliorations ### Architecture - Refactoring injection de dépendances - Amélioration routing et navigation - Optimisation providers (UserProvider, FriendsProvider) ### UI/UX - Amélioration thème et couleurs - Optimisation animations - Meilleure gestion erreurs ### Services - Configuration API avec env_config - Amélioration datasources (events, users) - Optimisation modèles de données
244 lines
6.9 KiB
Dart
244 lines
6.9 KiB
Dart
/// Classe utilitaire pour la validation des champs de formulaire.
|
|
///
|
|
/// Cette classe fournit des méthodes statiques pour valider différents
|
|
/// types de données d'entrée utilisateur.
|
|
///
|
|
/// **Usage:**
|
|
/// ```dart
|
|
/// final emailError = Validators.validateEmail(emailController.text);
|
|
/// if (emailError != null) {
|
|
/// // Afficher l'erreur
|
|
/// }
|
|
/// ```
|
|
class Validators {
|
|
/// Constructeur privé pour empêcher l'instanciation
|
|
Validators._();
|
|
|
|
/// Expression régulière pour valider les emails
|
|
static final RegExp _emailRegex = RegExp(
|
|
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
|
|
);
|
|
|
|
/// Expression régulière pour valider les mots de passe forts
|
|
/// (au moins 8 caractères, une majuscule, une minuscule, un chiffre)
|
|
static final RegExp _strongPasswordRegex = RegExp(
|
|
r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{8,}$',
|
|
);
|
|
|
|
/// Valide une adresse email.
|
|
///
|
|
/// [value] La valeur à valider
|
|
///
|
|
/// Returns `null` si l'email est valide, sinon un message d'erreur.
|
|
///
|
|
/// **Exemple:**
|
|
/// ```dart
|
|
/// final error = Validators.validateEmail('user@example.com');
|
|
/// // Retourne null si valide
|
|
/// ```
|
|
static String? validateEmail(String? value) {
|
|
if (value == null || value.trim().isEmpty) {
|
|
return 'Veuillez entrer votre email';
|
|
}
|
|
|
|
final trimmedValue = value.trim();
|
|
|
|
if (!_emailRegex.hasMatch(trimmedValue)) {
|
|
return 'Veuillez entrer un email valide';
|
|
}
|
|
|
|
// Validation supplémentaire de la longueur
|
|
if (trimmedValue.length > 254) {
|
|
return 'L\'email est trop long (maximum 254 caractères)';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// Valide un mot de passe.
|
|
///
|
|
/// [value] La valeur à valider
|
|
/// [minLength] Longueur minimale requise (par défaut: 6)
|
|
/// [requireStrong] Si true, exige un mot de passe fort (par défaut: false)
|
|
///
|
|
/// Returns `null` si le mot de passe est valide, sinon un message d'erreur.
|
|
///
|
|
/// **Exemple:**
|
|
/// ```dart
|
|
/// final error = Validators.validatePassword('password123', minLength: 8);
|
|
/// // Retourne null si valide
|
|
/// ```
|
|
static String? validatePassword(
|
|
String? value, {
|
|
int minLength = 6,
|
|
bool requireStrong = false,
|
|
}) {
|
|
if (value == null || value.isEmpty) {
|
|
return 'Veuillez entrer votre mot de passe';
|
|
}
|
|
|
|
if (value.length < minLength) {
|
|
return 'Le mot de passe doit comporter au moins $minLength caractères';
|
|
}
|
|
|
|
if (requireStrong && !_strongPasswordRegex.hasMatch(value)) {
|
|
return 'Le mot de passe doit contenir au moins une majuscule, '
|
|
'une minuscule et un chiffre';
|
|
}
|
|
|
|
// Validation de la longueur maximale
|
|
if (value.length > 128) {
|
|
return 'Le mot de passe est trop long (maximum 128 caractères)';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// Valide que deux mots de passe correspondent.
|
|
///
|
|
/// [password] Le premier mot de passe
|
|
/// [confirmPassword] Le mot de passe de confirmation
|
|
///
|
|
/// Returns `null` si les mots de passe correspondent, sinon un message d'erreur.
|
|
///
|
|
/// **Exemple:**
|
|
/// ```dart
|
|
/// final error = Validators.validatePasswordMatch(
|
|
/// 'password123',
|
|
/// 'password123',
|
|
/// );
|
|
/// // Retourne null si correspond
|
|
/// ```
|
|
static String? validatePasswordMatch(String? password, String? confirmPassword) {
|
|
if (password == null || password.isEmpty) {
|
|
return 'Veuillez entrer votre mot de passe';
|
|
}
|
|
|
|
if (confirmPassword == null || confirmPassword.isEmpty) {
|
|
return 'Veuillez confirmer votre mot de passe';
|
|
}
|
|
|
|
if (password != confirmPassword) {
|
|
return 'Les mots de passe ne correspondent pas';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// Valide un nom (prénom ou nom de famille).
|
|
///
|
|
/// [value] La valeur à valider
|
|
/// [fieldName] Le nom du champ (pour le message d'erreur)
|
|
///
|
|
/// Returns `null` si le nom est valide, sinon un message d'erreur.
|
|
static String? validateName(String? value, {String fieldName = 'ce champ'}) {
|
|
if (value == null || value.trim().isEmpty) {
|
|
return 'Veuillez entrer $fieldName';
|
|
}
|
|
|
|
final trimmedValue = value.trim();
|
|
|
|
if (trimmedValue.length < 2) {
|
|
return '$fieldName doit contenir au moins 2 caractères';
|
|
}
|
|
|
|
if (trimmedValue.length > 100) {
|
|
return '$fieldName est trop long (maximum 100 caractères)';
|
|
}
|
|
|
|
// Validation des caractères (lettres, espaces, tirets, apostrophes)
|
|
if (!RegExp(r"^[a-zA-ZÀ-ÿ\s\-']+$").hasMatch(trimmedValue)) {
|
|
return '$fieldName ne doit contenir que des lettres';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// Valide un numéro de téléphone.
|
|
///
|
|
/// [value] La valeur à valider
|
|
///
|
|
/// Returns `null` si le numéro est valide, sinon un message d'erreur.
|
|
static String? validatePhoneNumber(String? value) {
|
|
if (value == null || value.trim().isEmpty) {
|
|
return 'Veuillez entrer votre numéro de téléphone';
|
|
}
|
|
|
|
final trimmedValue = value.trim().replaceAll(RegExp(r'[\s\-\(\)]'), '');
|
|
|
|
// Validation du format (10 chiffres pour la France)
|
|
if (!RegExp(r'^\+?[0-9]{10,15}$').hasMatch(trimmedValue)) {
|
|
return 'Veuillez entrer un numéro de téléphone valide';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// Valide une URL.
|
|
///
|
|
/// [value] La valeur à valider
|
|
///
|
|
/// Returns `null` si l'URL est valide, sinon un message d'erreur.
|
|
static String? validateUrl(String? value) {
|
|
if (value == null || value.trim().isEmpty) {
|
|
return 'Veuillez entrer une URL';
|
|
}
|
|
|
|
final trimmedValue = value.trim();
|
|
|
|
try {
|
|
final uri = Uri.parse(trimmedValue);
|
|
if (!uri.hasScheme || !uri.hasAuthority) {
|
|
return 'Veuillez entrer une URL valide';
|
|
}
|
|
return null;
|
|
} catch (e) {
|
|
return 'Veuillez entrer une URL valide';
|
|
}
|
|
}
|
|
|
|
/// Valide qu'un champ n'est pas vide.
|
|
///
|
|
/// [value] La valeur à valider
|
|
/// [fieldName] Le nom du champ (pour le message d'erreur)
|
|
///
|
|
/// Returns `null` si le champ n'est pas vide, sinon un message d'erreur.
|
|
static String? validateRequired(String? value, {String fieldName = 'ce champ'}) {
|
|
if (value == null || value.trim().isEmpty) {
|
|
return 'Veuillez remplir $fieldName';
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// Valide la longueur d'une chaîne.
|
|
///
|
|
/// [value] La valeur à valider
|
|
/// [minLength] Longueur minimale
|
|
/// [maxLength] Longueur maximale
|
|
/// [fieldName] Le nom du champ (pour le message d'erreur)
|
|
///
|
|
/// Returns `null` si la longueur est valide, sinon un message d'erreur.
|
|
static String? validateLength(
|
|
String? value, {
|
|
int? minLength,
|
|
int? maxLength,
|
|
String fieldName = 'ce champ',
|
|
}) {
|
|
if (value == null) {
|
|
return 'Veuillez remplir $fieldName';
|
|
}
|
|
|
|
final length = value.length;
|
|
|
|
if (minLength != null && length < minLength) {
|
|
return '$fieldName doit contenir au moins $minLength caractères';
|
|
}
|
|
|
|
if (maxLength != null && length > maxLength) {
|
|
return '$fieldName ne doit pas dépasser $maxLength caractères';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|