Ajout du choix des utilisateurs sur un événement. Ajout de fichiers dans un événement. (dropzone cassée)
This commit is contained in:
		| @@ -6,6 +6,8 @@ import 'package:provider/provider.dart'; | ||||
| import 'package:em2rp/providers/local_user_provider.dart'; | ||||
| import 'package:em2rp/providers/event_provider.dart'; | ||||
| import 'package:latlong2/latlong.dart'; | ||||
| import 'package:url_launcher/url_launcher.dart'; | ||||
| import 'package:path/path.dart' as p; | ||||
|  | ||||
| class EventDetails extends StatelessWidget { | ||||
|   final EventModel event; | ||||
| @@ -139,9 +141,75 @@ class EventDetails extends StatelessWidget { | ||||
|             ), | ||||
|             const SizedBox(height: 8), | ||||
|             Text( | ||||
|               '${event.address.latitude}° N, ${event.address.longitude}° E', | ||||
|               event.address, | ||||
|               style: Theme.of(context).textTheme.bodyLarge, | ||||
|             ), | ||||
|             if (event.latitude != 0.0 || event.longitude != 0.0) ...[ | ||||
|               const SizedBox(height: 4), | ||||
|               Text( | ||||
|                 '${event.latitude}° N, ${event.longitude}° E', | ||||
|                 style: Theme.of(context).textTheme.bodySmall, | ||||
|               ), | ||||
|             ], | ||||
|             if (event.documents.isNotEmpty) ...[ | ||||
|               const SizedBox(height: 16), | ||||
|               Text('Documents', | ||||
|                   style: Theme.of(context).textTheme.titleLarge?.copyWith( | ||||
|                       color: AppColors.noir, fontWeight: FontWeight.bold)), | ||||
|               const SizedBox(height: 8), | ||||
|               Column( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                 children: event.documents.map((doc) { | ||||
|                   final fileName = doc['name'] ?? ''; | ||||
|                   final url = doc['url'] ?? ''; | ||||
|                   final ext = p.extension(fileName).toLowerCase(); | ||||
|                   IconData icon; | ||||
|                   if ([".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"] | ||||
|                       .contains(ext)) { | ||||
|                     icon = Icons.image; | ||||
|                   } else if (ext == ".pdf") { | ||||
|                     icon = Icons.picture_as_pdf; | ||||
|                   } else if ([ | ||||
|                     ".txt", | ||||
|                     ".md", | ||||
|                     ".csv", | ||||
|                     ".json", | ||||
|                     ".xml", | ||||
|                     ".docx", | ||||
|                     ".doc", | ||||
|                     ".xls", | ||||
|                     ".xlsx", | ||||
|                     ".ppt", | ||||
|                     ".pptx" | ||||
|                   ].contains(ext)) { | ||||
|                     icon = Icons.description; | ||||
|                   } else { | ||||
|                     icon = Icons.attach_file; | ||||
|                   } | ||||
|                   return ListTile( | ||||
|                     leading: Icon(icon, color: Colors.blueGrey), | ||||
|                     title: Text(fileName, overflow: TextOverflow.ellipsis), | ||||
|                     trailing: IconButton( | ||||
|                       icon: const Icon(Icons.download), | ||||
|                       onPressed: () async { | ||||
|                         if (await canLaunchUrl(Uri.parse(url))) { | ||||
|                           await launchUrl(Uri.parse(url), | ||||
|                               mode: LaunchMode.externalApplication); | ||||
|                         } | ||||
|                       }, | ||||
|                     ), | ||||
|                     onTap: () async { | ||||
|                       if (await canLaunchUrl(Uri.parse(url))) { | ||||
|                         await launchUrl(Uri.parse(url), | ||||
|                             mode: LaunchMode.externalApplication); | ||||
|                       } | ||||
|                     }, | ||||
|                     contentPadding: EdgeInsets.zero, | ||||
|                     dense: true, | ||||
|                   ); | ||||
|                 }).toList(), | ||||
|               ), | ||||
|             ], | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
| @@ -193,6 +261,7 @@ class _EventAddDialogState extends State<EventAddDialog> { | ||||
|   final TextEditingController _disassemblyController = TextEditingController(); | ||||
|   final TextEditingController _latitudeController = TextEditingController(); | ||||
|   final TextEditingController _longitudeController = TextEditingController(); | ||||
|   final TextEditingController _addressController = TextEditingController(); | ||||
|   DateTime? _startDateTime; | ||||
|   DateTime? _endDateTime; | ||||
|   bool _isLoading = false; | ||||
| @@ -208,6 +277,7 @@ class _EventAddDialogState extends State<EventAddDialog> { | ||||
|     _disassemblyController.dispose(); | ||||
|     _latitudeController.dispose(); | ||||
|     _longitudeController.dispose(); | ||||
|     _addressController.dispose(); | ||||
|     super.dispose(); | ||||
|   } | ||||
|  | ||||
| @@ -233,11 +303,11 @@ class _EventAddDialogState extends State<EventAddDialog> { | ||||
|         disassemblyTime: int.tryParse(_disassemblyController.text) ?? 0, | ||||
|         eventTypeId: '', // à adapter si tu veux gérer les types | ||||
|         customerId: '', // à adapter si tu veux gérer les clients | ||||
|         address: LatLng( | ||||
|           double.tryParse(_latitudeController.text) ?? 0.0, | ||||
|           double.tryParse(_longitudeController.text) ?? 0.0, | ||||
|         ), | ||||
|         address: _addressController.text.trim(), | ||||
|         latitude: double.tryParse(_latitudeController.text) ?? 0.0, | ||||
|         longitude: double.tryParse(_longitudeController.text) ?? 0.0, | ||||
|         workforce: [], | ||||
|         documents: [], | ||||
|       ); | ||||
|       await eventProvider.addEvent(newEvent); | ||||
|       setState(() { | ||||
| @@ -292,24 +362,19 @@ class _EventAddDialogState extends State<EventAddDialog> { | ||||
|                 decoration: const InputDecoration(labelText: 'Démontage (h)'), | ||||
|                 keyboardType: TextInputType.number, | ||||
|               ), | ||||
|               Row( | ||||
|                 children: [ | ||||
|                   Expanded( | ||||
|                     child: TextFormField( | ||||
|                       controller: _latitudeController, | ||||
|                       decoration: const InputDecoration(labelText: 'Latitude'), | ||||
|                       keyboardType: TextInputType.number, | ||||
|                     ), | ||||
|                   ), | ||||
|                   const SizedBox(width: 8), | ||||
|                   Expanded( | ||||
|                     child: TextFormField( | ||||
|                       controller: _longitudeController, | ||||
|                       decoration: const InputDecoration(labelText: 'Longitude'), | ||||
|                       keyboardType: TextInputType.number, | ||||
|                     ), | ||||
|                   ), | ||||
|                 ], | ||||
|               TextFormField( | ||||
|                 controller: _latitudeController, | ||||
|                 decoration: const InputDecoration(labelText: 'Latitude'), | ||||
|                 keyboardType: TextInputType.number, | ||||
|               ), | ||||
|               TextFormField( | ||||
|                 controller: _longitudeController, | ||||
|                 decoration: const InputDecoration(labelText: 'Longitude'), | ||||
|                 keyboardType: TextInputType.number, | ||||
|               ), | ||||
|               TextFormField( | ||||
|                 controller: _addressController, | ||||
|                 decoration: const InputDecoration(labelText: 'Adresse'), | ||||
|               ), | ||||
|               const SizedBox(height: 8), | ||||
|               Row( | ||||
|   | ||||
| @@ -88,7 +88,10 @@ class ProfilePictureWidget extends StatelessWidget { | ||||
|   Widget _buildIconAvatar(double radius) { | ||||
|     return CircleAvatar( | ||||
|       radius: radius, | ||||
|       child: Icon(Icons.account_circle, size: radius * 1.5), // Icône par défaut | ||||
|       child: FittedBox( | ||||
|         fit: BoxFit.scaleDown, | ||||
|         child: Icon(Icons.account_circle, size: radius * 1.5), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user