import 'package:flutter/material.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../../../shared/design_system/tokens/color_tokens.dart'; import '../../../../shared/design_system/tokens/spacing_tokens.dart'; /// Page À propos - UnionFlow Mobile /// /// Page d'informations sur l'application, version, équipe de développement, /// liens utiles et fonctionnalités de support. class AboutPage extends StatefulWidget { const AboutPage({super.key}); @override State createState() => _AboutPageState(); } class _AboutPageState extends State { PackageInfo? _packageInfo; @override void initState() { super.initState(); _loadPackageInfo(); } Future _loadPackageInfo() async { final info = await PackageInfo.fromPlatform(); setState(() { _packageInfo = info; }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF8F9FA), body: SingleChildScrollView( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header harmonisé _buildHeader(), const SizedBox(height: 16), // Informations de l'application _buildAppInfoSection(), const SizedBox(height: 16), // Équipe de développement _buildTeamSection(), const SizedBox(height: 16), // Fonctionnalités _buildFeaturesSection(), const SizedBox(height: 16), // Liens utiles _buildLinksSection(), const SizedBox(height: 16), // Support et contact _buildSupportSection(), const SizedBox(height: 80), ], ), ), ); } /// Header harmonisé avec le design system Widget _buildHeader() { return Container( padding: const EdgeInsets.all(SpacingTokens.xl), decoration: BoxDecoration( gradient: const LinearGradient( colors: ColorTokens.primaryGradient, begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(SpacingTokens.xl), boxShadow: [ BoxShadow( color: ColorTokens.primary.withOpacity(0.3), blurRadius: 20, offset: const Offset(0, 8), ), ], ), child: Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(12), ), child: const Icon( Icons.info, color: Colors.white, size: 24, ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'À propos de UnionFlow', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), Text( 'Version et informations de l\'application', style: TextStyle( fontSize: 14, color: Colors.white.withOpacity(0.8), ), ), ], ), ), ], ), ); } /// Section informations de l'application Widget _buildAppInfoSection() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.mobile_friendly, color: Colors.grey[600], size: 20, ), const SizedBox(width: 8), Text( 'Informations de l\'application', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.grey[800], ), ), ], ), const SizedBox(height: 16), // Logo et nom de l'app Center( child: Column( children: [ Container( width: 80, height: 80, decoration: BoxDecoration( gradient: const LinearGradient( colors: ColorTokens.primaryGradient, begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(SpacingTokens.xxl), ), child: const Icon( Icons.account_balance, color: Colors.white, size: 40, ), ), const SizedBox(height: 12), const Text( 'UnionFlow Mobile', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFF1F2937), ), ), const SizedBox(height: 4), Text( 'Gestion d\'associations et syndicats', style: TextStyle( fontSize: 14, color: Colors.grey[600], ), ), ], ), ), const SizedBox(height: 20), // Informations techniques _buildInfoRow('Version', _packageInfo?.version ?? 'Chargement...'), _buildInfoRow('Build', _packageInfo?.buildNumber ?? 'Chargement...'), _buildInfoRow('Package', _packageInfo?.packageName ?? 'Chargement...'), _buildInfoRow('Plateforme', 'Android/iOS'), _buildInfoRow('Framework', 'Flutter 3.x'), ], ), ); } /// Ligne d'information Widget _buildInfoRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: TextStyle( fontSize: 14, color: Colors.grey[600], fontWeight: FontWeight.w500, ), ), Flexible( child: Text( value, style: const TextStyle( fontSize: 14, color: Color(0xFF1F2937), fontWeight: FontWeight.w600, ), textAlign: TextAlign.end, ), ), ], ), ); } /// Section équipe de développement Widget _buildTeamSection() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.group, color: Colors.grey[600], size: 20, ), const SizedBox(width: 8), Text( 'Équipe de développement', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.grey[800], ), ), ], ), const SizedBox(height: 16), _buildTeamMember( 'UnionFlow Team', 'Développement & Architecture', Icons.code, ColorTokens.primary, ), _buildTeamMember( 'Design System', 'Interface utilisateur & UX', Icons.design_services, ColorTokens.info, ), _buildTeamMember( 'Support Technique', 'Maintenance & Support', Icons.support_agent, ColorTokens.success, ), ], ), ); } /// Membre de l'équipe Widget _buildTeamMember(String name, String role, IconData icon, Color color) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( icon, color: color, size: 20, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( name, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF1F2937), ), ), Text( role, style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), ), ], ), ); } /// Section fonctionnalités Widget _buildFeaturesSection() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.featured_play_list, color: Colors.grey[600], size: 20, ), const SizedBox(width: 8), Text( 'Fonctionnalités principales', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.grey[800], ), ), ], ), const SizedBox(height: 16), _buildFeatureItem( 'Gestion des membres', 'Administration complète des adhérents', Icons.people, ColorTokens.primary, ), _buildFeatureItem( 'Organisations', 'Gestion des syndicats et fédérations', Icons.business, ColorTokens.info, ), _buildFeatureItem( 'Événements', 'Planification et suivi des événements', Icons.event, ColorTokens.success, ), _buildFeatureItem( 'Tableau de bord', 'Statistiques et métriques en temps réel', Icons.dashboard, ColorTokens.warning, ), _buildFeatureItem( 'Authentification sécurisée', 'Connexion via Keycloak OIDC', Icons.security, ColorTokens.tertiary, ), ], ), ); } /// Élément de fonctionnalité Widget _buildFeatureItem(String title, String description, IconData icon, Color color) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( icon, color: color, size: 20, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF1F2937), ), ), Text( description, style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), ), ], ), ); } /// Section liens utiles Widget _buildLinksSection() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.link, color: Colors.grey[600], size: 20, ), const SizedBox(width: 8), Text( 'Liens utiles', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.grey[800], ), ), ], ), const SizedBox(height: 16), _buildLinkItem( 'Site web officiel', 'https://unionflow.com', Icons.web, () => _launchUrl('https://unionflow.com'), ), _buildLinkItem( 'Documentation', 'Guide d\'utilisation complet', Icons.book, () => _launchUrl('https://docs.unionflow.com'), ), _buildLinkItem( 'Code source', 'Projet open source sur GitHub', Icons.code, () => _launchUrl('https://github.com/unionflow/unionflow'), ), _buildLinkItem( 'Politique de confidentialité', 'Protection de vos données', Icons.privacy_tip, () => _launchUrl('https://unionflow.com/privacy'), ), ], ), ); } /// Élément de lien Widget _buildLinkItem(String title, String subtitle, IconData icon, VoidCallback onTap) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(8), child: Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), child: Row( children: [ Container( padding: const EdgeInsets.all(SpacingTokens.md), decoration: BoxDecoration( color: ColorTokens.primary.withOpacity(0.1), borderRadius: BorderRadius.circular(SpacingTokens.md), ), child: Icon( icon, color: ColorTokens.primary, size: 20, ), ), const SizedBox(width: SpacingTokens.lg), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF1F2937), ), ), Text( subtitle, style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: Colors.grey[400], size: 16, ), ], ), ), ); } /// Section support et contact Widget _buildSupportSection() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.support_agent, color: Colors.grey[600], size: 20, ), const SizedBox(width: 8), Text( 'Support et contact', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.grey[800], ), ), ], ), const SizedBox(height: 16), _buildSupportItem( 'Support technique', 'support@unionflow.com', Icons.email, () => _launchUrl('mailto:support@unionflow.com'), ), _buildSupportItem( 'Signaler un bug', 'Rapporter un problème technique', Icons.bug_report, () => _showBugReportDialog(), ), _buildSupportItem( 'Suggérer une amélioration', 'Proposer de nouvelles fonctionnalités', Icons.lightbulb, () => _showFeatureRequestDialog(), ), _buildSupportItem( 'Évaluer l\'application', 'Donner votre avis sur les stores', Icons.star, () => _showRatingDialog(), ), const SizedBox(height: 20), // Copyright et mentions légales Center( child: Column( children: [ Text( '© 2024 UnionFlow. Tous droits réservés.', style: TextStyle( fontSize: 12, color: Colors.grey[600], ), textAlign: TextAlign.center, ), const SizedBox(height: 4), Text( 'Développé avec ❤️ pour les organisations syndicales', style: TextStyle( fontSize: 12, color: Colors.grey[500], ), textAlign: TextAlign.center, ), ], ), ), ], ), ); } /// Élément de support Widget _buildSupportItem(String title, String subtitle, IconData icon, VoidCallback onTap) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(8), child: Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFF00B894).withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( icon, color: const Color(0xFF00B894), size: 20, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF1F2937), ), ), Text( subtitle, style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: Colors.grey[400], size: 16, ), ], ), ), ); } /// Lancer une URL Future _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 le dialogue de rapport de bug void _showBugReportDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Signaler un bug'), content: const Text( 'Pour signaler un bug, veuillez envoyer un email à support@unionflow.com ' 'en décrivant le problème rencontré et les étapes pour le reproduire.', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Fermer'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _launchUrl('mailto:support@unionflow.com?subject=Rapport de bug - UnionFlow Mobile'); }, style: ElevatedButton.styleFrom( backgroundColor: ColorTokens.primary, foregroundColor: ColorTokens.onPrimary, ), child: const Text('Envoyer un email'), ), ], ), ); } /// Afficher le dialogue de demande de fonctionnalité void _showFeatureRequestDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Suggérer une amélioration'), content: const Text( 'Nous sommes toujours à l\'écoute de vos suggestions ! ' 'Envoyez-nous vos idées d\'amélioration par email.', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Fermer'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _launchUrl('mailto:support@unionflow.com?subject=Suggestion d\'amélioration - UnionFlow Mobile'); }, style: ElevatedButton.styleFrom( backgroundColor: ColorTokens.primary, foregroundColor: ColorTokens.onPrimary, ), child: const Text('Envoyer une suggestion'), ), ], ), ); } /// Afficher le dialogue d'évaluation void _showRatingDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Évaluer l\'application'), content: const Text( 'Votre avis nous aide à améliorer UnionFlow ! ' 'Prenez quelques secondes pour évaluer l\'application sur votre store.', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Plus tard'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); // Ici on pourrait utiliser un package comme in_app_review _showErrorSnackBar('Fonctionnalité bientôt disponible'); }, style: ElevatedButton.styleFrom( backgroundColor: ColorTokens.primary, foregroundColor: ColorTokens.onPrimary, ), child: const Text('Évaluer maintenant'), ), ], ), ); } /// Afficher un message d'erreur void _showErrorSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: const Color(0xFFE74C3C), behavior: SnackBarBehavior.floating, ), ); } }