import 'package:cb_prestige_qr/core/utils/MainShell.dart'; import 'package:flutter/material.dart'; import 'package:local_auth/local_auth.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State createState() => _LoginPageState(); } enum _SupportState { unknown, supported, unsupported } class _LoginPageState extends State { final _formKey = GlobalKey(); final _usernameController = TextEditingController(); final _passwordController = TextEditingController(); final LocalAuthentication auth = LocalAuthentication(); bool? _canCheckBiometric; List? _availableBiometrics; String _authorized = "Not Authorized"; bool _isAuthenticating = false; bool _isSigningIn = false; _SupportState _supportState = _SupportState.unknown; var _obscurePassword = true; @override void initState(){ super.initState(); auth.isDeviceSupported().then( (bool isSupported) => setState( () => _supportState = isSupported ? _SupportState.supported : _SupportState.unsupported, ), ); } @override void dispose() { _usernameController.dispose(); _passwordController.dispose(); super.dispose(); } Future _submit() async { final form = _formKey.currentState; if (form == null || !form.validate()) return; setState(() { _isSigningIn = true; }); await Future.delayed(const Duration(seconds: 2)); if (!mounted) return; Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (_) => const MainShell()), ); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; return Scaffold( body: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xff17181c), Color(0xff25262b), Color(0xff2c2d33), ], ), ), child: SafeArea( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 440), child: Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: const Color(0xff1d1e23).withOpacity(0.92), borderRadius: BorderRadius.circular(28), border: Border.all(color: Colors.white.withOpacity(0.08)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.28), blurRadius: 28, offset: const Offset(0, 18), ), ], ), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Row( children: [ Container( height: 56, width: 56, decoration: BoxDecoration( color: colorScheme.primary.withOpacity(0.16), borderRadius: BorderRadius.circular(18), ), child: const Icon( Icons.lock_person_rounded, color: Colors.white, size: 30, ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Secure Login', style: theme.textTheme.headlineSmall ?.copyWith( fontWeight: FontWeight.w700, color: Colors.white, ), ), const SizedBox(height: 4), Text( 'Use your username and password to continue.', style: theme.textTheme.bodyMedium?.copyWith( color: Colors.white70, height: 1.35, ), ), ], ), ), ], ), const SizedBox(height: 28), Container( width: double.infinity, padding: const EdgeInsets.all(18), decoration: BoxDecoration( color: Colors.white.withOpacity(0.04), borderRadius: BorderRadius.circular(20), border: Border.all( color: Colors.white.withOpacity(0.06), ), ), child: Row( children: [ ClipRRect( borderRadius: BorderRadius.circular(14), child: Image.asset( 'assets/images/logo_white.png', height: 48, width: 48, fit: BoxFit.cover, ), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'CB Prestige Banking', style: theme.textTheme.titleMedium ?.copyWith( color: Colors.white, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 2), Text( 'Sign in to access your QR dashboard.', style: theme.textTheme.bodySmall ?.copyWith(color: Colors.white60), ), ], ), ), ], ), ), const SizedBox(height: 28), _AuthTextField( controller: _usernameController, label: 'Username', hintText: 'Enter your username', keyboardType: TextInputType.text, prefixIcon: Icons.person_rounded, validator: (value) { final username = value?.trim() ?? ''; if (username.isEmpty) { return 'Username is required'; } if (username.length < 3) { return 'Username must be at least 3 characters'; } return null; }, ), const SizedBox(height: 16), _AuthTextField( controller: _passwordController, label: 'Password', hintText: 'Enter your password', prefixIcon: Icons.lock_rounded, obscureText: _obscurePassword, validator: (value) { final password = value ?? ''; if (password.isEmpty) { return 'Password is required'; } if (password.length < 6) { return 'Password must be at least 6 characters'; } return null; }, suffixIcon: IconButton( onPressed: () { setState(() { _obscurePassword = !_obscurePassword; }); }, icon: Icon( _obscurePassword ? Icons.visibility_off_rounded : Icons.visibility_rounded, color: Colors.white70, ), ), ), const SizedBox(height: 12), Align( alignment: Alignment.centerRight, child: TextButton( onPressed: () {}, child: const Text('Forgot password?'), ), ), const SizedBox(height: 24), SizedBox( width: double.infinity, child: FilledButton( onPressed: _isSigningIn ? null : _submit, style: FilledButton.styleFrom( backgroundColor: colorScheme.primary, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(18), ), ), child: _isSigningIn ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( strokeWidth: 2.4, valueColor: AlwaysStoppedAnimation( Colors.white, ), ), ) : const Text( 'Sign In', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ), ), ], ), ), ), ), ), ), ), ), ); } } class _AuthTextField extends StatelessWidget { const _AuthTextField({ required this.controller, required this.label, required this.hintText, required this.prefixIcon, required this.validator, this.keyboardType, this.obscureText = false, this.suffixIcon, }); final TextEditingController controller; final String label; final String hintText; final IconData prefixIcon; final String? Function(String?) validator; final TextInputType? keyboardType; final bool obscureText; final Widget? suffixIcon; @override Widget build(BuildContext context) { return TextFormField( controller: controller, keyboardType: keyboardType, obscureText: obscureText, validator: validator, style: const TextStyle(color: Colors.white), decoration: InputDecoration( labelText: label, hintText: hintText, prefixIcon: Icon(prefixIcon), suffixIcon: suffixIcon, ), ); } }