import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'navbar.dart'; import 'page2.dart'; class PageConnexion extends StatefulWidget { const PageConnexion({super.key}); @override State createState() => _PageConnexionState(); } class _PageConnexionState extends State with TickerProviderStateMixin { final TextEditingController emailController = TextEditingController(); final TextEditingController passwordController = TextEditingController(); final FirebaseAuth _auth = FirebaseAuth.instance; bool _isLoading = false; bool _obscurePassword = true; late AnimationController _animationController; late Animation _fadeAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this, ); _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); _animationController.forward(); } @override void dispose() { _animationController.dispose(); super.dispose(); } void _seConnecter() async { if (emailController.text.trim().isEmpty || passwordController.text.trim().isEmpty) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('Veuillez remplir tous les champs'), backgroundColor: Colors.orange, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), ); return; } setState(() { _isLoading = true; }); try { await _auth.signInWithEmailAndPassword( email: emailController.text.trim(), password: passwordController.text.trim(), ); Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => MinimalExample()), ); } on FirebaseAuthException catch (e) { String message = 'Erreur inconnue'; if (e.code == 'user-not-found') { message = 'Aucun utilisateur trouvé avec cet email.'; } else if (e.code == 'wrong-password') { message = 'Mot de passe incorrect.'; } else if (e.code == 'invalid-email') { message = 'Format d\'email invalide.'; } ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: [ const Icon(Icons.error_outline, color: Colors.white), const SizedBox(width: 8), Expanded(child: Text(message)), ], ), backgroundColor: Colors.red, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), ); } finally { setState(() { _isLoading = false; }); } } @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFF4A90E2), Color(0xFF2E7D82), Color(0xFF1B5E62), ], ), ), child: SafeArea( child: SingleChildScrollView( child: FadeTransition( opacity: _fadeAnimation, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 20), // Header avec bouton retour Row( children: [ Container( decoration: BoxDecoration( color: Colors.white.withOpacity(0.15), borderRadius: BorderRadius.circular(12), ), child: IconButton( onPressed: () => Navigator.pop(context), icon: const Icon( Icons.arrow_back_ios_new, color: Colors.white, ), ), ), const Expanded( child: Text( 'Connexion', style: TextStyle( fontSize: 24, color: Colors.white, fontWeight: FontWeight.w600, ), textAlign: TextAlign.center, ), ), const SizedBox(width: 48), ], ), const SizedBox(height: 40), // Logo et titre Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white.withOpacity(0.15), borderRadius: BorderRadius.circular(20), border: Border.all( color: Colors.white.withOpacity(0.2), width: 1, ), ), child: Column( children: [ Container( height: 80, width: 80, decoration: BoxDecoration( color: Colors.white.withOpacity(0.15), shape: BoxShape.circle, border: Border.all( color: Colors.white.withOpacity(0.3), width: 2, ), ), child: const Icon( Icons.medical_services_outlined, size: 40, color: Colors.white, ), ), const SizedBox(height: 16), const Text( 'TuberculoScan', style: TextStyle( fontSize: 28, color: Colors.white, fontWeight: FontWeight.bold, letterSpacing: 1.2, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), const Text( 'Connectez-vous pour accéder au diagnostic', style: TextStyle( fontSize: 16, color: Colors.white70, fontWeight: FontWeight.w300, ), textAlign: TextAlign.center, ), ], ), ), const SizedBox(height: 40), // Formulaire de connexion Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: Colors.white.withOpacity(0.95), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 20, offset: const Offset(0, 8), ), ], ), child: Column( children: [ // Champ Email Container( decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(15), border: Border.all( color: Colors.grey.shade200, width: 1, ), ), child: TextField( controller: emailController, decoration: InputDecoration( labelText: 'Adresse email', hintText: 'votre.email@exemple.com', prefixIcon: Container( margin: const EdgeInsets.all(12), padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFF4A90E2) .withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.email_outlined, color: Color(0xFF4A90E2), size: 20, ), ), border: InputBorder.none, labelStyle: TextStyle( color: Colors.grey.shade600, fontSize: 16, ), hintStyle: TextStyle( color: Colors.grey.shade400, fontSize: 14, ), ), keyboardType: TextInputType.emailAddress, ), ), const SizedBox(height: 20), // Champ mot de passe Container( decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(15), border: Border.all( color: Colors.grey.shade200, width: 1, ), ), child: TextField( controller: passwordController, decoration: InputDecoration( labelText: 'Mot de passe', hintText: 'Entrez votre mot de passe', prefixIcon: Container( margin: const EdgeInsets.all(12), padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFF4A90E2) .withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.lock_outline, color: Color(0xFF4A90E2), size: 20, ), ), suffixIcon: IconButton( onPressed: () { setState(() { _obscurePassword = !_obscurePassword; }); }, icon: Icon( _obscurePassword ? Icons.visibility_off_outlined : Icons.visibility_outlined, color: Colors.grey.shade600, ), ), border: InputBorder.none, labelStyle: TextStyle( color: Colors.grey.shade600, fontSize: 16, ), hintStyle: TextStyle( color: Colors.grey.shade400, fontSize: 14, ), ), obscureText: _obscurePassword, ), ), const SizedBox(height: 16), // Mot de passe oublié Align( alignment: Alignment.centerRight, child: TextButton( onPressed: () { // Action mot de passe oublié }, child: const Text( 'Mot de passe oublié?', style: TextStyle( color: Color(0xFF4A90E2), fontSize: 14, fontWeight: FontWeight.w500, ), ), ), ), const SizedBox(height: 24), // Bouton de connexion Container( height: 55, width: double.infinity, decoration: BoxDecoration( gradient: const LinearGradient( colors: [ Color(0xFF00E676), Color(0xFF00C853), ], ), borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( color: const Color(0xFF00E676).withOpacity(0.4), blurRadius: 15, offset: const Offset(0, 5), ), ], ), child: ElevatedButton( onPressed: _isLoading ? null : _seConnecter, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), ), child: _isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.login_rounded, color: Colors.white, size: 20, ), SizedBox(width: 8), Text( 'Se connecter', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600, ), ), ], ), ), ), ], ), ), const SizedBox(height: 30), // Divider "Ou continuer avec" Row( children: [ Expanded( child: Container( height: 1, color: Colors.white.withOpacity(0.3), ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( "Ou continuer avec", style: TextStyle( color: Colors.white.withOpacity(0.8), fontSize: 14, ), ), ), Expanded( child: Container( height: 1, color: Colors.white.withOpacity(0.3), ), ), ], ), const SizedBox(height: 30), // Bouton Google Center( child: GestureDetector( onTap: () { // Connexion Google à implémenter }, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 15, offset: const Offset(0, 5), ), ], ), child: Image.asset( 'assets/image3.png', height: 32, width: 32, ), ), ), ), const SizedBox(height: 40), // Lien vers inscription Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), borderRadius: BorderRadius.circular(15), border: Border.all( color: Colors.white.withOpacity(0.2), width: 1, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Vous n'avez pas de compte? ", style: TextStyle( color: Colors.white.withOpacity(0.8), fontSize: 14, ), ), TextButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const PageInscription(), ), ); }, child: const Text( 'S\'inscrire', style: TextStyle( color: Color(0xFF00E676), fontSize: 14, fontWeight: FontWeight.w600, ), ), ), ], ), ), const SizedBox(height: 30), ], ), ), ), ), ), ), ); } }