import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:go_router/go_router.dart'; import 'package:geosector_app/core/theme/app_theme.dart'; import 'package:url_launcher/url_launcher.dart'; class LandingPage extends StatefulWidget { const LandingPage({super.key}); @override State createState() => _LandingPageState(); } class _LandingPageState extends State with TickerProviderStateMixin { final PageController _pageController = PageController(); int _currentPage = 0; // Contrôleurs d'animation late List _controllers; late List> _opacityAnimations; late List> _slideAnimations; late List> _scaleAnimations; final List _features = [ FeatureItem( title: 'Gestion intuitive', description: 'Dessinez vos secteurs de distribution directement sur une carte interactive. Les adresses des habitants sont automatiquement intégrées pour une planification optimale.', icon: Icons.map, color: const Color(0xFF2E4057), // Couleur primaire ), FeatureItem( title: 'Suivi en temps réel et traçabilité', description: 'Suivez en temps réel la progression des tournées grâce à un tableau de bord complet. Visualisez les passages effectués et les dons collectés pour une gestion efficace.', icon: Icons.track_changes, color: const Color(0xFF048BA8), // Couleur secondaire ), FeatureItem( title: 'Génération automatique PDF', description: 'Générez des reçus au format PDF instantanément après chaque collecte. Envoyez-les automatiquement par email pour une transparence totale.', icon: Icons.picture_as_pdf, color: const Color(0xFFF18F01), // Couleur accent ), ]; @override void initState() { super.initState(); // Initialiser les contrôleurs d'animation _controllers = List.generate( _features.length, (index) => AnimationController( vsync: this, duration: const Duration(milliseconds: 800), ), ); // Créer les animations _opacityAnimations = _controllers .map((controller) => Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: controller, curve: Curves.easeInOut))) .toList(); _slideAnimations = _controllers .map((controller) => Tween(begin: const Offset(0, 0.2), end: Offset.zero) .animate(CurvedAnimation( parent: controller, curve: Curves.easeOutQuart))) .toList(); _scaleAnimations = _controllers .map((controller) => Tween(begin: 0.8, end: 1.0).animate( CurvedAnimation(parent: controller, curve: Curves.easeOutBack))) .toList(); // Démarrer les animations avec délai _startAnimationsWithDelay(); } void _startAnimationsWithDelay() { for (int i = 0; i < _controllers.length; i++) { Future.delayed(Duration(milliseconds: 300 * (i + 1)), () { if (mounted) { _controllers[i].forward(); } }); } } @override void dispose() { _pageController.dispose(); for (var controller in _controllers) { controller.dispose(); } super.dispose(); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final screenSize = MediaQuery.of(context).size; bool isWebOrTablet = screenSize.width > 600; return Scaffold( // Utilisation d'un ListView pour rendre toute la page défilable, y compris le footer body: SafeArea( child: ListView( children: [ // Header avec logo et navigation Container( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // Logo Row( children: [ Container( width: 40, height: 40, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.asset( 'assets/images/geosector-logo-80.png', fit: BoxFit.cover, ), ), ), const SizedBox(width: 8), Text( 'GEOSECTOR', style: theme.textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), ), ], ), // Navigation const SizedBox(width: 16), // Boutons Contact/Connexion/Inscription if (isWebOrTablet) Row( children: [ TextButton( onPressed: () {}, style: TextButton.styleFrom( foregroundColor: theme.colorScheme.primary, padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8), ), child: const Text('Contact'), ), const SizedBox(width: 8), OutlinedButton( onPressed: () { // Naviguer avec debug print('DEBUG: Navigation vers login admin'); // Utiliser directement les paramètres avec go context.go('/login', extra: {'type': 'admin'}); print('DEBUG: Navigation admin avec extra'); }, style: OutlinedButton.styleFrom( foregroundColor: Colors.red, side: const BorderSide(color: Colors.red), padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8), ), child: const Text('Connexion Administrateur'), ), const SizedBox(width: 8), OutlinedButton( onPressed: () { // Naviguer avec debug print('DEBUG: Navigation vers login user'); // Utiliser directement les paramètres avec go context.go('/login', extra: {'type': 'user'}); print('DEBUG: Navigation user avec extra'); }, style: OutlinedButton.styleFrom( foregroundColor: Colors.green, side: const BorderSide(color: Colors.green), padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8), ), child: const Text('Connexion Utilisateur'), ), const SizedBox(width: 8), ElevatedButton( onPressed: () { context.go('/register?from=landing'); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFF18F01), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8), elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text('S\'inscrire'), ), ], ) else Row( children: [ // Bouton de login administrateur IconButton( icon: const Icon(Icons.admin_panel_settings), tooltip: 'Connexion Administrateur', color: Colors.red, onPressed: () { print('DEBUG: Navigation mobile vers login admin'); context.go('/login', extra: {'type': 'admin'}); print('DEBUG: Navigation mobile admin avec extra'); }, ), // Bouton de login utilisateur IconButton( icon: const Icon(Icons.person), tooltip: 'Connexion Utilisateur', color: Colors.green, onPressed: () { print('DEBUG: Navigation mobile vers login user'); context.go('/login', extra: {'type': 'user'}); print('DEBUG: Navigation mobile user avec extra'); }, ), IconButton( icon: const Icon(Icons.menu), onPressed: () { Scaffold.of(context).openDrawer(); }, ), ], ), ], ), ), // Contenu principal if (isWebOrTablet) _buildWebLayout(theme, screenSize) else _buildMobileLayout(theme, screenSize), // Footer Container( padding: const EdgeInsets.all(32), color: const Color(0xFFF5F5F5), child: Column( children: [ // Trois colonnes du footer isWebOrTablet ? Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Première colonne - Coordonnées Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 30, height: 30, margin: const EdgeInsets.only(right: 8), child: Image.asset( 'assets/images/geosector-logo-80.png', fit: BoxFit.contain, ), ), Text( 'GEOSECTOR', style: theme.textTheme.titleLarge ?.copyWith( fontWeight: FontWeight.bold, color: Colors.black87, ), ), ], ), const SizedBox(height: 16), Row( children: [ Icon(Icons.location_on_outlined, color: Colors.black87, size: 20), const SizedBox(width: 8), Expanded( child: Text( '16 Rue des marguerites, 56930 Pluméliau-Bieuzy', style: theme.textTheme.bodyMedium ?.copyWith(color: Colors.black87), ), ), ], ), const SizedBox(height: 8), Row( children: [ Icon(Icons.phone_outlined, color: Colors.black87, size: 20), const SizedBox(width: 8), Text( '+33 7 69 09 17 06', style: theme.textTheme.bodyMedium ?.copyWith(color: Colors.black87), ), ], ), const SizedBox(height: 8), Row( children: [ Icon(Icons.email_outlined, color: Colors.black87, size: 20), const SizedBox(width: 8), Text( 'contactgeosector@gmail.com', style: theme.textTheme.bodyMedium ?.copyWith(color: Colors.black87), ), ], ), const SizedBox(height: 16), OutlinedButton.icon( onPressed: () async { final Uri url = Uri.parse( 'https://www.facebook.com/geosector/'); if (await canLaunchUrl(url)) { await launchUrl(url, mode: LaunchMode.externalApplication); } }, icon: const Icon(Icons.facebook), label: const Text('Suivez-nous sur Facebook'), style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFF1877F2), side: const BorderSide( color: Color(0xFF1877F2)), ), ), ], ), ), const SizedBox(width: 32), // Deuxième colonne - Liens Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Téléchargement', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), Row( children: [ OutlinedButton.icon( onPressed: () {}, icon: const Icon(Icons.apple), label: const Text('App Store'), style: OutlinedButton.styleFrom( foregroundColor: Colors.black, ), ), const SizedBox(width: 8), OutlinedButton.icon( onPressed: () {}, icon: const Icon(Icons.android), label: const Text('Play Store'), style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFF3DDC84), side: const BorderSide( color: Color(0xFF3DDC84)), ), ), ], ), const SizedBox(height: 24), Text( 'Informations légales', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), TextButton.icon( onPressed: () {}, icon: const Icon(Icons.gavel_outlined, size: 18), label: const Text('Mentions légales'), style: TextButton.styleFrom( padding: EdgeInsets.zero, alignment: Alignment.centerLeft, ), ), TextButton.icon( onPressed: () {}, icon: const Icon(Icons.privacy_tip_outlined, size: 18), label: const Text( 'Politique de confidentialité'), style: TextButton.styleFrom( padding: EdgeInsets.zero, alignment: Alignment.centerLeft, ), ), TextButton.icon( onPressed: () {}, icon: const Icon(Icons.description_outlined, size: 18), label: const Text('Conditions d\'utilisation'), style: TextButton.styleFrom( padding: EdgeInsets.zero, alignment: Alignment.centerLeft, ), ), ], ), ), const SizedBox(width: 32), // Troisième colonne - Formulaire de contact Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Contactez-nous', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), TextField( decoration: InputDecoration( hintText: 'Votre nom', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), ), ), const SizedBox(height: 8), TextField( decoration: InputDecoration( hintText: 'Votre email', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), ), ), const SizedBox(height: 8), TextField( maxLines: 3, decoration: InputDecoration( hintText: 'Votre message', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), ), ), const SizedBox(height: 12), ElevatedButton.icon( onPressed: () {}, icon: const Icon(Icons.send), label: const Text('Envoyer'), style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primary, foregroundColor: Colors.white, minimumSize: const Size(double.infinity, 48), ), ), ], ), ), ], ) : Column( // Version mobile du footer children: [ // Première colonne - Coordonnées Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'GEOSECTOR', style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), ), const SizedBox(height: 16), Row( children: [ Icon(Icons.location_on_outlined, color: theme.colorScheme.primary, size: 20), const SizedBox(width: 8), Expanded( child: Text( '123 Rue de la Distribution, 75000 Paris', style: theme.textTheme.bodyMedium ?.copyWith(color: Colors.black87), ), ), ], ), const SizedBox(height: 8), Row( children: [ Icon(Icons.phone_outlined, color: theme.colorScheme.primary, size: 20), const SizedBox(width: 8), Text( '+33 1 23 45 67 89', style: theme.textTheme.bodyMedium, ), ], ), const SizedBox(height: 8), Row( children: [ Icon(Icons.email_outlined, color: theme.colorScheme.primary, size: 20), const SizedBox(width: 8), Text( 'contact@geosector.com', style: theme.textTheme.bodyMedium, ), ], ), const SizedBox(height: 16), OutlinedButton.icon( onPressed: () async { final Uri url = Uri.parse( 'https://www.facebook.com/geosector/'); if (await canLaunchUrl(url)) { await launchUrl(url, mode: LaunchMode.externalApplication); } }, icon: const Icon(Icons.facebook), label: const Text('Suivez-nous sur Facebook'), style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFF1877F2), side: const BorderSide( color: Color(0xFF1877F2)), minimumSize: const Size(double.infinity, 40), ), ), ], ), const SizedBox(height: 32), // Deuxième colonne - Liens Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Téléchargement', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), Row( children: [ Expanded( child: OutlinedButton.icon( onPressed: () {}, icon: const Icon(Icons.apple), label: const Text('App Store'), style: OutlinedButton.styleFrom( foregroundColor: Colors.black, ), ), ), const SizedBox(width: 8), Expanded( child: OutlinedButton.icon( onPressed: () {}, icon: const Icon(Icons.android), label: const Text('Play Store'), style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFF3DDC84), side: const BorderSide( color: Color(0xFF3DDC84)), ), ), ), ], ), const SizedBox(height: 24), Text( 'Informations légales', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), TextButton.icon( onPressed: () {}, icon: const Icon(Icons.gavel_outlined, size: 18), label: const Text('Mentions légales'), style: TextButton.styleFrom( padding: EdgeInsets.zero, alignment: Alignment.centerLeft, ), ), TextButton.icon( onPressed: () {}, icon: const Icon(Icons.privacy_tip_outlined, size: 18), label: const Text( 'Politique de confidentialité'), style: TextButton.styleFrom( padding: EdgeInsets.zero, alignment: Alignment.centerLeft, ), ), TextButton.icon( onPressed: () {}, icon: const Icon(Icons.description_outlined, size: 18), label: const Text('Conditions d\'utilisation'), style: TextButton.styleFrom( padding: EdgeInsets.zero, alignment: Alignment.centerLeft, ), ), ], ), const SizedBox(height: 32), // Troisième colonne - Formulaire de contact Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Contactez-nous', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), TextField( decoration: InputDecoration( hintText: 'Votre nom', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), ), ), const SizedBox(height: 8), TextField( decoration: InputDecoration( hintText: 'Votre email', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), ), ), const SizedBox(height: 8), TextField( maxLines: 3, decoration: InputDecoration( hintText: 'Votre message', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), ), ), const SizedBox(height: 12), ElevatedButton.icon( onPressed: () {}, icon: const Icon(Icons.send), label: const Text('Envoyer'), style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primary, foregroundColor: Colors.white, minimumSize: const Size(double.infinity, 48), ), ), ], ), ], ), const SizedBox(height: 32), // Copyright Divider(color: Colors.black38), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( '© ${DateTime.now().year} GEOSECTOR. Tous droits réservés. ', style: theme.textTheme.bodySmall ?.copyWith(color: Colors.black87), ), InkWell( onTap: () async { // Ouvrir le lien vers D6SOFT final Uri url = Uri.parse('https://d6soft.fr'); if (await canLaunchUrl(url)) { await launchUrl(url, mode: LaunchMode.externalApplication); } }, child: Text( 'Conception D6SOFT', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.primary, decoration: TextDecoration.underline, ), ), ), ], ), ], ), ), ], ), ), drawer: !isWebOrTablet ? Drawer( child: ListView( padding: EdgeInsets.zero, children: [ DrawerHeader( decoration: const BoxDecoration( gradient: LinearGradient( colors: [Color(0xFF2E4057), Color(0xFF048BA8)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 40, height: 40, child: Image.asset( 'assets/images/geosector-logo-80.png', fit: BoxFit.contain, ), ), const SizedBox(height: 8), Text( 'GEOSECTOR', style: theme.textTheme.headlineSmall?.copyWith( color: Colors.white, fontWeight: FontWeight.bold, ), ), ], ), ), ListTile( leading: const Icon(Icons.star_outline), title: const Text('Fonctionnalités'), onTap: () { Navigator.pop(context); }, ), ListTile( leading: const Icon(Icons.info_outline), title: const Text('À propos'), onTap: () { Navigator.pop(context); }, ), ListTile( leading: const Icon(Icons.email_outlined), title: const Text('Contact'), onTap: () { Navigator.pop(context); }, ), const Divider(), ListTile( leading: const Icon(Icons.login), title: const Text('Se connecter'), onTap: () { Navigator.pop(context); context.go('/login', extra: {'type': 'admin'}); print('DEBUG: Navigation drawer avec extra'); }, ), ListTile( leading: const Icon(Icons.person_add_outlined), title: const Text('S\'inscrire'), onTap: () { Navigator.pop(context); context.go('/register?from=landing'); }, ), ], ), ) : null, ); } Widget _buildWebLayout(ThemeData theme, Size screenSize) { return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Section d'en-tête Container( padding: const EdgeInsets.all(48), decoration: BoxDecoration( color: theme.colorScheme.background, ), child: Stack( children: [ // Fond de carte Positioned.fill( child: Opacity( opacity: 0.1, child: SvgPicture.asset( 'assets/images/city-map-bg-fixed.svg', fit: BoxFit.cover, ), ), ), // Contenu Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Suppression du second menu const SizedBox(height: 80), // Titre principal Text( 'Une application puissante et intuitive, pour une gestion efficace de vos distributions', style: theme.textTheme.displayMedium?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), ), const SizedBox(height: 16), // Sous-titre Text( 'Simplifiez vos distributions, optimisez vos collectes.', style: theme.textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.w300, color: theme.colorScheme.onBackground.withOpacity(0.8), ), ), const SizedBox(height: 32), // Boutons d'action Row( children: [ ElevatedButton.icon( onPressed: () { context.go('/register?from=landing'); }, icon: const Icon(Icons.person_add_outlined), label: const Text('Créer un compte gratuit'), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFF18F01), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 16), elevation: 2, ), ), const SizedBox(width: 16), OutlinedButton.icon( onPressed: () {}, icon: const Icon(Icons.play_circle_outline), label: const Text('Voir la démo'), style: OutlinedButton.styleFrom( foregroundColor: theme.colorScheme.primary, padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 16), side: BorderSide( color: theme.colorScheme.primary, ), ), ), ], ), ], ), ], ), ), // Section des fonctionnalités Container( padding: const EdgeInsets.all(48), color: theme.colorScheme.surface, child: Column( children: [ Text( 'Fonctionnalités principales', style: theme.textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), textAlign: TextAlign.center, ), const SizedBox(height: 48), Row( crossAxisAlignment: CrossAxisAlignment.start, children: _buildFeatureItems(theme, true), ), ], ), ), // Appel à l'action Container( padding: const EdgeInsets.all(48), decoration: const BoxDecoration( gradient: LinearGradient( colors: [Color(0xFF2E4057), Color(0xFF048BA8)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Column( children: [ Text( 'Prêt à tester GEOSECTOR ?', style: theme.textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.bold, color: Colors.white, ), textAlign: TextAlign.center, ), const SizedBox(height: 16), Text( 'Rejoignez notre communauté et commencez à transformer vos distributions dès aujourd\'hui.', style: theme.textTheme.bodyLarge?.copyWith( color: Colors.white.withOpacity(0.9), ), textAlign: TextAlign.center, ), const SizedBox(height: 32), ElevatedButton.icon( onPressed: () { context.go('/register?from=landing'); }, icon: const Icon(Icons.person_add_outlined), label: const Text('Créer un compte gratuitement'), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFF18F01), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 32, vertical: 16), elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), ], ), ), ], ), ); } Widget _buildMobileLayout(ThemeData theme, Size screenSize) { return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Section d'en-tête Container( padding: const EdgeInsets.all(24), color: theme.colorScheme.background, child: Column( children: [ Container( width: 150, height: 150, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 3), ), ], ), padding: const EdgeInsets.all(15), child: Image.asset( 'assets/images/geosector-logo.png', fit: BoxFit.contain, ), ), const SizedBox(height: 24), Text( 'Une application puissante et intuitive, pour une gestion efficace de vos distributions', style: theme.textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), textAlign: TextAlign.center, ), const SizedBox(height: 16), Text( 'Simplifiez vos distributions, optimisez vos collectes.', style: theme.textTheme.bodyMedium, textAlign: TextAlign.center, ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: () { context.go('/register?from=landing'); }, icon: const Icon(Icons.arrow_forward), label: const Text('Commencer gratuitement'), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFF18F01), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 16), minimumSize: const Size(double.infinity, 48), elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), const SizedBox(height: 12), OutlinedButton.icon( onPressed: () {}, icon: const Icon(Icons.play_circle_outline), label: const Text('Voir la démo'), style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 12), minimumSize: const Size(double.infinity, 48), ), ), ], ), ), // Section des fonctionnalités Container( padding: const EdgeInsets.all(24), color: theme.colorScheme.surface, child: Column( children: [ Text( 'Fonctionnalités principales', style: theme.textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), textAlign: TextAlign.center, ), const SizedBox(height: 24), SizedBox( height: 350, child: PageView.builder( controller: _pageController, itemCount: _features.length, onPageChanged: (int page) { setState(() { _currentPage = page; }); }, itemBuilder: (context, index) { return AnimatedBuilder( animation: _controllers[index], builder: (context, child) { return Opacity( opacity: _opacityAnimations[index].value, child: Transform.translate( offset: Offset(0, 20 * (1 - _slideAnimations[index].value.dy)), child: Transform.scale( scale: _scaleAnimations[index].value, child: _buildFeatureCard(_features[index], theme), ), ), ); }, ); }, ), ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate( _features.length, (index) => Container( width: 10, height: 10, margin: const EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration( shape: BoxShape.circle, color: _currentPage == index ? theme.colorScheme.primary : theme.colorScheme.primary.withOpacity(0.3), ), ), ), ), ], ), ), // Appel à l'action Container( padding: const EdgeInsets.all(24), color: theme.colorScheme.primary, child: Column( children: [ Text( 'Prêt à tester GEOSECTOR ?', style: theme.textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.bold, color: Colors.white, ), textAlign: TextAlign.center, ), const SizedBox(height: 16), Text( 'Rejoignez notre communauté dès aujourd\'hui.', style: theme.textTheme.bodyMedium?.copyWith( color: Colors.white.withOpacity(0.9), ), textAlign: TextAlign.center, ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: () { context.go('/register?from=landing'); }, icon: const Icon(Icons.person_add_outlined), label: const Text('Créer un compte'), style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: theme.colorScheme.primary, padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 12), minimumSize: const Size(double.infinity, 48), ), ), ], ), ), ], ), ); } List _buildFeatureItems(ThemeData theme, bool isWeb) { return List.generate(_features.length, (index) { return Expanded( child: Padding( padding: const EdgeInsets.all(16.0), child: AnimatedBuilder( animation: _controllers[index], builder: (context, child) { return Opacity( opacity: _opacityAnimations[index].value, child: Transform.translate( offset: Offset(0, 20 * (1 - _slideAnimations[index].value.dy)), child: Transform.scale( scale: _scaleAnimations[index].value, child: _buildFeatureCard(_features[index], theme), ), ), ); }, ), ), ); }); } Widget _buildFeatureCard(FeatureItem feature, ThemeData theme) { return Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: 100, height: 100, decoration: BoxDecoration( color: feature.color.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon( feature.icon, size: 60, color: feature.color, ), ), const SizedBox(height: 16), Text( feature.title, style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( feature.description, style: theme.textTheme.bodyMedium, textAlign: TextAlign.center, ), ], ), ), ); } } class FeatureItem { final String title; final String description; final IconData icon; final Color color; FeatureItem({ required this.title, required this.description, required this.icon, required this.color, }); }