Initial commit: unionflow-mobile-apps
Application Flutter complète (sans build artifacts). Signed-off-by: lions dev Team
This commit is contained in:
691
lib/features/help/presentation/pages/help_support_page.dart
Normal file
691
lib/features/help/presentation/pages/help_support_page.dart
Normal file
@@ -0,0 +1,691 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
import '../../../../shared/widgets/core_card.dart';
|
||||
|
||||
/// Page Aide & Support - UnionFlow Mobile
|
||||
///
|
||||
/// Page complète d'aide avec FAQ, guides, support technique,
|
||||
/// et ressources pour les utilisateurs.
|
||||
class HelpSupportPage extends StatefulWidget {
|
||||
const HelpSupportPage({super.key});
|
||||
|
||||
@override
|
||||
State<HelpSupportPage> createState() => _HelpSupportPageState();
|
||||
}
|
||||
|
||||
class _HelpSupportPageState extends State<HelpSupportPage> {
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
String _searchQuery = '';
|
||||
int _selectedCategoryIndex = 0;
|
||||
|
||||
final List<String> _categories = [
|
||||
'Tout',
|
||||
'Connexion',
|
||||
'Membres',
|
||||
'Organisations',
|
||||
'Événements',
|
||||
'Technique',
|
||||
];
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
appBar: const UFAppBar(title: 'AIDE & SUPPORT'),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Header harmonisé
|
||||
_buildHeader(),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Barre de recherche
|
||||
_buildSearchSection(),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Actions rapides
|
||||
_buildQuickActionsSection(),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Catégories FAQ
|
||||
_buildCategoriesSection(),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// FAQ
|
||||
_buildFAQSection(),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Guides et tutoriels
|
||||
_buildGuidesSection(),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Contact support
|
||||
_buildContactSection(),
|
||||
const SizedBox(height: 80),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Header épuré
|
||||
Widget _buildHeader() {
|
||||
return Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primaryGreen.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.help_outline,
|
||||
color: AppColors.primaryGreen,
|
||||
size: 48,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'COMMENT POUVONS-NOUS VOUS AIDER ?',
|
||||
style: AppTypography.headerSmall.copyWith(fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Documentation, FAQ et support technique',
|
||||
style: AppTypography.subtitleSmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Section de recherche
|
||||
Widget _buildSearchSection() {
|
||||
return CoreCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.search, color: AppColors.primaryGreen, size: 18),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'RECHERCHER DANS L\'AIDE',
|
||||
style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.lightSurface,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppColors.lightBorder),
|
||||
),
|
||||
child: TextField(
|
||||
controller: _searchController,
|
||||
onChanged: (value) => setState(() => _searchQuery = value),
|
||||
style: AppTypography.bodyTextSmall,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Une question, un mot-clé...',
|
||||
hintStyle: AppTypography.subtitleSmall,
|
||||
prefixIcon: const Icon(Icons.search, color: AppColors.textSecondaryLight, size: 18),
|
||||
suffixIcon: _searchQuery.isNotEmpty
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
_searchController.clear();
|
||||
setState(() => _searchQuery = '');
|
||||
},
|
||||
icon: const Icon(Icons.clear, color: AppColors.textSecondaryLight, size: 18),
|
||||
)
|
||||
: null,
|
||||
border: InputBorder.none,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Section actions rapides
|
||||
Widget _buildQuickActionsSection() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4, bottom: 12),
|
||||
child: Text(
|
||||
'ACTIONS RAPIDES',
|
||||
style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildQuickActionCard(
|
||||
'CHAT',
|
||||
'Support Direct',
|
||||
Icons.chat_bubble_outline,
|
||||
AppColors.primaryGreen,
|
||||
() => _startLiveChat(),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildQuickActionCard(
|
||||
'BUG',
|
||||
'Signaler',
|
||||
Icons.bug_report_outlined,
|
||||
AppColors.error,
|
||||
() => _reportBug(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildQuickActionCard(
|
||||
'IDÉE',
|
||||
'Suggérer',
|
||||
Icons.lightbulb_outline,
|
||||
AppColors.warning,
|
||||
() => _requestFeature(),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildQuickActionCard(
|
||||
'EMAIL',
|
||||
'Support Tech',
|
||||
Icons.mark_email_read_outlined,
|
||||
AppColors.info,
|
||||
() => _contactByEmail(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Carte d'action rapide
|
||||
Widget _buildQuickActionCard(String title, String subtitle, IconData icon, Color color, VoidCallback onTap) {
|
||||
return CoreCard(
|
||||
padding: const EdgeInsets.all(12),
|
||||
onTap: onTap,
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(icon, color: color, size: 24),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
title,
|
||||
style: AppTypography.actionText.copyWith(fontSize: 11),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
subtitle,
|
||||
style: AppTypography.subtitleSmall.copyWith(fontSize: 9),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Section catégories
|
||||
Widget _buildCategoriesSection() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4, bottom: 8),
|
||||
child: Text(
|
||||
'PAR CATÉGORIE',
|
||||
style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1),
|
||||
),
|
||||
),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: _categories.asMap().entries.map((entry) {
|
||||
final isSelected = _selectedCategoryIndex == entry.key;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: _buildCategoryChip(entry.value, isSelected, () {
|
||||
setState(() => _selectedCategoryIndex = entry.key);
|
||||
}),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Chip de catégorie
|
||||
Widget _buildCategoryChip(String label, bool isSelected, VoidCallback onTap) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? AppColors.primaryGreen.withOpacity(0.1) : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
border: Border.all(
|
||||
color: isSelected ? AppColors.primaryGreen : AppColors.lightBorder,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
label.toUpperCase(),
|
||||
style: AppTypography.badgeText.copyWith(
|
||||
color: isSelected ? AppColors.primaryGreen : AppColors.textSecondaryLight,
|
||||
fontSize: 9,
|
||||
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Section FAQ
|
||||
Widget _buildFAQSection() {
|
||||
final faqs = _getFilteredFAQs();
|
||||
if (faqs.isEmpty) return const SizedBox.shrink();
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4, bottom: 12),
|
||||
child: Text(
|
||||
'QUESTIONS FRÉQUENTES',
|
||||
style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1),
|
||||
),
|
||||
),
|
||||
...faqs.map((faq) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: _buildFAQItem(faq),
|
||||
)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Élément FAQ
|
||||
Widget _buildFAQItem(Map<String, dynamic> faq) {
|
||||
return CoreCard(
|
||||
padding: EdgeInsets.zero,
|
||||
child: ExpansionTile(
|
||||
title: Text(
|
||||
faq['question'],
|
||||
style: AppTypography.actionText.copyWith(fontSize: 12),
|
||||
),
|
||||
leading: Icon(
|
||||
faq['icon'] as IconData,
|
||||
color: AppColors.primaryGreen,
|
||||
size: 18,
|
||||
),
|
||||
iconColor: AppColors.primaryGreen,
|
||||
collapsedIconColor: AppColors.textSecondaryLight,
|
||||
shape: const RoundedRectangleBorder(side: BorderSide.none),
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: Text(
|
||||
faq['answer'],
|
||||
style: AppTypography.subtitleSmall.copyWith(fontSize: 11, height: 1.4),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Section guides
|
||||
Widget _buildGuidesSection() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4, bottom: 12),
|
||||
child: Text(
|
||||
'GUIDES & TUTORIELS',
|
||||
style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1),
|
||||
),
|
||||
),
|
||||
_buildGuideItem('Introduction', 'Démarrer avec UnionFlow', Icons.play_circle_outline, AppColors.success, () => _openGuide('getting-started')),
|
||||
_buildGuideItem('Membres', 'Gérer vos adhérents', Icons.people_outline, AppColors.primaryGreen, () => _openGuide('members')),
|
||||
_buildGuideItem('Organisations', 'Structures & Syndicats', Icons.business_outlined, AppColors.info, () => _openGuide('organizations')),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Élément de guide
|
||||
Widget _buildGuideItem(String title, String description, IconData icon, Color color, VoidCallback onTap) {
|
||||
return CoreCard(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
onTap: onTap,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, color: color, size: 20),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title, style: AppTypography.actionText.copyWith(fontSize: 12)),
|
||||
Text(description, style: AppTypography.subtitleSmall.copyWith(fontSize: 10)),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Icon(Icons.chevron_right, color: AppColors.textSecondaryLight, size: 16),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Section contact
|
||||
Widget _buildContactSection() {
|
||||
return CoreCard(
|
||||
backgroundColor: AppColors.primaryGreen, // Correction: color -> backgroundColor
|
||||
child: Column(
|
||||
children: [
|
||||
const Icon(Icons.headset_mic_outlined, color: Colors.white, size: 32),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'BESOIN D\'AIDE SUPPLÉMENTAIRE ?',
|
||||
style: AppTypography.headerSmall.copyWith(color: Colors.white, fontSize: 14),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Disponible lun-ven, 9h-18h',
|
||||
style: AppTypography.subtitleSmall.copyWith(color: Colors.white.withOpacity(0.8)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: UFPrimaryButton(
|
||||
label: 'EMAIL', // Correction: text -> label
|
||||
onPressed: () => _contactByEmail(),
|
||||
backgroundColor: Colors.white,
|
||||
textColor: AppColors.primaryGreen,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: UFPrimaryButton(
|
||||
label: 'CHAT', // Correction: text -> label
|
||||
onPressed: () => _startLiveChat(),
|
||||
backgroundColor: Colors.white.withOpacity(0.2),
|
||||
textColor: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Obtenir les FAQs filtrées
|
||||
List<Map<String, dynamic>> _getFilteredFAQs() {
|
||||
final allFAQs = [
|
||||
{
|
||||
'question': 'Comment me connecter à UnionFlow ?',
|
||||
'answer': 'Utilisez vos identifiants fournis par votre organisation. La connexion se fait via Keycloak pour une sécurité optimale.',
|
||||
'category': 'Connexion',
|
||||
'icon': Icons.login,
|
||||
},
|
||||
{
|
||||
'question': 'Comment ajouter un nouveau membre ?',
|
||||
'answer': 'Allez dans la section Membres, cliquez sur le bouton + et remplissez les informations requises. Vous devez avoir les permissions appropriées.',
|
||||
'category': 'Membres',
|
||||
'icon': Icons.person_add,
|
||||
},
|
||||
{
|
||||
'question': 'Comment créer une nouvelle organisation ?',
|
||||
'answer': 'Dans la section Organisations, utilisez le bouton "Nouvelle organisation" et suivez les étapes du formulaire.',
|
||||
'category': 'Organisations',
|
||||
'icon': Icons.business,
|
||||
},
|
||||
{
|
||||
'question': 'Comment planifier un événement ?',
|
||||
'answer': 'Accédez à la section Événements, cliquez sur "Nouvel événement" et configurez les détails, date, lieu et participants.',
|
||||
'category': 'Événements',
|
||||
'icon': Icons.event,
|
||||
},
|
||||
{
|
||||
'question': 'L\'application ne se synchronise pas',
|
||||
'answer': 'Vérifiez votre connexion internet. Si le problème persiste, déconnectez-vous et reconnectez-vous.',
|
||||
'category': 'Technique',
|
||||
'icon': Icons.sync_problem,
|
||||
},
|
||||
{
|
||||
'question': 'Comment modifier mes informations personnelles ?',
|
||||
'answer': 'Allez dans Plus > Profil pour modifier vos informations personnelles et préférences.',
|
||||
'category': 'Tout',
|
||||
'icon': Icons.edit,
|
||||
},
|
||||
];
|
||||
|
||||
if (_selectedCategoryIndex == 0) return allFAQs; // Tout
|
||||
|
||||
final selectedCategory = _categories[_selectedCategoryIndex];
|
||||
return allFAQs.where((faq) => faq['category'] == selectedCategory).toList();
|
||||
}
|
||||
|
||||
// ==================== MÉTHODES D'ACTION ====================
|
||||
|
||||
/// Démarrer un chat en direct
|
||||
void _startLiveChat() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Chat en direct'),
|
||||
content: const Text(
|
||||
'Contacter le support par email pour toute question. '
|
||||
'Notre équipe vous répondra dans les meilleurs délais.',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Fermer'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
_contactByEmail();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF6C5CE7),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('Envoyer un email'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Signaler un bug
|
||||
void _reportBug() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Signaler un bug'),
|
||||
content: const Text(
|
||||
'Décrivez le problème rencontré et les étapes pour le reproduire. '
|
||||
'Notre équipe technique vous répondra rapidement.',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Annuler'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
_launchUrl('mailto:support@unionflow.com?subject=Rapport de bug - UnionFlow Mobile');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFFE17055),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('Signaler'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Demander une fonctionnalité
|
||||
void _requestFeature() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Demander une fonctionnalité'),
|
||||
content: const Text(
|
||||
'Partagez vos idées d\'amélioration ! '
|
||||
'Nous étudions toutes les suggestions pour améliorer UnionFlow.',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Annuler'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
_launchUrl('mailto:support@unionflow.com?subject=Demande de fonctionnalité - UnionFlow Mobile');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0984E3),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('Envoyer'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Contacter par email
|
||||
void _contactByEmail() {
|
||||
_launchUrl('mailto:support@unionflow.com?subject=Support UnionFlow Mobile');
|
||||
}
|
||||
|
||||
/// Ouvrir un guide
|
||||
void _openGuide(String guideId) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Guide'),
|
||||
content: Text(
|
||||
'Consultez notre documentation en ligne pour le guide "$guideId".',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Fermer'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
_launchUrl('https://docs.unionflow.com/$guideId');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF6C5CE7),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('Voir en ligne'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Afficher la visite guidée
|
||||
void _showHelpTour() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Visite guidée'),
|
||||
content: const Text(
|
||||
'Parcourez les onglets de l\'application pour découvrir les fonctionnalités. '
|
||||
'En cas de question, contactez le support par email.',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Fermer'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
_contactByEmail();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF6C5CE7),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('Contacter le support'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Lancer une URL
|
||||
Future<void> _launchUrl(String url) async {
|
||||
try {
|
||||
final uri = Uri.parse(url);
|
||||
if (await canLaunchUrl(uri)) {
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
} else {
|
||||
_showErrorSnackBar('Impossible d\'ouvrir le lien');
|
||||
}
|
||||
} catch (e) {
|
||||
_showErrorSnackBar('Erreur lors de l\'ouverture du lien');
|
||||
}
|
||||
}
|
||||
|
||||
/// Afficher un message d'erreur
|
||||
void _showErrorSnackBar(String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
backgroundColor: const Color(0xFFE74C3C),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Afficher un message de succès
|
||||
void _showSuccessSnackBar(String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
backgroundColor: const Color(0xFF00B894),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user