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/gestures.dart';
import 'package:em2rp/models/event_model.dart';
import 'package:em2rp/utils/colors.dart';
import 'package:url_launcher/url_launcher.dart';
class EventDetailsDescription extends StatelessWidget {
final EventModel event;
@@ -45,17 +47,48 @@ class EventDetailsDescription extends StatelessWidget {
),
),
const SizedBox(height: 8),
SelectableText(
event.address,
style: Theme.of(context).textTheme.bodyLarge,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
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'),
const SizedBox(height: 8),
],
if (event.contactEmail != null) ...[
_buildInfoRow(context, Icons.email, 'Email', event.contactEmail!),
if (event.contactEmail != null && event.contactEmail!.isNotEmpty) ...[
_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),
],
if (event.contactPhone != null) ...[
_buildInfoRow(context, Icons.phone, 'Téléphone', event.contactPhone!),
if (event.contactPhone != null && event.contactPhone!.isNotEmpty) ...[
_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: [
if (event.jauge != null)
_buildInfoChip(context, Icons.people, 'Jauge', '${event.jauge} personnes'),
if (event.contactEmail != null)
_buildInfoChip(context, Icons.email, 'Email', event.contactEmail!),
if (event.contactPhone != null)
_buildInfoChip(context, Icons.phone, 'Téléphone', event.contactPhone!),
if (event.contactEmail != null && event.contactEmail!.isNotEmpty)
_buildInfoChip(context, Icons.email, 'Email', event.contactEmail!, onTap: () async {
final url = Uri.parse('mailto:${event.contactEmail!}');
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(
children: [
Icon(icon, size: 20, color: Theme.of(context).primaryColor),
@@ -109,12 +162,24 @@ class EventDetailsDescription extends StatelessWidget {
color: Colors.grey[600],
),
),
SelectableText(
value,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w500,
onTap == null
? SelectableText(
value,
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;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
@@ -146,12 +211,24 @@ class EventDetailsDescription extends StatelessWidget {
color: Colors.grey[600],
),
),
SelectableText(
value,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w500,
onTap == null
? SelectableText(
value,
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,
),
),
),
],
),
],