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/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,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user