import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/images.dart'; import 'package:marco/view/auth/email_login_form.dart'; import 'package:marco/view/auth/otp_login_form.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; import 'package:marco/view/auth/request_demo_bottom_sheet.dart'; enum LoginOption { email, otp } class LoginOptionScreen extends StatelessWidget { const LoginOptionScreen({super.key}); @override Widget build(BuildContext context) => const WelcomeScreen(); } class WelcomeScreen extends StatefulWidget { const WelcomeScreen({super.key}); @override State createState() => _WelcomeScreenState(); } class _WelcomeScreenState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _logoAnimation; bool get _isBetaEnvironment => ApiEndpoints.baseUrl.contains("stage"); @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(); super.dispose(); } void _showLoginDialog(BuildContext context, LoginOption option) { showDialog( context: context, barrierDismissible: false, // Prevent dismiss on outside tap builder: (_) => Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), insetPadding: const EdgeInsets.all(24), child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(24), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 420), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Row with title and close button Row( children: [ Expanded( child: MyText( option == LoginOption.email ? "Login with Email" : "Login with OTP", fontSize: 20, fontWeight: 700, ), ), IconButton( icon: const Icon(Icons.close), onPressed: () => Navigator.of(context).pop(), ), ], ), const SizedBox(height: 20), option == LoginOption.email ? EmailLoginForm() : const OTPLoginScreen(), ], ), ), ), ), ), ); } @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; return Scaffold( body: Stack( children: [ const _RedWaveBackground(), SafeArea( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: ConstrainedBox( constraints: BoxConstraints( maxWidth: screenWidth < 500 ? double.infinity : 420, ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ // Logo with circular background ScaleTransition( scale: _logoAnimation, child: Container( width: 100, height: 100, decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black12, blurRadius: 10, offset: Offset(0, 4), ), ], ), padding: const EdgeInsets.all(20), child: Image.asset(Images.logoDark), ), ), const SizedBox(height: 24), // Welcome Text MyText( "Welcome to Marco", fontSize: 26, fontWeight: 800, 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, ), if (_isBetaEnvironment) ...[ const SizedBox(height: 12), 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, ), ), ], const SizedBox(height: 36), _buildActionButton( context, label: "Login with Username", icon: LucideIcons.mail, option: LoginOption.email, ), const SizedBox(height: 16), _buildActionButton( context, label: "Login with OTP", icon: LucideIcons.message_square, option: LoginOption.otp, ), const SizedBox(height: 16), _buildActionButton( context, label: "Request a Demo", icon: LucideIcons.phone_call, option: null, ), const SizedBox(height: 36), MyText( 'App version 1.0.0', color: Colors.grey, fontSize: 12, ), ], ), ), ), ), ), ], ), ); } Widget _buildActionButton( BuildContext context, { required String label, required IconData icon, LoginOption? option, }) { return SizedBox( width: double.infinity, child: ElevatedButton.icon( icon: Icon(icon, size: 20, color: Colors.white), label: Padding( padding: const EdgeInsets.symmetric(vertical: 14), child: MyText( label, fontSize: 16, fontWeight: 600, color: Colors.white, ), ), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFB71C1C), // Red background foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), ), elevation: 4, shadowColor: Colors.black26, ), onPressed: () { if (option == null) { OrganizationFormBottomSheet.show(context); } else { _showLoginDialog(context, option); } }, ), ); } } /// Custom red wave background shifted lower to reduce red area at top class _RedWaveBackground extends StatelessWidget { const _RedWaveBackground(); @override Widget build(BuildContext context) { return CustomPaint( painter: _WavePainter(), size: Size.infinite, ); } } class _WavePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paint1 = Paint() ..shader = const LinearGradient( colors: [Color(0xFFB71C1C), Color(0xFFD32F2F)], 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; }