Enhance group member management: add last name support in GroupMember model, update member display in chat and trip details, and implement pseudo change functionality in chat group.
This commit is contained in:
@@ -260,7 +260,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: theme.colorScheme.surfaceContainerHighest.withOpacity(0.3),
|
color: theme.colorScheme.surfaceContainerHighest.withValues(alpha:0.3),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@@ -268,11 +268,11 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Rechercher restaurants, musées...',
|
hintText: 'Rechercher restaurants, musées...',
|
||||||
hintStyle: TextStyle(
|
hintStyle: TextStyle(
|
||||||
color: theme.colorScheme.onSurface.withOpacity(0.6),
|
color: theme.colorScheme.onSurface.withValues(alpha:0.6),
|
||||||
),
|
),
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.search,
|
Icons.search,
|
||||||
color: theme.colorScheme.onSurface.withOpacity(0.6),
|
color: theme.colorScheme.onSurface.withValues(alpha:0.6),
|
||||||
),
|
),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
@@ -331,7 +331,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(color: theme.colorScheme.outline.withOpacity(0.5)),
|
border: Border.all(color: theme.colorScheme.outline.withValues(alpha:0.5)),
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
color: theme.colorScheme.surface,
|
color: theme.colorScheme.surface,
|
||||||
),
|
),
|
||||||
@@ -341,13 +341,13 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: theme.colorScheme.onSurface.withOpacity(0.7),
|
color: theme.colorScheme.onSurface.withValues(alpha:0.7),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(
|
Text(
|
||||||
text,
|
text,
|
||||||
style: theme.textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: theme.colorScheme.onSurface.withOpacity(0.7),
|
color: theme.colorScheme.onSurface.withValues(alpha:0.7),
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -362,13 +362,13 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: theme.colorScheme.surfaceContainerHighest.withOpacity(0.3),
|
color: theme.colorScheme.surfaceContainerHighest.withValues(alpha:0.3),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: TabBar(
|
child: TabBar(
|
||||||
controller: _tabController,
|
controller: _tabController,
|
||||||
labelColor: Colors.white,
|
labelColor: Colors.white,
|
||||||
unselectedLabelColor: theme.colorScheme.onSurface.withOpacity(0.7),
|
unselectedLabelColor: theme.colorScheme.onSurface.withValues(alpha:0.7),
|
||||||
indicator: BoxDecoration(
|
indicator: BoxDecoration(
|
||||||
color: theme.colorScheme.primary,
|
color: theme.colorScheme.primary,
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
@@ -814,7 +814,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
Text(
|
Text(
|
||||||
'Recherche powered by Google Places',
|
'Recherche powered by Google Places',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6),
|
color: Theme.of(context).colorScheme.onSurface.withValues(alpha:0.6),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -845,7 +845,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
Text(
|
Text(
|
||||||
subtitle,
|
subtitle,
|
||||||
style: theme.textTheme.bodyMedium?.copyWith(
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
color: theme.colorScheme.onSurface.withOpacity(0.7),
|
color: theme.colorScheme.onSurface.withValues(alpha:0.7),
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
@@ -977,7 +977,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: theme.colorScheme.primary.withOpacity(0.1),
|
color: theme.colorScheme.primary.withValues(alpha:0.1),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
@@ -1015,7 +1015,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
vertical: 4,
|
vertical: 4,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.amber.withOpacity(0.1),
|
color: Colors.amber.withValues(alpha:0.1),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -1043,7 +1043,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
Text(
|
Text(
|
||||||
activity.description,
|
activity.description,
|
||||||
style: theme.textTheme.bodyMedium?.copyWith(
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
color: theme.colorScheme.onSurface.withOpacity(0.8),
|
color: theme.colorScheme.onSurface.withValues(alpha:0.8),
|
||||||
),
|
),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
@@ -1056,14 +1056,14 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
Icon(
|
Icon(
|
||||||
Icons.location_on,
|
Icons.location_on,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: theme.colorScheme.onSurface.withOpacity(0.6),
|
color: theme.colorScheme.onSurface.withValues(alpha:0.6),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
activity.address!,
|
activity.address!,
|
||||||
style: theme.textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: theme.colorScheme.onSurface.withOpacity(0.6),
|
color: theme.colorScheme.onSurface.withValues(alpha:0.6),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -1084,10 +1084,10 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
vertical: 8,
|
vertical: 8,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.orange.withOpacity(0.1),
|
color: Colors.orange.withValues(alpha:0.1),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Colors.orange.withOpacity(0.3),
|
color: Colors.orange.withValues(alpha:0.3),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -1140,7 +1140,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
vertical: 4,
|
vertical: 4,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.green.withOpacity(0.1),
|
color: Colors.green.withValues(alpha:0.1),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -1170,7 +1170,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
vertical: 4,
|
vertical: 4,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.red.withOpacity(0.1),
|
color: Colors.red.withValues(alpha:0.1),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'dart:async';
|
||||||
import '../../blocs/user/user_bloc.dart';
|
import '../../blocs/user/user_bloc.dart';
|
||||||
import '../../blocs/user/user_state.dart' as user_state;
|
import '../../blocs/user/user_state.dart' as user_state;
|
||||||
import '../../blocs/message/message_bloc.dart';
|
import '../../blocs/message/message_bloc.dart';
|
||||||
import '../../blocs/message/message_event.dart';
|
import '../../blocs/message/message_event.dart';
|
||||||
import '../../blocs/message/message_state.dart';
|
import '../../blocs/message/message_state.dart';
|
||||||
import '../../models/group.dart';
|
import '../../models/group.dart';
|
||||||
|
import '../../models/group_member.dart';
|
||||||
import '../../models/message.dart';
|
import '../../models/message.dart';
|
||||||
|
import '../../repositories/group_repository.dart';
|
||||||
|
|
||||||
/// Chat group content widget for group messaging functionality.
|
/// Chat group content widget for group messaging functionality.
|
||||||
///
|
///
|
||||||
@@ -47,17 +50,34 @@ class _ChatGroupContentState extends State<ChatGroupContent> {
|
|||||||
/// Currently selected message for editing (null if not editing)
|
/// Currently selected message for editing (null if not editing)
|
||||||
Message? _editingMessage;
|
Message? _editingMessage;
|
||||||
|
|
||||||
|
/// Repository pour gérer les groupes
|
||||||
|
final _groupRepository = GroupRepository();
|
||||||
|
|
||||||
|
/// Subscription pour écouter les changements des membres du groupe
|
||||||
|
late StreamSubscription<List<GroupMember>> _membersSubscription;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
// Load messages when the widget initializes
|
// Load messages when the widget initializes
|
||||||
context.read<MessageBloc>().add(LoadMessages(widget.group.id));
|
context.read<MessageBloc>().add(LoadMessages(widget.group.id));
|
||||||
|
|
||||||
|
// Écouter les changements des membres du groupe
|
||||||
|
_membersSubscription = _groupRepository.watchGroupMembers(widget.group.id).listen((updatedMembers) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
widget.group.members.clear();
|
||||||
|
widget.group.members.addAll(updatedMembers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_messageController.dispose();
|
_messageController.dispose();
|
||||||
_scrollController.dispose();
|
_scrollController.dispose();
|
||||||
|
_membersSubscription.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,12 +401,15 @@ class _ChatGroupContentState extends State<ChatGroupContent> {
|
|||||||
textColor = isDark ? Colors.white : Colors.black87;
|
textColor = isDark ? Colors.white : Colors.black87;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trouver le membre qui a envoyé le message pour récupérer sa photo
|
// Trouver le membre qui a envoyé le message pour récupérer son pseudo actuel
|
||||||
final senderMember = widget.group.members.firstWhere(
|
final senderMember = widget.group.members.firstWhere(
|
||||||
(m) => m.userId == message.senderId,
|
(m) => m.userId == message.senderId,
|
||||||
orElse: () => null as dynamic,
|
orElse: () => null as dynamic,
|
||||||
) as dynamic;
|
) as dynamic;
|
||||||
|
|
||||||
|
// Utiliser le pseudo actuel du membre, ou le senderName en fallback
|
||||||
|
final displayName = senderMember != null ? senderMember.pseudo : message.senderName;
|
||||||
|
|
||||||
return Align(
|
return Align(
|
||||||
alignment: isMe ? Alignment.centerRight : Alignment.centerLeft,
|
alignment: isMe ? Alignment.centerRight : Alignment.centerLeft,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
@@ -413,8 +436,8 @@ class _ChatGroupContentState extends State<ChatGroupContent> {
|
|||||||
senderMember.profilePictureUrl == null ||
|
senderMember.profilePictureUrl == null ||
|
||||||
senderMember.profilePictureUrl!.isEmpty)
|
senderMember.profilePictureUrl!.isEmpty)
|
||||||
? Text(
|
? Text(
|
||||||
message.senderName.isNotEmpty
|
displayName.isNotEmpty
|
||||||
? message.senderName[0].toUpperCase()
|
? displayName[0].toUpperCase()
|
||||||
: '?',
|
: '?',
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
)
|
)
|
||||||
@@ -443,7 +466,7 @@ class _ChatGroupContentState extends State<ChatGroupContent> {
|
|||||||
children: [
|
children: [
|
||||||
if (!isMe) ...[
|
if (!isMe) ...[
|
||||||
Text(
|
Text(
|
||||||
message.senderName,
|
displayName,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@@ -689,6 +712,9 @@ class _ChatGroupContentState extends State<ChatGroupContent> {
|
|||||||
? member.firstName[0].toUpperCase()
|
? member.firstName[0].toUpperCase()
|
||||||
: '?');
|
: '?');
|
||||||
|
|
||||||
|
// Construire le nom complet
|
||||||
|
final fullName = '${member.firstName} ${member.lastName}'.trim();
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
backgroundImage: (member.profilePictureUrl != null &&
|
backgroundImage: (member.profilePictureUrl != null &&
|
||||||
@@ -699,10 +725,30 @@ class _ChatGroupContentState extends State<ChatGroupContent> {
|
|||||||
? Text(initials)
|
? Text(initials)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
title: Text(member.pseudo),
|
title: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(member.pseudo),
|
||||||
|
if (fullName.isNotEmpty)
|
||||||
|
Text(
|
||||||
|
fullName,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
subtitle: member.role == 'admin'
|
subtitle: member.role == 'admin'
|
||||||
? const Text('Administrateur', style: TextStyle(fontSize: 12))
|
? const Text('Administrateur', style: TextStyle(fontSize: 12))
|
||||||
: null,
|
: null,
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: const Icon(Icons.edit, size: 18),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
_showChangePseudoDialog(member);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -716,4 +762,86 @@ class _ChatGroupContentState extends State<ChatGroupContent> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showChangePseudoDialog(dynamic member) {
|
||||||
|
final pseudoController = TextEditingController(text: member.pseudo);
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
backgroundColor: theme.dialogBackgroundColor,
|
||||||
|
title: Text(
|
||||||
|
'Changer le pseudo',
|
||||||
|
style: theme.textTheme.titleLarge?.copyWith(
|
||||||
|
color: theme.colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
content: TextField(
|
||||||
|
controller: pseudoController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Nouveau pseudo',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: TextStyle(color: theme.colorScheme.onSurface),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text(
|
||||||
|
'Annuler',
|
||||||
|
style: TextStyle(color: theme.colorScheme.primary),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
final newPseudo = pseudoController.text.trim();
|
||||||
|
if (newPseudo.isNotEmpty) {
|
||||||
|
_updateMemberPseudo(member, newPseudo);
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'Valider',
|
||||||
|
style: TextStyle(color: theme.colorScheme.primary),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _updateMemberPseudo(dynamic member, String newPseudo) async {
|
||||||
|
try {
|
||||||
|
final updatedMember = member.copyWith(pseudo: newPseudo);
|
||||||
|
await _groupRepository.addMember(widget.group.id, updatedMember);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
// Le stream listener va automatiquement mettre à jour les membres
|
||||||
|
// Pas besoin de fermer le dialog ou de faire un refresh manuel
|
||||||
|
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Pseudo modifié en "$newPseudo"'),
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Erreur lors de la modification du pseudo: $e'),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,7 @@ class _GroupContentState extends State<GroupContent> {
|
|||||||
if (group.members.isNotEmpty) {
|
if (group.members.isNotEmpty) {
|
||||||
final names = group.members
|
final names = group.members
|
||||||
.take(2)
|
.take(2)
|
||||||
.map((m) => m.pseudo.isNotEmpty ? m.pseudo : m.firstName)
|
.map((m) => m.firstName)
|
||||||
.join(', ');
|
.join(', ');
|
||||||
memberInfo += '\n$names';
|
memberInfo += '\n$names';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -956,6 +956,7 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
GroupMember(
|
GroupMember(
|
||||||
userId: currentUser.id,
|
userId: currentUser.id,
|
||||||
firstName: currentUser.prenom,
|
firstName: currentUser.prenom,
|
||||||
|
lastName: currentUser.nom,
|
||||||
pseudo: currentUser.prenom,
|
pseudo: currentUser.prenom,
|
||||||
role: 'admin',
|
role: 'admin',
|
||||||
profilePictureUrl: currentUser.profilePictureUrl,
|
profilePictureUrl: currentUser.profilePictureUrl,
|
||||||
@@ -963,6 +964,7 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
...participantsData.map((p) => GroupMember(
|
...participantsData.map((p) => GroupMember(
|
||||||
userId: p['id'] as String,
|
userId: p['id'] as String,
|
||||||
firstName: p['firstName'] as String,
|
firstName: p['firstName'] as String,
|
||||||
|
lastName: p['lastName'] as String? ?? '',
|
||||||
pseudo: p['firstName'] as String,
|
pseudo: p['firstName'] as String,
|
||||||
role: 'member',
|
role: 'member',
|
||||||
profilePictureUrl: p['profilePictureUrl'] as String?,
|
profilePictureUrl: p['profilePictureUrl'] as String?,
|
||||||
@@ -1151,11 +1153,13 @@ class _CreateTripContentState extends State<CreateTripContent> {
|
|||||||
if (userId != null) {
|
if (userId != null) {
|
||||||
final userDoc = await _userService.getUserById(userId);
|
final userDoc = await _userService.getUserById(userId);
|
||||||
final firstName = userDoc?.prenom ?? 'Utilisateur';
|
final firstName = userDoc?.prenom ?? 'Utilisateur';
|
||||||
|
final lastName = userDoc?.nom ?? '';
|
||||||
final profilePictureUrl = userDoc?.profilePictureUrl;
|
final profilePictureUrl = userDoc?.profilePictureUrl;
|
||||||
|
|
||||||
participantsData.add({
|
participantsData.add({
|
||||||
'id': userId,
|
'id': userId,
|
||||||
'firstName': firstName,
|
'firstName': firstName,
|
||||||
|
'lastName': lastName,
|
||||||
'profilePictureUrl': profilePictureUrl,
|
'profilePictureUrl': profilePictureUrl,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -892,6 +892,7 @@ class _ShowTripDetailsContentState extends State<ShowTripDetailsContent> {
|
|||||||
final newMember = GroupMember(
|
final newMember = GroupMember(
|
||||||
userId: user.id!,
|
userId: user.id!,
|
||||||
firstName: user.prenom,
|
firstName: user.prenom,
|
||||||
|
lastName: user.nom,
|
||||||
pseudo: user.prenom,
|
pseudo: user.prenom,
|
||||||
profilePictureUrl: user.profilePictureUrl,
|
profilePictureUrl: user.profilePictureUrl,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
class GroupMember {
|
class GroupMember {
|
||||||
final String userId;
|
final String userId;
|
||||||
final String firstName;
|
final String firstName;
|
||||||
|
final String lastName;
|
||||||
final String pseudo; // Pseudo du membre (par défaut = prénom)
|
final String pseudo; // Pseudo du membre (par défaut = prénom)
|
||||||
final String role; // 'admin' ou 'member'
|
final String role; // 'admin' ou 'member'
|
||||||
final DateTime joinedAt;
|
final DateTime joinedAt;
|
||||||
@@ -9,17 +10,20 @@ class GroupMember {
|
|||||||
GroupMember({
|
GroupMember({
|
||||||
required this.userId,
|
required this.userId,
|
||||||
required this.firstName,
|
required this.firstName,
|
||||||
|
String? lastName,
|
||||||
String? pseudo,
|
String? pseudo,
|
||||||
this.role = 'member',
|
this.role = 'member',
|
||||||
DateTime? joinedAt,
|
DateTime? joinedAt,
|
||||||
this.profilePictureUrl,
|
this.profilePictureUrl,
|
||||||
}) : pseudo = pseudo ?? firstName, // Par défaut, pseudo = prénom
|
}) : lastName = lastName ?? '',
|
||||||
|
pseudo = pseudo ?? firstName,
|
||||||
joinedAt = joinedAt ?? DateTime.now();
|
joinedAt = joinedAt ?? DateTime.now();
|
||||||
|
|
||||||
factory GroupMember.fromMap(Map<String, dynamic> map, String userId) {
|
factory GroupMember.fromMap(Map<String, dynamic> map, String userId) {
|
||||||
return GroupMember(
|
return GroupMember(
|
||||||
userId: userId,
|
userId: userId,
|
||||||
firstName: map['firstName'] ?? '',
|
firstName: map['firstName'] ?? '',
|
||||||
|
lastName: map['lastName'] ?? '',
|
||||||
pseudo: map['pseudo'] ?? map['firstName'] ?? '',
|
pseudo: map['pseudo'] ?? map['firstName'] ?? '',
|
||||||
role: map['role'] ?? 'member',
|
role: map['role'] ?? 'member',
|
||||||
joinedAt: DateTime.fromMillisecondsSinceEpoch(map['joinedAt'] ?? 0),
|
joinedAt: DateTime.fromMillisecondsSinceEpoch(map['joinedAt'] ?? 0),
|
||||||
@@ -30,6 +34,7 @@ class GroupMember {
|
|||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
return {
|
return {
|
||||||
'firstName': firstName,
|
'firstName': firstName,
|
||||||
|
'lastName': lastName,
|
||||||
'pseudo': pseudo,
|
'pseudo': pseudo,
|
||||||
'role': role,
|
'role': role,
|
||||||
'joinedAt': joinedAt.millisecondsSinceEpoch,
|
'joinedAt': joinedAt.millisecondsSinceEpoch,
|
||||||
@@ -40,6 +45,7 @@ class GroupMember {
|
|||||||
GroupMember copyWith({
|
GroupMember copyWith({
|
||||||
String? userId,
|
String? userId,
|
||||||
String? firstName,
|
String? firstName,
|
||||||
|
String? lastName,
|
||||||
String? pseudo,
|
String? pseudo,
|
||||||
String? role,
|
String? role,
|
||||||
DateTime? joinedAt,
|
DateTime? joinedAt,
|
||||||
@@ -48,6 +54,7 @@ class GroupMember {
|
|||||||
return GroupMember(
|
return GroupMember(
|
||||||
userId: userId ?? this.userId,
|
userId: userId ?? this.userId,
|
||||||
firstName: firstName ?? this.firstName,
|
firstName: firstName ?? this.firstName,
|
||||||
|
lastName: lastName ?? this.lastName,
|
||||||
pseudo: pseudo ?? this.pseudo,
|
pseudo: pseudo ?? this.pseudo,
|
||||||
role: role ?? this.role,
|
role: role ?? this.role,
|
||||||
joinedAt: joinedAt ?? this.joinedAt,
|
joinedAt: joinedAt ?? this.joinedAt,
|
||||||
|
|||||||
Reference in New Issue
Block a user