import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:get/get.dart'; import 'package:marco/controller/auth/forgot_password_controller.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:marco/helpers/widgets/my_button.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/images.dart'; class ForgotPasswordScreen extends StatefulWidget { const ForgotPasswordScreen({super.key}); @override State createState() => _ForgotPasswordScreenState(); } class _ForgotPasswordScreenState extends State with UIMixin, SingleTickerProviderStateMixin { final ForgotPasswordController controller = Get.put(ForgotPasswordController()); late final AnimationController _controller; late final Animation _logoAnimation; final bool _isBetaEnvironment = ApiEndpoints.baseUrl.contains("stage"); bool _isLoading = false; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 800), ); _logoAnimation = CurvedAnimation( parent: _controller, curve: Curves.easeOutBack, ); _controller.forward(); } @override void dispose() { _controller.dispose(); Get.delete(); super.dispose(); } Future _handleForgotPassword() async { setState(() => _isLoading = true); await controller.onForgotPassword(); setState(() => _isLoading = false); } @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ _RedWaveBackground(brandRed: contentTheme.brandRed), SafeArea( child: Center( child: Column( children: [ const SizedBox(height: 24), _buildAnimatedLogo(), const SizedBox(height: 8), Expanded( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 420), child: Column( children: [ const SizedBox(height: 12), _buildWelcomeText(), if (_isBetaEnvironment) ...[ const SizedBox(height: 12), _buildBetaBadge(), ], const SizedBox(height: 36), _buildForgotCard(), ], ), ), ), ), ], ), ), ), ], ), ); } Widget _buildAnimatedLogo() { return ScaleTransition( scale: _logoAnimation, child: Container( width: 100, height: 100, padding: const EdgeInsets.all(20), decoration: const BoxDecoration( color: Colors.white, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black12, blurRadius: 10, offset: Offset(0, 4), ), ], ), child: Image.asset(Images.logoDark), ), ); } Widget _buildWelcomeText() { return Column( children: [ MyText( "Welcome to Marco", fontSize: 24, fontWeight: 600, color: Colors.black87, textAlign: TextAlign.center, ), const SizedBox(height: 10), MyText( "Streamline Project Management\nBoost Productivity with Automation.", fontSize: 14, color: Colors.black54, textAlign: TextAlign.center, ), ], ); } Widget _buildBetaBadge() { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: Colors.orangeAccent, borderRadius: BorderRadius.circular(6), ), child: MyText( 'BETA', color: Colors.white, fontWeight: 600, fontSize: 12, ), ); } Widget _buildForgotCard() { return Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: const [ BoxShadow( color: Colors.black12, blurRadius: 10, offset: Offset(0, 4), ), ], ), child: Form( key: controller.basicValidator.formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ MyText( 'Forgot Password', fontSize: 20, fontWeight: 600, color: Colors.black87, textAlign: TextAlign.center, ), const SizedBox(height: 10), MyText( "Enter your email and we'll send you instructions to reset your password.", fontSize: 14, color: Colors.black54, textAlign: TextAlign.center, ), const SizedBox(height: 30), _buildEmailInput(), const SizedBox(height: 32), _buildResetButton(), const SizedBox(height: 20), _buildBackButton(), ], ), ), ); } Widget _buildEmailInput() { return TextFormField( validator: controller.basicValidator.getValidation('email'), controller: controller.basicValidator.getController('email'), keyboardType: TextInputType.emailAddress, style: const TextStyle(fontSize: 14), decoration: InputDecoration( labelText: "Email Address", labelStyle: const TextStyle(color: Colors.black54), filled: true, fillColor: Colors.grey.shade100, prefixIcon: const Icon(LucideIcons.mail, size: 20), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), ), ); } Widget _buildResetButton() { return MyButton.rounded( onPressed: _isLoading ? null : _handleForgotPassword, elevation: 2, padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 16), borderRadiusAll: 10, backgroundColor: _isLoading ? contentTheme.brandRed.withOpacity(0.6) : contentTheme.brandRed, child: _isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : MyText.bodyMedium( 'Send Reset Link', color: Colors.white, fontWeight: 600, fontSize: 16, ), ); } Widget _buildBackButton() { return TextButton.icon( onPressed: () async => await LocalStorage.logout(), icon: const Icon(Icons.arrow_back, size: 18, color: Colors.redAccent), label: MyText.bodyMedium( 'Back to Login', color: contentTheme.brandRed, fontWeight: 600, fontSize: 14, ), ); } } class _RedWaveBackground extends StatelessWidget { final Color brandRed; const _RedWaveBackground({required this.brandRed}); @override Widget build(BuildContext context) { return CustomPaint( painter: _WavePainter(brandRed), size: Size.infinite, ); } } class _WavePainter extends CustomPainter { final Color brandRed; _WavePainter(this.brandRed); @override void paint(Canvas canvas, Size size) { final paint1 = Paint() ..shader = LinearGradient( colors: [brandRed, const Color.fromARGB(255, 97, 22, 22)], begin: Alignment.topLeft, end: Alignment.bottomRight, ).createShader(Rect.fromLTWH(0, 0, size.width, size.height)); final path1 = Path() ..moveTo(0, size.height * 0.2) ..quadraticBezierTo(size.width * 0.25, size.height * 0.05, size.width * 0.5, size.height * 0.15) ..quadraticBezierTo( size.width * 0.75, size.height * 0.25, size.width, size.height * 0.1) ..lineTo(size.width, 0) ..lineTo(0, 0) ..close(); canvas.drawPath(path1, paint1); final paint2 = Paint()..color = Colors.redAccent.withOpacity(0.15); final path2 = Path() ..moveTo(0, size.height * 0.25) ..quadraticBezierTo( size.width * 0.4, size.height * 0.1, size.width, size.height * 0.2) ..lineTo(size.width, 0) ..lineTo(0, 0) ..close(); canvas.drawPath(path2, paint2); } @override bool shouldRepaint(CustomPainter oldDelegate) => false; }