## 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
225 lines
6.9 KiB
Dart
225 lines
6.9 KiB
Dart
import '../../core/constants/env_config.dart';
|
|
import '../../core/utils/app_logger.dart';
|
|
import '../../domain/entities/user.dart';
|
|
|
|
/// Modèle de données pour les utilisateurs (Data Transfer Object).
|
|
///
|
|
/// Cette classe est responsable de la sérialisation/désérialisation
|
|
/// avec l'API backend et convertit vers/depuis l'entité de domaine [User].
|
|
///
|
|
/// **Usage:**
|
|
/// ```dart
|
|
/// // Depuis JSON
|
|
/// final user = UserModel.fromJson(jsonData);
|
|
///
|
|
/// // Vers JSON
|
|
/// final json = user.toJson();
|
|
///
|
|
/// // Vers entité de domaine
|
|
/// final entity = user.toEntity();
|
|
/// ```
|
|
class UserModel extends User {
|
|
/// Crée une nouvelle instance de [UserModel].
|
|
///
|
|
/// [userId] L'identifiant unique de l'utilisateur
|
|
/// [userLastName] Le nom de famille de l'utilisateur
|
|
/// [userFirstName] Le prénom de l'utilisateur
|
|
/// [email] L'adresse email de l'utilisateur
|
|
/// [motDePasse] Le mot de passe (hashé côté serveur)
|
|
/// [profileImageUrl] L'URL de l'image de profil
|
|
/// [eventsCount] Le nombre d'événements créés (optionnel)
|
|
/// [friendsCount] Le nombre d'amis (optionnel)
|
|
/// [postsCount] Le nombre de posts (optionnel)
|
|
/// [visitedPlacesCount] Le nombre de lieux visités (optionnel)
|
|
const UserModel({
|
|
required super.userId,
|
|
required super.userLastName,
|
|
required super.userFirstName,
|
|
required super.email,
|
|
required super.motDePasse,
|
|
required super.profileImageUrl,
|
|
super.isVerified,
|
|
super.eventsCount,
|
|
super.friendsCount,
|
|
super.postsCount,
|
|
super.visitedPlacesCount,
|
|
});
|
|
|
|
/// Crée un [UserModel] à partir d'un JSON reçu depuis l'API.
|
|
///
|
|
/// [json] Les données JSON à parser
|
|
///
|
|
/// Returns un [UserModel] avec les données parsées
|
|
///
|
|
/// **Note:** Les valeurs par défaut sont utilisées si des champs sont manquants.
|
|
///
|
|
/// **Exemple:**
|
|
/// ```dart
|
|
/// final json = {
|
|
/// 'userId': '123',
|
|
/// 'nom': 'Doe',
|
|
/// 'prenoms': 'John',
|
|
/// 'email': 'john@example.com',
|
|
/// };
|
|
/// final user = UserModel.fromJson(json);
|
|
/// ```
|
|
factory UserModel.fromJson(Map<String, dynamic> json) {
|
|
try {
|
|
// Le backend peut renvoyer 'uuid' ou 'userId', on accepte les deux
|
|
final userId = _parseString(json, 'userId', '') != ''
|
|
? _parseString(json, 'userId', '')
|
|
: _parseString(json, 'uuid', '');
|
|
|
|
return UserModel(
|
|
userId: userId.isNotEmpty ? userId : (json['uuid']?.toString() ?? json['userId']?.toString() ?? ''),
|
|
userLastName: _parseString(json, 'nom', 'Inconnu'),
|
|
userFirstName: _parseString(json, 'prenoms', 'Inconnu'),
|
|
email: _parseString(json, 'email', ''),
|
|
motDePasse: _parseString(json, 'motDePasse', ''),
|
|
profileImageUrl: _parseString(json, 'profileImageUrl', ''),
|
|
isVerified: json['isVerified'] as bool? ?? false,
|
|
eventsCount: _parseInt(json, 'eventsCount') ?? 0,
|
|
friendsCount: _parseInt(json, 'friendsCount') ?? 0,
|
|
postsCount: _parseInt(json, 'postsCount') ?? 0,
|
|
visitedPlacesCount: _parseInt(json, 'visitedPlacesCount') ?? 0,
|
|
);
|
|
} catch (e, stackTrace) {
|
|
AppLogger.e('Erreur lors du parsing JSON', error: e, stackTrace: stackTrace, tag: 'UserModel');
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
/// Parse une valeur string depuis le JSON avec valeur par défaut.
|
|
static String _parseString(
|
|
Map<String, dynamic> json,
|
|
String key,
|
|
String defaultValue,
|
|
) {
|
|
final value = json[key];
|
|
if (value == null) return defaultValue;
|
|
return value.toString();
|
|
}
|
|
|
|
/// Parse une valeur int depuis le JSON (optionnel).
|
|
static int? _parseInt(Map<String, dynamic> json, String key) {
|
|
final value = json[key];
|
|
if (value == null) return null;
|
|
if (value is int) return value;
|
|
if (value is String) {
|
|
return int.tryParse(value);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// Convertit ce [UserModel] en JSON pour l'envoi vers l'API.
|
|
///
|
|
/// Returns une [Map] contenant les données de l'utilisateur
|
|
///
|
|
/// **Note:** Le mot de passe est envoyé en clair (hashé côté serveur).
|
|
///
|
|
/// **Exemple:**
|
|
/// ```dart
|
|
/// final user = UserModel(...);
|
|
/// final json = user.toJson();
|
|
/// // Envoyer json à l'API
|
|
/// ```
|
|
@override
|
|
Map<String, dynamic> toJson() {
|
|
final json = <String, dynamic>{
|
|
if (userId.isNotEmpty) 'id': userId,
|
|
'nom': userLastName,
|
|
'prenoms': userFirstName,
|
|
'email': email,
|
|
if (motDePasse.isNotEmpty) 'motDePasse': motDePasse,
|
|
if (profileImageUrl.isNotEmpty) 'profileImageUrl': profileImageUrl,
|
|
};
|
|
|
|
// Ajouter les compteurs optionnels s'ils sont présents
|
|
if (eventsCount != null) {
|
|
json['eventsCount'] = eventsCount;
|
|
}
|
|
if (friendsCount != null) {
|
|
json['friendsCount'] = friendsCount;
|
|
}
|
|
if (postsCount != null) {
|
|
json['postsCount'] = postsCount;
|
|
}
|
|
if (visitedPlacesCount != null) {
|
|
json['visitedPlacesCount'] = visitedPlacesCount;
|
|
}
|
|
|
|
return json;
|
|
}
|
|
|
|
/// Convertit ce modèle vers une entité de domaine [User].
|
|
///
|
|
/// Returns une instance de [User] avec les mêmes données
|
|
///
|
|
/// **Exemple:**
|
|
/// ```dart
|
|
/// final model = UserModel.fromJson(json);
|
|
/// final entity = model.toEntity();
|
|
/// ```
|
|
User toEntity() {
|
|
return User(
|
|
userId: userId,
|
|
userLastName: userLastName,
|
|
userFirstName: userFirstName,
|
|
email: email,
|
|
motDePasse: motDePasse,
|
|
profileImageUrl: profileImageUrl,
|
|
eventsCount: eventsCount,
|
|
friendsCount: friendsCount,
|
|
postsCount: postsCount,
|
|
visitedPlacesCount: visitedPlacesCount,
|
|
);
|
|
}
|
|
|
|
/// Crée une copie de ce [UserModel] avec des valeurs modifiées.
|
|
///
|
|
/// Tous les paramètres sont optionnels. Seuls les paramètres fournis
|
|
/// seront modifiés dans la nouvelle instance.
|
|
///
|
|
/// **Exemple:**
|
|
/// ```dart
|
|
/// final updated = user.copyWith(
|
|
/// userFirstName: 'Jane',
|
|
/// profileImageUrl: 'https://example.com/new-image.jpg',
|
|
/// );
|
|
/// ```
|
|
UserModel copyWith({
|
|
String? userId,
|
|
String? userLastName,
|
|
String? userFirstName,
|
|
String? email,
|
|
String? motDePasse,
|
|
String? profileImageUrl,
|
|
int? eventsCount,
|
|
int? friendsCount,
|
|
int? postsCount,
|
|
int? visitedPlacesCount,
|
|
}) {
|
|
return UserModel(
|
|
userId: userId ?? this.userId,
|
|
userLastName: userLastName ?? this.userLastName,
|
|
userFirstName: userFirstName ?? this.userFirstName,
|
|
email: email ?? this.email,
|
|
motDePasse: motDePasse ?? this.motDePasse,
|
|
profileImageUrl: profileImageUrl ?? this.profileImageUrl,
|
|
eventsCount: eventsCount ?? this.eventsCount,
|
|
friendsCount: friendsCount ?? this.friendsCount,
|
|
postsCount: postsCount ?? this.postsCount,
|
|
visitedPlacesCount: visitedPlacesCount ?? this.visitedPlacesCount,
|
|
);
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
return 'UserModel('
|
|
'userId: $userId, '
|
|
'name: $userFirstName $userLastName, '
|
|
'email: $email'
|
|
')';
|
|
}
|
|
}
|