import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart' show defaultTargetPlatform, TargetPlatform, kIsWeb; import 'package:package_info_plus/package_info_plus.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../../../shared/design_system/unionflow_design_system.dart'; import '../../../../shared/widgets/core_card.dart'; import '../../../../shared/widgets/info_badge.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: Theme.of(context).scaffoldBackgroundColor, appBar: UFAppBar( title: 'À PROPOS', actions: [ IconButton( icon: const Icon(Icons.share_outlined, size: 20), onPressed: _shareApp, ), ], ), body: SingleChildScrollView( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header harmonisé _buildHeader(), const SizedBox(height: 8), // Informations de l'application _buildAppInfoSection(), const SizedBox(height: 8), // Équipe de développement _buildTeamSection(), const SizedBox(height: 8), // Fonctionnalités _buildFeaturesSection(), const SizedBox(height: 8), // Liens utiles _buildLinksSection(), const SizedBox(height: 8), // Support et contact _buildSupportSection(), const SizedBox(height: 80), ], ), ), ); } /// Header épuré Widget _buildHeader() { return Center( child: Column( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: AppColors.primaryGreen.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: const Icon( Icons.account_balance, color: AppColors.primaryGreen, size: 32, ), ), const SizedBox(height: 8), Text( 'UNIONFLOW MOBILE', style: AppTypography.headerSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.2), ), Text( 'Gestion d\'associations et syndicats', style: AppTypography.subtitleSmall, ), const SizedBox(height: 8), if (_packageInfo != null) InfoBadge( text: 'VERSION ${_packageInfo!.version}', backgroundColor: AppColors.lightSurface, textColor: AppColors.textSecondaryLight, ), ], ), ); } /// Section informations de l'application Widget _buildAppInfoSection() { return CoreCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'INFORMATIONS', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), const SizedBox(height: 8), _buildInfoRow('Construction', _packageInfo?.buildNumber ?? '...'), _buildInfoRow('Package', _packageInfo?.packageName ?? '...'), _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: 4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: AppTypography.bodyTextSmall.copyWith(color: AppColors.textSecondaryLight), ), Flexible( child: Text( value, style: AppTypography.actionText.copyWith(fontSize: 12), textAlign: TextAlign.end, ), ), ], ), ); } /// Section équipe de développement Widget _buildTeamSection() { return CoreCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'ÉQUIPE', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), const SizedBox(height: 8), _buildTeamMember( 'UnionFlow Team', 'Architecture & Dev', Icons.code, AppColors.primaryGreen, ), _buildTeamMember( 'Design System', 'UI / UX Focus', Icons.design_services, AppColors.brandGreenLight, ), ], ), ); } /// Membre de l'équipe Widget _buildTeamMember(String name, String role, IconData icon, Color color) { return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon(icon, color: color, size: 16), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(name, style: AppTypography.actionText.copyWith(fontSize: 12)), Text(role, style: AppTypography.subtitleSmall.copyWith(fontSize: 10)), ], ), ), ], ), ); } /// Section fonctionnalités Widget _buildFeaturesSection() { return CoreCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'FONCTIONNALITÉS', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), const SizedBox(height: 8), _buildFeatureItem('Membres', 'Administration complète', Icons.people, AppColors.primaryGreen), _buildFeatureItem('Organisations', 'Syndicats & Fédérations', Icons.business, AppColors.brandGreenLight), _buildFeatureItem('Événements', 'Planification & Suivi', Icons.event, AppColors.success), _buildFeatureItem('Sécurité', 'Auth Keycloak OIDC', Icons.security, AppColors.warning), ], ), ); } /// Élément de fonctionnalité Widget _buildFeatureItem(String title, String description, IconData icon, Color color) { return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ Icon(icon, color: color, size: 16), 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)), ], ), ), ], ), ); } /// Section liens utiles Widget _buildLinksSection() { return CoreCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'LIENS UTILES', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), const SizedBox(height: 8), _buildLinkItem('Site Web', 'https://unionflow.com', Icons.web, () => _launchUrl('https://unionflow.com')), _buildLinkItem('Documentation', 'Guide d\'utilisation', Icons.book, () => _launchUrl('https://docs.unionflow.com')), _buildLinkItem('Confidentialité', 'Protection des données', Icons.privacy_tip, () => _launchUrl('https://unionflow.com/privacy')), _buildLinkItem('Évaluer l\'app', 'Noter sur le store', Icons.star, _showRatingDialog), ], ), ); } /// Élément de lien Widget _buildLinkItem(String title, String subtitle, IconData icon, VoidCallback onTap) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(4), child: Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: [ Icon(icon, color: AppColors.primaryGreen, size: 16), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: AppTypography.actionText.copyWith(fontSize: 12)), Text(subtitle, style: AppTypography.subtitleSmall.copyWith(fontSize: 10)), ], ), ), const Icon(Icons.chevron_right, color: AppColors.textSecondaryLight, size: 14), ], ), ), ); } /// Section support Widget _buildSupportSection() { return CoreCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'SUPPORT', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), const SizedBox(height: 8), _buildSupportItem('Email', 'support@unionflow.com', Icons.email, () => _launchUrl('mailto:support@unionflow.com')), _buildSupportItem('Bug', 'Signaler un problème', Icons.bug_report, () => _showBugReportDialog()), const SizedBox(height: 12), const Center( child: Column( children: [ Text('© 2024 UNIONFLOW', style: AppTypography.badgeText), Text('Fait avec ❤️ pour les syndicats', style: AppTypography.subtitleSmall), ], ), ), ], ), ); } /// Élément de support Widget _buildSupportItem(String title, String subtitle, IconData icon, VoidCallback onTap) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(4), child: Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: [ Icon(icon, color: AppColors.error, size: 16), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: AppTypography.actionText.copyWith(fontSize: 12)), Text(subtitle, style: AppTypography.subtitleSmall.copyWith(fontSize: 10)), ], ), ), const Icon(Icons.chevron_right, color: AppColors.textSecondaryLight, size: 14), ], ), ), ); } /// 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: AppColors.primaryGreen, foregroundColor: Colors.white, ), 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: AppColors.primaryGreen, foregroundColor: Colors.white, ), 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(); _launchStoreForRating(); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryGreen, foregroundColor: Colors.white, ), child: const Text('Évaluer maintenant'), ), ], ), ); } /// Partager les infos de l'app (titre, description, lien) Future _shareApp() async { final version = _packageInfo != null ? '${_packageInfo!.version}+${_packageInfo!.buildNumber}' : ''; await Share.share( 'Découvrez UnionFlow - Mouvement d\'entraide et de solidarité.\n' 'Version $version\n' 'https://unionflow.com', subject: 'UnionFlow - Application mobile', ); } /// Ouvrir le store (Play Store / App Store) pour noter l'app Future _launchStoreForRating() async { try { final packageName = _packageInfo?.packageName ?? 'dev.lions.unionflow'; String storeUrl; if (kIsWeb) { storeUrl = 'https://unionflow.com'; } else if (defaultTargetPlatform == TargetPlatform.android) { storeUrl = 'https://play.google.com/store/apps/details?id=$packageName'; } else if (defaultTargetPlatform == TargetPlatform.iOS) { // Remplacer par l'ID App Store réel une fois l'app publiée storeUrl = 'https://apps.apple.com/app/id0000000000'; } else { storeUrl = 'https://unionflow.com'; } final uri = Uri.parse(storeUrl); if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication); } else { _showErrorSnackBar('Impossible d\'ouvrir le store'); } } catch (e) { _showErrorSnackBar('Erreur lors de l\'ouverture du store'); } } /// Afficher un message d'erreur void _showErrorSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: AppColors.error, behavior: SnackBarBehavior.floating, ), ); } }