Implement message deletion functionality: add isDeleted flag to Message model, update deleteMessage method in MessageRepository, and adjust chat display for deleted messages.

This commit is contained in:
Van Leemput Dayron
2025-11-14 00:54:28 +01:00
parent 79cf3f4655
commit 258f10b42b
5 changed files with 42 additions and 60 deletions

View File

@@ -28,8 +28,9 @@ import '../../blocs/account/account_state.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:travel_mate/components/error/error_content.dart'; import 'package:travel_mate/components/error/error_content.dart';
import '../../blocs/user/user_state.dart' as user_state; import '../../blocs/user/user_state.dart' as user_state;
import '../../repositories/group_repository.dart'; // Ajouter cet import import '../../repositories/group_repository.dart';
import 'group_expenses_page.dart'; // Ajouter cet import import '../widgets/user_state_widget.dart';
import 'group_expenses_page.dart';
/// Widget that displays the account content page with account management functionality. /// Widget that displays the account content page with account management functionality.
class AccountContent extends StatefulWidget { class AccountContent extends StatefulWidget {
@@ -132,33 +133,13 @@ class _AccountContentState extends State<AccountContent> {
/// Widget representing the complete account page UI /// Widget representing the complete account page UI
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<UserBloc, user_state.UserState>( return UserStateWrapper(
builder: (context, userState) { builder: (context, user) {
if (userState is user_state.UserLoading) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
if (userState is user_state.UserError) {
return ErrorContent(
message: 'User error: ${userState.message}',
onRetry: () {},
);
}
if (userState is! user_state.UserLoaded) {
return const Scaffold(
body: Center(child: Text('User not connected')),
);
}
final user = userState.user;
return BlocConsumer<AccountBloc, AccountState>( return BlocConsumer<AccountBloc, AccountState>(
listener: (context, accountState) { listener: (context, accountState) {
if (accountState is AccountError) { if (accountState is AccountError) {
ErrorContent( ErrorContent(
message: 'Account loading error: ${accountState.message}', message: 'Erreur de chargement des comptes : ${accountState.message}',
onRetry: () { onRetry: () {
context.read<AccountBloc>().add(LoadAccountsByUserId(user.id)); context.read<AccountBloc>().add(LoadAccountsByUserId(user.id));
}, },
@@ -167,11 +148,21 @@ class _AccountContentState extends State<AccountContent> {
}, },
builder: (context, accountState) { builder: (context, accountState) {
return Scaffold( return Scaffold(
body: SafeArea(child: _buildContent(accountState, user.id)) body: SafeArea(child: _buildContent(accountState, user.id)),
); );
}, },
); );
}, },
loadingWidget: const Scaffold(
body: Center(child: CircularProgressIndicator()),
),
errorWidget: ErrorContent(
message: 'User error',
onRetry: () {},
),
noUserWidget: const Scaffold(
body: Center(child: Text('Utilisateur non connecté')),
),
); );
} }
@@ -196,7 +187,7 @@ class _AccountContentState extends State<AccountContent> {
children: [ children: [
CircularProgressIndicator(), CircularProgressIndicator(),
SizedBox(height: 16), SizedBox(height: 16),
Text('Loading accounts...'), Text('Chargement des comptes...'),
], ],
), ),
); );
@@ -204,7 +195,7 @@ class _AccountContentState extends State<AccountContent> {
if (accountState is AccountError) { if (accountState is AccountError) {
return ErrorContent( return ErrorContent(
message: 'Account loading error...', message: 'Erreur de chargement des comptes...',
onRetry: () { onRetry: () {
context.read<AccountBloc>().add(LoadAccountsByUserId(userId)); context.read<AccountBloc>().add(LoadAccountsByUserId(userId));
}, },
@@ -222,13 +213,13 @@ class _AccountContentState extends State<AccountContent> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const Text('Unknown state'), const Text('État inconnu'),
const SizedBox(height: 16), const SizedBox(height: 16),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
context.read<AccountBloc>().add(LoadAccountsByUserId(userId)); context.read<AccountBloc>().add(LoadAccountsByUserId(userId));
}, },
child: const Text('Load accounts'), child: const Text('Charger les comptes'),
), ),
], ],
), ),
@@ -258,7 +249,7 @@ class _AccountContentState extends State<AccountContent> {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
const Text( const Text(
'Accounts are automatically created when you create a trip', 'Les comptes sont créés automatiquement lorsque vous créez des voyages.',
style: TextStyle(fontSize: 14, color: Colors.grey), style: TextStyle(fontSize: 14, color: Colors.grey),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
@@ -289,18 +280,7 @@ class _AccountContentState extends State<AccountContent> {
child: ListView( child: ListView(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
children: [ children: [
const Text( ...accounts.map((account) {
'My accounts',
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Manage your travel accounts',
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
),
const SizedBox(height: 24),
...accounts.map((account) {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.only(bottom: 12),
child: _buildSimpleAccountCard(account), child: _buildSimpleAccountCard(account),

View File

@@ -476,8 +476,12 @@ class _ChatGroupContentState extends State<ChatGroupContent> {
const SizedBox(height: 4), const SizedBox(height: 4),
], ],
Text( Text(
message.text, message.isDeleted ? 'a supprimé un message' : message.text,
style: TextStyle(fontSize: 15, color: textColor), style: TextStyle(
fontSize: 15,
color: message.isDeleted ? textColor.withValues(alpha: 0.5) : textColor,
fontStyle: message.isDeleted ? FontStyle.italic : FontStyle.normal,
),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
Row( Row(

View File

@@ -127,17 +127,6 @@ class _GroupContentState extends State<GroupContent> {
child: ListView( child: ListView(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
children: [ children: [
const Text(
'Mes groupes',
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Discutez avec les participants',
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
),
const SizedBox(height: 24),
...groups.map((group) { ...groups.map((group) {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.only(bottom: 12),

View File

@@ -10,6 +10,7 @@ class Message {
final Map<String, String> reactions; // userId -> emoji final Map<String, String> reactions; // userId -> emoji
final DateTime? editedAt; final DateTime? editedAt;
final bool isEdited; final bool isEdited;
final bool isDeleted;
Message({ Message({
this.id = '', this.id = '',
@@ -21,6 +22,7 @@ class Message {
this.reactions = const {}, this.reactions = const {},
this.editedAt, this.editedAt,
this.isEdited = false, this.isEdited = false,
this.isDeleted = false,
}); });
factory Message.fromFirestore(DocumentSnapshot doc) { factory Message.fromFirestore(DocumentSnapshot doc) {
@@ -39,6 +41,7 @@ class Message {
reactions: reactionsData?.map((key, value) => MapEntry(key, value.toString())) ?? {}, reactions: reactionsData?.map((key, value) => MapEntry(key, value.toString())) ?? {},
editedAt: editedAtTimestamp?.toDate(), editedAt: editedAtTimestamp?.toDate(),
isEdited: data['isEdited'] ?? false, isEdited: data['isEdited'] ?? false,
isDeleted: data['isDeleted'] ?? false,
); );
} }
@@ -52,6 +55,7 @@ class Message {
'reactions': reactions, 'reactions': reactions,
'editedAt': editedAt != null ? Timestamp.fromDate(editedAt!) : null, 'editedAt': editedAt != null ? Timestamp.fromDate(editedAt!) : null,
'isEdited': isEdited, 'isEdited': isEdited,
'isDeleted': isDeleted,
}; };
} }
@@ -65,6 +69,7 @@ class Message {
Map<String, String>? reactions, Map<String, String>? reactions,
DateTime? editedAt, DateTime? editedAt,
bool? isEdited, bool? isEdited,
bool? isDeleted,
}) { }) {
return Message( return Message(
id: id ?? this.id, id: id ?? this.id,
@@ -76,6 +81,7 @@ class Message {
reactions: reactions ?? this.reactions, reactions: reactions ?? this.reactions,
editedAt: editedAt ?? this.editedAt, editedAt: editedAt ?? this.editedAt,
isEdited: isEdited ?? this.isEdited, isEdited: isEdited ?? this.isEdited,
isDeleted: isDeleted ?? this.isDeleted,
); );
} }
} }

View File

@@ -42,7 +42,7 @@ class MessageRepository {
}); });
} }
// Supprimer un message // Supprimer un message (marquer comme supprimé)
Future<void> deleteMessage({ Future<void> deleteMessage({
required String groupId, required String groupId,
required String messageId, required String messageId,
@@ -52,7 +52,10 @@ class MessageRepository {
.doc(groupId) .doc(groupId)
.collection('messages') .collection('messages')
.doc(messageId) .doc(messageId)
.delete(); .update({
'isDeleted': true,
'text': '',
});
} }
// Modifier un message // Modifier un message