import 'dart:math' as math; import 'package:base_project/core/constants/ui_constants.dart'; import 'package:base_project/routes/route_names.dart'; import 'package:base_project/view_model/auth/auth_view_model.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../core/providers/dynamic_theme_provider.dart'; import '../../core/providers/theme_provider.dart'; import '../../shared/widgets/buttons/modern_button.dart'; import '../../shared/widgets/inputs/modern_text_field.dart'; import '../../shared/widgets/theme_toggle.dart'; class LoginView extends StatefulWidget { const LoginView({super.key}); @override _LoginViewState createState() => _LoginViewState(); } class _LoginViewState extends State with TickerProviderStateMixin { // Controllers final TextEditingController _emailController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); final FocusNode _emailFocusNode = FocusNode(); final FocusNode _passwordFocusNode = FocusNode(); // Animation Controllers late AnimationController _pageAnimationController; late AnimationController _formAnimationController; late AnimationController _logoAnimationController; late AnimationController _backgroundAnimationController; late AnimationController _particleAnimationController; // Animations late Animation _pageFadeAnimation; late Animation _pageSlideAnimation; late Animation _formScaleAnimation; late Animation _logoScaleAnimation; late Animation _logoRotationAnimation; late Animation _backgroundOpacityAnimation; late Animation _particleRotationAnimation; // State bool _isPasswordVisible = false; bool _isFormValid = false; bool _isEmailFocused = false; bool _isPasswordFocused = false; @override void initState() { super.initState(); _initializeAnimations(); _startPageAnimation(); _setupFocusListeners(); } void _setupFocusListeners() { _emailFocusNode.addListener(() { setState(() { _isEmailFocused = _emailFocusNode.hasFocus; }); }); _passwordFocusNode.addListener(() { setState(() { _isPasswordFocused = _passwordFocusNode.hasFocus; }); }); } void _initializeAnimations() { // Page Animation Controller _pageAnimationController = AnimationController( duration: UIConstants.durationSlow, vsync: this, ); // Form Animation Controller _formAnimationController = AnimationController( duration: UIConstants.durationNormal, vsync: this, ); // Logo Animation Controller _logoAnimationController = AnimationController( duration: UIConstants.durationVerySlow, vsync: this, ); // Background Animation Controller _backgroundAnimationController = AnimationController( duration: UIConstants.durationSlow, vsync: this, ); // Particle Animation Controller _particleAnimationController = AnimationController( duration: const Duration(seconds: 10), vsync: this, ); // Page Animations _pageFadeAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _pageAnimationController, curve: UIConstants.curveNormal, )); _pageSlideAnimation = Tween( begin: const Offset(0, 0.3), end: Offset.zero, ).animate(CurvedAnimation( parent: _pageAnimationController, curve: UIConstants.curveNormal, )); // Form Animations _formScaleAnimation = Tween( begin: 0.8, end: 1.0, ).animate(CurvedAnimation( parent: _formAnimationController, curve: UIConstants.curveElastic, )); // Logo Animations _logoScaleAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _logoAnimationController, curve: UIConstants.curveElastic, )); _logoRotationAnimation = Tween( begin: -0.5, end: 0.0, ).animate(CurvedAnimation( parent: _logoAnimationController, curve: UIConstants.curveElastic, )); // Background Animations _backgroundOpacityAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _backgroundAnimationController, curve: UIConstants.curveNormal, )); // Particle Animations _particleRotationAnimation = Tween( begin: 0.0, end: 2 * math.pi, ).animate(CurvedAnimation( parent: _particleAnimationController, curve: Curves.linear, )); // Listen to form changes _emailController.addListener(_validateForm); _passwordController.addListener(_validateForm); } void _startPageAnimation() async { await Future.delayed(const Duration(milliseconds: 300)); _backgroundAnimationController.forward(); await Future.delayed(const Duration(milliseconds: 200)); _pageAnimationController.forward(); await Future.delayed(const Duration(milliseconds: 500)); _logoAnimationController.forward(); await Future.delayed(const Duration(milliseconds: 300)); _formAnimationController.forward(); _particleAnimationController.repeat(); } void _validateForm() { final isValid = _emailController.text.isNotEmpty && _passwordController.text.isNotEmpty; if (isValid != _isFormValid) { setState(() { _isFormValid = isValid; }); } } @override void dispose() { _emailController.dispose(); _passwordController.dispose(); _emailFocusNode.dispose(); _passwordFocusNode.dispose(); _pageAnimationController.dispose(); _formAnimationController.dispose(); _logoAnimationController.dispose(); _backgroundAnimationController.dispose(); _particleAnimationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // Always use dynamic theme provider for guaranteed dynamic colors return Consumer( builder: (context, dynamicThemeProvider, child) { final colorScheme = dynamicThemeProvider.getCurrentColorScheme( Theme.of(context).brightness == Brightness.dark); final size = MediaQuery.of(context).size; return Scaffold( body: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ colorScheme.primary, colorScheme.primaryContainer, colorScheme.secondary, colorScheme.tertiary, ], stops: const [0.0, 0.3, 0.7, 1.0], ), ), child: Stack( children: [ // Animated Background Particles _buildParticleBackground(colorScheme), // Glassmorphism Background _buildGlassmorphismBackground(colorScheme), // Theme Toggle Button Positioned( top: UIConstants.spacing16, right: UIConstants.spacing16, child: Consumer( builder: (context, themeProvider, child) { return Container( decoration: BoxDecoration( color: colorScheme.surface.withOpacity(0.1), borderRadius: BorderRadius.circular(UIConstants.radiusFull), border: Border.all( color: colorScheme.surface.withOpacity(0.2), width: 1, ), ), child: ThemeToggle( isDarkMode: themeProvider.isDarkMode, onThemeChanged: (isDark) { themeProvider.setTheme(isDark); }, size: UIConstants.iconSizeLarge, ), ); }, ), ), // Main Content SafeArea( child: SingleChildScrollView( padding: UIConstants.getResponsivePadding( context, mobile: const EdgeInsets.all(UIConstants.spacing16), tablet: const EdgeInsets.all(UIConstants.spacing24), desktop: const EdgeInsets.all(UIConstants.spacing32), ), child: ConstrainedBox( constraints: BoxConstraints( minHeight: size.height - MediaQuery.of(context).padding.top - MediaQuery.of(context).padding.bottom, ), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ // Logo Section _buildLogoSection(colorScheme), SizedBox( height: UIConstants.getResponsiveSpacing( context, mobile: UIConstants.spacing32, tablet: UIConstants.spacing40, desktop: UIConstants.spacing48, )), // Welcome Text _buildWelcomeSection(colorScheme), SizedBox( height: UIConstants.getResponsiveSpacing( context, mobile: UIConstants.spacing32, tablet: UIConstants.spacing40, desktop: UIConstants.spacing48, )), // Login Form _buildLoginForm(colorScheme), SizedBox( height: UIConstants.getResponsiveSpacing( context, mobile: UIConstants.spacing20, tablet: UIConstants.spacing24, desktop: UIConstants.spacing32, )), // Login Button _buildLoginButton(colorScheme), SizedBox( height: UIConstants.getResponsiveSpacing( context, mobile: UIConstants.spacing32, tablet: UIConstants.spacing40, desktop: UIConstants.spacing48, )), // Sign Up Section _buildSignUpSection(colorScheme), SizedBox( height: UIConstants.getResponsiveSpacing( context, mobile: UIConstants.spacing20, tablet: UIConstants.spacing24, desktop: UIConstants.spacing32, )), // Social Login Section _buildSocialLoginSection(colorScheme), ], ), ), ), ), ], ), ), ); }, ); } Widget _buildParticleBackground(ColorScheme colorScheme) { return AnimatedBuilder( animation: _particleRotationAnimation, builder: (context, child) { return CustomPaint( painter: ParticlePainter( rotation: _particleRotationAnimation.value, color: colorScheme.surface.withOpacity(0.1), ), size: Size.infinite, ); }, ); } Widget _buildGlassmorphismBackground(ColorScheme colorScheme) { return AnimatedBuilder( animation: _backgroundAnimationController, builder: (context, child) { return FadeTransition( opacity: _backgroundOpacityAnimation, child: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ colorScheme.surface.withOpacity(0.05), colorScheme.surface.withOpacity(0.1), colorScheme.surface.withOpacity(0.05), ], ), ), ), ); }, ); } Widget _buildLogoSection(ColorScheme colorScheme) { return AnimatedBuilder( animation: _logoAnimationController, builder: (context, child) { return Transform.scale( scale: _logoScaleAnimation.value, child: Transform.rotate( angle: _logoRotationAnimation.value, child: Container( width: UIConstants.getResponsiveValue( context, mobile: UIConstants.logoSizeLarge, // Reduced from 1.5x tablet: UIConstants.logoSizeXLarge, // Reduced from 1.5x desktop: UIConstants.logoSizeXLarge, // Reduced from 1.5x ), height: UIConstants.getResponsiveValue( context, mobile: UIConstants.logoSizeLarge, // Reduced from 1.5x tablet: UIConstants.logoSizeXLarge, // Reduced from 1.5x desktop: UIConstants.logoSizeXLarge, // Reduced from 1.5x ), decoration: BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ colorScheme.surface.withOpacity(0.2), colorScheme.surface.withOpacity(0.1), ], ), border: Border.all( color: colorScheme.surface.withOpacity(0.3), width: 2, ), boxShadow: [ BoxShadow( color: colorScheme.primary.withOpacity(0.3), blurRadius: 30, offset: const Offset(0, 15), spreadRadius: 5, ), BoxShadow( color: colorScheme.secondary.withOpacity(0.2), blurRadius: 50, offset: const Offset(0, 25), spreadRadius: 10, ), ], ), child: Center( child: Icon( Icons.security, size: UIConstants.getResponsiveValue( context, mobile: UIConstants.iconSizeLarge, tablet: UIConstants.iconSizeXLarge, desktop: UIConstants.iconSizeXLarge, ), color: colorScheme.onSurface, ), ), ), ), ); }, ); } Widget _buildWelcomeSection(ColorScheme colorScheme) { return AnimatedBuilder( animation: _pageAnimationController, builder: (context, child) { return FadeTransition( opacity: _pageFadeAnimation, child: SlideTransition( position: _pageSlideAnimation, child: Container( padding: UIConstants.cardPaddingMedium, decoration: BoxDecoration( color: Colors.white.withOpacity(0.95), borderRadius: BorderRadius.circular(UIConstants.radius20), border: Border.all( color: Colors.white.withOpacity(0.3), width: 1, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 20, offset: const Offset(0, 10), spreadRadius: 5, ), ], ), child: Column( children: [ Text( 'Welcome Back!', style: Theme.of(context).textTheme.headlineMedium?.copyWith( color: colorScheme.primary, fontWeight: FontWeight.w700, letterSpacing: 0.5, ), textAlign: TextAlign.center, ), const SizedBox(height: UIConstants.spacing12), Text( 'Sign in to continue to your account', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: colorScheme.onSurface.withOpacity(0.8), fontWeight: FontWeight.w400, ), textAlign: TextAlign.center, ), ], ), ), ), ); }, ); } Widget _buildLoginForm(ColorScheme colorScheme) { return AnimatedBuilder( animation: _formAnimationController, builder: (context, child) { return Transform.scale( scale: _formScaleAnimation.value, child: Container( width: UIConstants.getResponsiveValue( context, mobile: double.infinity, tablet: 450, desktop: 500, ), padding: UIConstants.cardPaddingLarge, decoration: BoxDecoration( color: Colors.white.withOpacity(0.95), borderRadius: BorderRadius.circular(UIConstants.radius24), border: Border.all( color: Colors.white.withOpacity(0.3), width: 1, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.15), blurRadius: 25, offset: const Offset(0, 15), spreadRadius: 8, ), ], ), child: Column( children: [ // Email Field _buildEnhancedTextField( label: 'Email Address', hint: 'Enter your email', controller: _emailController, focusNode: _emailFocusNode, keyboardType: TextInputType.emailAddress, prefixIcon: Icons.email_outlined, isFocused: _isEmailFocused, colorScheme: colorScheme, textInputAction: TextInputAction.next, onSubmitted: (_) => _passwordFocusNode.requestFocus(), validator: (value) { if (value == null || value.isEmpty) { return 'Email is required'; } if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$') .hasMatch(value)) { return 'Please enter a valid email'; } return null; }, ), const SizedBox(height: UIConstants.spacing24), // Password Field _buildEnhancedTextField( label: 'Password', hint: 'Enter your password', controller: _passwordController, focusNode: _passwordFocusNode, obscureText: !_isPasswordVisible, prefixIcon: Icons.lock_outlined, isFocused: _isPasswordFocused, colorScheme: colorScheme, suffixIcon: IconButton( icon: Icon( _isPasswordVisible ? Icons.visibility : Icons.visibility_off, color: colorScheme.onSurface.withOpacity(0.6), ), onPressed: () { setState(() { _isPasswordVisible = !_isPasswordVisible; }); }, ), textInputAction: TextInputAction.done, validator: (value) { if (value == null || value.isEmpty) { return 'Password is required'; } if (value.length < 6) { return 'Password must be at least 6 characters'; } return null; }, ), const SizedBox(height: UIConstants.spacing16), // Forgot Password - Now below password field _buildForgotPasswordSection(colorScheme), ], ), ), ); }, ); } Widget _buildEnhancedTextField({ required String label, required String hint, required TextEditingController controller, required FocusNode focusNode, required IconData prefixIcon, required bool isFocused, required ColorScheme colorScheme, bool obscureText = false, Widget? suffixIcon, TextInputType? keyboardType, TextInputAction? textInputAction, Function(String)? onSubmitted, String? Function(String?)? validator, }) { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(UIConstants.radius16), border: Border.all( color: isFocused ? colorScheme.primary : Colors.grey.withOpacity(0.3), width: isFocused ? 2 : 1, ), boxShadow: isFocused ? [ BoxShadow( color: colorScheme.primary.withOpacity(0.2), blurRadius: 12, spreadRadius: 3, ), ] : null, ), child: ModernTextField( label: label, hint: hint, controller: controller, focusNode: focusNode, obscureText: obscureText, keyboardType: keyboardType, prefixIcon: Icon( prefixIcon, color: isFocused ? colorScheme.primary : Colors.grey.withOpacity(0.7), ), suffixIcon: suffixIcon, textInputAction: textInputAction, onSubmitted: onSubmitted, validator: validator, ), ); } Widget _buildForgotPasswordSection(ColorScheme colorScheme) { return AnimatedBuilder( animation: _formAnimationController, builder: (context, child) { return FadeTransition( opacity: _formScaleAnimation, child: Align( alignment: Alignment.centerLeft, child: Container( padding: const EdgeInsets.symmetric( horizontal: UIConstants.spacing12, vertical: UIConstants.spacing6, ), decoration: BoxDecoration( color: Colors.white.withOpacity(0.9), borderRadius: BorderRadius.circular(UIConstants.radius12), border: Border.all( color: colorScheme.primary.withOpacity(0.3), width: 1, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.08), blurRadius: 6, offset: const Offset(0, 2), spreadRadius: 1, ), ], ), child: TextButton( onPressed: () { // Handle forgot password action }, style: TextButton.styleFrom( padding: EdgeInsets.zero, minimumSize: Size.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.help_outline, color: colorScheme.primary, size: UIConstants.iconSizeSmall, ), const SizedBox(width: UIConstants.spacing6), Text( 'Forgot Password?', style: Theme.of(context).textTheme.labelSmall?.copyWith( color: colorScheme.primary, fontWeight: FontWeight.w600, fontSize: 12, ), ), ], ), ), ), ), ); }, ); } Widget _buildLoginButton(ColorScheme colorScheme) { return AnimatedBuilder( animation: _formAnimationController, builder: (context, child) { return Transform.scale( scale: _formScaleAnimation.value, child: Container( width: UIConstants.getResponsiveValue( context, mobile: double.infinity, tablet: 450, desktop: 500, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(UIConstants.radius20), boxShadow: [ BoxShadow( color: colorScheme.primary.withOpacity(0.3), blurRadius: 20, offset: const Offset(0, 10), spreadRadius: 5, ), ], ), child: Consumer( builder: (context, provider, child) { return ModernButton( text: 'Sign In', type: ModernButtonType.primary, size: ModernButtonSize.large, isLoading: provider.isLoading, isDisabled: !_isFormValid, onPressed: _isFormValid ? () { final data = { "email": _emailController.text, "password": _passwordController.text, }; provider.login(context, data); } : null, icon: Icon(Icons.login), ); }, ), ), ); }, ); } Widget _buildSignUpSection(ColorScheme colorScheme) { return AnimatedBuilder( animation: _formAnimationController, builder: (context, child) { return FadeTransition( opacity: _formScaleAnimation, child: Container( padding: UIConstants.cardPaddingMedium, decoration: BoxDecoration( color: Colors.white.withOpacity(0.9), borderRadius: BorderRadius.circular(UIConstants.radius20), border: Border.all( color: Colors.white.withOpacity(0.3), width: 1, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 15, offset: const Offset(0, 8), spreadRadius: 3, ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Don't have an account? ", style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Colors.grey.shade700, fontWeight: FontWeight.w500, ), ), TextButton( onPressed: () { Navigator.pushNamed(context, RouteNames.getOtpView); }, child: Text( 'Sign Up', style: Theme.of(context).textTheme.labelLarge?.copyWith( color: colorScheme.primary, fontWeight: FontWeight.w700, fontSize: 16, ), ), ), ], ), ), ); }, ); } Widget _buildSocialLoginSection(ColorScheme colorScheme) { return AnimatedBuilder( animation: _formAnimationController, builder: (context, child) { return FadeTransition( opacity: _formScaleAnimation, child: Column( children: [ Row( children: [ Expanded( child: Container( height: 1, color: Colors.white.withOpacity(0.4), ), ), Padding( padding: const EdgeInsets.symmetric( horizontal: UIConstants.spacing16), child: Text( 'Or continue with', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Colors.white.withOpacity(0.9), fontWeight: FontWeight.w500, ), ), ), Expanded( child: Container( height: 1, color: Colors.white.withOpacity(0.4), ), ), ], ), const SizedBox(height: UIConstants.spacing24), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ _buildSocialButton( icon: Icons.g_mobiledata, label: 'Google', colorScheme: colorScheme, onPressed: () { // Handle Google sign in }, ), const SizedBox(width: UIConstants.spacing16), _buildSocialButton( icon: Icons.apple, label: 'Apple', colorScheme: colorScheme, onPressed: () { // Handle Apple sign in }, ), ], ), ], ), ); }, ); } Widget _buildSocialButton({ required IconData icon, required String label, required ColorScheme colorScheme, required VoidCallback onPressed, }) { return Container( decoration: BoxDecoration( color: Colors.white.withOpacity(0.95), borderRadius: BorderRadius.circular(UIConstants.radius16), border: Border.all( color: Colors.white.withOpacity(0.3), width: 1, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 5), spreadRadius: 2, ), ], ), child: Material( color: Colors.transparent, child: InkWell( onTap: onPressed, borderRadius: BorderRadius.circular(UIConstants.radius16), child: Padding( padding: const EdgeInsets.symmetric( horizontal: UIConstants.spacing20, vertical: UIConstants.spacing12, ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( icon, size: UIConstants.iconSizeMedium, color: colorScheme.primary, ), const SizedBox(width: UIConstants.spacing8), Text( label, style: Theme.of(context).textTheme.labelMedium?.copyWith( color: colorScheme.primary, fontWeight: FontWeight.w600, ), ), ], ), ), ), ), ); } } class ParticlePainter extends CustomPainter { final double rotation; final Color color; ParticlePainter({required this.rotation, required this.color}); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = color ..style = PaintingStyle.fill; final center = Offset(size.width / 2, size.height / 2); final radius = math.min(size.width, size.height) / 2.5; // Draw rotating particles for (int i = 0; i < 12; i++) { final angle = (i * math.pi / 6) + rotation; final x = center.dx + radius * math.cos(angle); final y = center.dy + radius * math.sin(angle); canvas.drawCircle( Offset(x, y), 4, paint, ); } } @override bool shouldRepaint(ParticlePainter oldDelegate) => true; }