import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'dart:math' as math; import '../../../../application/auth/auth_bloc.dart'; import '../../../../application/auth/login_form/login_form_bloc.dart'; import '../../../../common/extension/extension.dart'; import '../../../../common/theme/theme.dart'; import '../../../../injection.dart'; import '../../../components/button/button.dart'; import '../../../components/spacer/spacer.dart'; import '../../../components/toast/flushbar.dart'; import '../../../router/app_router.gr.dart'; import 'widgets/email_field.dart'; import 'widgets/password_field.dart'; @RoutePage() class LoginPage extends StatelessWidget implements AutoRouteWrapper { const LoginPage({super.key}); @override Widget wrappedRoute(BuildContext context) => BlocProvider(create: (_) => getIt(), child: this); @override Widget build(BuildContext context) { return BlocListener( listenWhen: (previous, current) => previous.failureOrAuthOption != current.failureOrAuthOption, listener: (context, state) { state.failureOrAuthOption.fold( () => null, (either) => either.fold( (f) => AppFlushbar.showAuthFailureToast(context, f), (user) { if (context.mounted) { context.read().add(AuthEvent.fetchCurrentUser()); context.router.replace(const MainRoute()); } }, ), ); }, child: Scaffold( body: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: AppColor.primaryGradient, ), ), child: Stack( children: [ _buildStaticBackground(context), SafeArea( child: Center( child: SingleChildScrollView( padding: EdgeInsets.symmetric(horizontal: AppValue.padding), child: BlocBuilder( builder: (context, state) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _buildLogo(context), const SpaceHeight(48), _buildLoginCard( context, state.isSubmitting, state.showErrorMessages, ), ], ); }, ), ), ), ), ], ), ), ), ); } Widget _buildStaticBackground(BuildContext context) { final size = MediaQuery.of(context).size; return Stack( children: [ // Static circles ...List.generate(6, (index) { final double circleSize = 80 + (index * 40); final double left = (index * 60.0) % size.width; final double top = (index * 120.0) % size.height; return Positioned( left: left, top: top, child: Container( width: circleSize, height: circleSize, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.white.withOpacity(0.1), border: Border.all( color: Colors.white.withOpacity(0.2), width: 2, ), ), ), ); }), // Geometric shapes Positioned( top: 100, right: 50, child: Transform.rotate( angle: math.pi / 4, child: Container( width: 60, height: 60, decoration: BoxDecoration( color: Colors.white.withOpacity(0.08), borderRadius: BorderRadius.circular(12), border: Border.all( color: Colors.white.withOpacity(0.15), width: 1, ), ), ), ), ), Positioned( bottom: 150, left: 30, child: Container( width: 80, height: 80, decoration: BoxDecoration( color: Colors.white.withOpacity(0.06), shape: BoxShape.circle, border: Border.all( color: Colors.white.withOpacity(0.12), width: 1, ), ), ), ), // Static particles ...List.generate(8, (index) { return Positioned( left: (index * 45.0) % size.width, top: (index * 80.0) % size.height, child: Container( width: 4.0 + (index % 3) * 2, height: 4.0 + (index % 3) * 2, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.white.withOpacity(0.3), ), ), ); }), // Gradient overlay Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.transparent, Colors.black.withOpacity(0.1), Colors.transparent, ], ), ), ), ], ); } Widget _buildLogo(BuildContext context) { return Column( children: [ Text( context.lang.login_header, style: AppStyle.h1.copyWith( fontWeight: FontWeight.bold, color: AppColor.white, ), textAlign: TextAlign.center, ), const SpaceHeight(8), Text( context.lang.login_desc, style: AppStyle.lg.copyWith(color: AppColor.textLight), ), ], ); } Widget _buildLoginCard( BuildContext context, bool isLoading, bool showErrorMessages, ) { return Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 32, horizontal: 24), decoration: BoxDecoration( color: AppColor.white, borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: AppColor.black.withOpacity(0.15), blurRadius: 40, offset: const Offset(0, 20), spreadRadius: 0, ), BoxShadow( color: AppColor.black.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 5), spreadRadius: 0, ), ], ), child: Form( autovalidateMode: showErrorMessages ? AutovalidateMode.always : AutovalidateMode.disabled, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ LoginEmailField(), const SpaceHeight(24), LoginPasswordField(), const SpaceHeight(16), _buildForgetPassword(context), const SpaceHeight(32), _buildLoginButton(context, isLoading), ], ), ), ); } Widget _buildForgetPassword(BuildContext context) { return Align( alignment: Alignment.centerRight, child: GestureDetector( onTap: () {}, child: Text( '${context.lang.forgot_password}?', style: AppStyle.md.copyWith( color: AppColor.primary, fontWeight: FontWeight.w600, ), ), ), ); } Widget _buildLoginButton(BuildContext context, bool isLoading) { return AppElevatedButton( text: context.lang.sign_in, isLoading: isLoading, onPressed: () { context.read().add(LoginFormEvent.submitted()); }, ); } }