feat: add event details description component and environment configuration file
This commit is contained in:
+107
-30
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user