feat: add event details description component and environment configuration file

This commit is contained in:
ElPoyo
2026-05-28 00:04:48 +02:00
parent d9cd251bb7
commit 4d18956abe
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
import 'package:em2rp/models/event_model.dart'; import 'package:em2rp/models/event_model.dart';
import 'package:em2rp/utils/colors.dart'; import 'package:em2rp/utils/colors.dart';
import 'package:url_launcher/url_launcher.dart';
class EventDetailsDescription extends StatelessWidget { class EventDetailsDescription extends StatelessWidget {
final EventModel event; final EventModel event;
@@ -45,17 +47,48 @@ class EventDetailsDescription extends StatelessWidget {
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
SelectableText( Row(
event.address, crossAxisAlignment: CrossAxisAlignment.start,
style: Theme.of(context).textTheme.bodyLarge, children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SelectableText(
event.address,
style: Theme.of(context).textTheme.bodyLarge,
),
if (event.latitude != 0.0 || event.longitude != 0.0) ...[
const SizedBox(height: 4),
SelectableText(
'${event.latitude}° N, ${event.longitude}° E',
style: Theme.of(context).textTheme.bodySmall,
),
],
],
),
),
IconButton(
icon: const Icon(Icons.map, color: AppColors.rouge),
tooltip: 'Ouvrir dans Maps',
onPressed: () async {
final query = event.address;
if (query.isEmpty) return;
final url = Uri.parse('https://www.google.com/maps/search/?api=1&query=${Uri.encodeComponent(query)}');
if (await canLaunchUrl(url)) {
await launchUrl(url, mode: LaunchMode.externalApplication);
} else {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Impossible d\'ouvrir l\'application de carte')),
);
}
}
},
),
],
), ),
if (event.latitude != 0.0 || event.longitude != 0.0) ...[
const SizedBox(height: 4),
SelectableText(
'${event.latitude}° N, ${event.longitude}° E',
style: Theme.of(context).textTheme.bodySmall,
),
],
], ],
); );
} }
@@ -68,12 +101,22 @@ class EventDetailsDescription extends StatelessWidget {
_buildInfoRow(context, Icons.people, 'Jauge', '${event.jauge} personnes'), _buildInfoRow(context, Icons.people, 'Jauge', '${event.jauge} personnes'),
const SizedBox(height: 8), const SizedBox(height: 8),
], ],
if (event.contactEmail != null) ...[ if (event.contactEmail != null && event.contactEmail!.isNotEmpty) ...[
_buildInfoRow(context, Icons.email, 'Email', event.contactEmail!), _buildInfoRow(context, Icons.email, 'Email', event.contactEmail!, onTap: () async {
final url = Uri.parse('mailto:${event.contactEmail!}');
if (await canLaunchUrl(url)) {
await launchUrl(url);
}
}),
const SizedBox(height: 8), const SizedBox(height: 8),
], ],
if (event.contactPhone != null) ...[ if (event.contactPhone != null && event.contactPhone!.isNotEmpty) ...[
_buildInfoRow(context, Icons.phone, 'Téléphone', event.contactPhone!), _buildInfoRow(context, Icons.phone, 'Téléphone', event.contactPhone!, onTap: () async {
final url = Uri.parse('tel:${event.contactPhone!}');
if (await canLaunchUrl(url)) {
await launchUrl(url);
}
}),
], ],
], ],
); );
@@ -86,15 +129,25 @@ class EventDetailsDescription extends StatelessWidget {
children: [ children: [
if (event.jauge != null) if (event.jauge != null)
_buildInfoChip(context, Icons.people, 'Jauge', '${event.jauge} personnes'), _buildInfoChip(context, Icons.people, 'Jauge', '${event.jauge} personnes'),
if (event.contactEmail != null) if (event.contactEmail != null && event.contactEmail!.isNotEmpty)
_buildInfoChip(context, Icons.email, 'Email', event.contactEmail!), _buildInfoChip(context, Icons.email, 'Email', event.contactEmail!, onTap: () async {
if (event.contactPhone != null) final url = Uri.parse('mailto:${event.contactEmail!}');
_buildInfoChip(context, Icons.phone, 'Téléphone', event.contactPhone!), if (await canLaunchUrl(url)) {
await launchUrl(url);
}
}),
if (event.contactPhone != null && event.contactPhone!.isNotEmpty)
_buildInfoChip(context, Icons.phone, 'Téléphone', event.contactPhone!, onTap: () async {
final url = Uri.parse('tel:${event.contactPhone!}');
if (await canLaunchUrl(url)) {
await launchUrl(url);
}
}),
], ],
); );
} }
Widget _buildInfoRow(BuildContext context, IconData icon, String label, String value) { Widget _buildInfoRow(BuildContext context, IconData icon, String label, String value, {VoidCallback? onTap}) {
return Row( return Row(
children: [ children: [
Icon(icon, size: 20, color: Theme.of(context).primaryColor), Icon(icon, size: 20, color: Theme.of(context).primaryColor),
@@ -109,12 +162,24 @@ class EventDetailsDescription extends StatelessWidget {
color: Colors.grey[600], color: Colors.grey[600],
), ),
), ),
SelectableText( onTap == null
value, ? SelectableText(
style: Theme.of(context).textTheme.bodyMedium?.copyWith( value,
fontWeight: FontWeight.w500, style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w500,
),
)
: SelectableText.rich(
TextSpan(
text: value,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w500,
color: AppColors.rouge,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()..onTap = onTap,
),
), ),
),
], ],
), ),
), ),
@@ -122,7 +187,7 @@ class EventDetailsDescription extends StatelessWidget {
); );
} }
Widget _buildInfoChip(BuildContext context, IconData icon, String label, String value) { Widget _buildInfoChip(BuildContext context, IconData icon, String label, String value, {VoidCallback? onTap}) {
final primaryColor = Theme.of(context).primaryColor; final primaryColor = Theme.of(context).primaryColor;
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
@@ -146,12 +211,24 @@ class EventDetailsDescription extends StatelessWidget {
color: Colors.grey[600], color: Colors.grey[600],
), ),
), ),
SelectableText( onTap == null
value, ? SelectableText(
style: Theme.of(context).textTheme.bodySmall?.copyWith( value,
fontWeight: FontWeight.w500, style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w500,
),
)
: SelectableText.rich(
TextSpan(
text: value,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w500,
color: AppColors.rouge,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()..onTap = onTap,
),
), ),
),
], ],
), ),
], ],