feat(communication): module messagerie unifié + contact policies + blocages

Aligné avec le backend MessagingResource :
- Nouveau module communication (conversations, messages, participants)
- Respect des ContactPolicy (qui peut parler à qui par rôle)
- Gestion MemberBlock (blocages individuels)
- UI : conversations list, conversation detail, broadcast, tiles
- BLoC : MessagingBloc avec events (envoyer, démarrer conversation rôle, etc.)
This commit is contained in:
dahoud
2026-04-15 20:26:35 +00:00
parent 07b8488714
commit 45dcd2171e
23 changed files with 2096 additions and 1588 deletions

View File

@@ -1,83 +1,48 @@
/// Model de données Message avec sérialisation JSON
/// Modèle de données Message v4 avec sérialisation JSON
library message_model;
import 'package:json_annotation/json_annotation.dart';
import '../../domain/entities/message.dart';
part 'message_model.g.dart';
@JsonSerializable(explicitToJson: true)
/// Modèle Message v4
class MessageModel extends Message {
const MessageModel({
required super.id,
required super.conversationId,
required super.senderId,
required super.senderName,
super.senderAvatar,
required super.content,
required super.type,
required super.status,
super.priority,
required super.recipientIds,
super.recipientRoles,
super.organizationId,
required super.createdAt,
super.readAt,
super.metadata,
super.attachments,
super.isEdited,
super.editedAt,
super.isDeleted,
required super.typeMessage,
super.contenu,
super.urlFichier,
super.dureeAudio,
super.supprime,
super.expediteurId,
super.expediteurNom,
super.expediteurPrenom,
super.messageParentId,
super.messageParentApercu,
super.dateEnvoi,
});
factory MessageModel.fromJson(Map<String, dynamic> json) =>
_$MessageModelFromJson(json);
Map<String, dynamic> toJson() => _$MessageModelToJson(this);
factory MessageModel.fromEntity(Message message) {
factory MessageModel.fromJson(Map<String, dynamic> json) {
return MessageModel(
id: message.id,
conversationId: message.conversationId,
senderId: message.senderId,
senderName: message.senderName,
senderAvatar: message.senderAvatar,
content: message.content,
type: message.type,
status: message.status,
priority: message.priority,
recipientIds: message.recipientIds,
recipientRoles: message.recipientRoles,
organizationId: message.organizationId,
createdAt: message.createdAt,
readAt: message.readAt,
metadata: message.metadata,
attachments: message.attachments,
isEdited: message.isEdited,
editedAt: message.editedAt,
isDeleted: message.isDeleted,
id: json['id']?.toString() ?? '',
typeMessage: json['typeMessage']?.toString() ?? 'TEXTE',
contenu: json['contenu']?.toString(),
urlFichier: json['urlFichier']?.toString(),
dureeAudio: _parseInt(json['dureeAudio']),
supprime: json['supprime'] == true,
expediteurId: json['expediteurId']?.toString(),
expediteurNom: json['expediteurNom']?.toString(),
expediteurPrenom: json['expediteurPrenom']?.toString(),
messageParentId: json['messageParentId']?.toString(),
messageParentApercu: json['messageParentApercu']?.toString(),
dateEnvoi: json['dateEnvoi'] != null
? DateTime.tryParse(json['dateEnvoi'].toString())
: null,
);
}
Message toEntity() => Message(
id: id,
conversationId: conversationId,
senderId: senderId,
senderName: senderName,
senderAvatar: senderAvatar,
content: content,
type: type,
status: status,
priority: priority,
recipientIds: recipientIds,
recipientRoles: recipientRoles,
organizationId: organizationId,
createdAt: createdAt,
readAt: readAt,
metadata: metadata,
attachments: attachments,
isEdited: isEdited,
editedAt: editedAt,
isDeleted: isDeleted,
);
}
int? _parseInt(dynamic value) {
if (value == null) return null;
if (value is int) return value;
if (value is double) return value.toInt();
return int.tryParse(value.toString());
}