import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/widgets/app_scaffold.dart'; import '../../../data/services/biometric_service.dart'; import '../../auth/application/auth_controller.dart'; import 'package:local_auth/local_auth.dart' as local_auth; class BiometricSettingsScreen extends ConsumerStatefulWidget { const BiometricSettingsScreen({super.key}); @override ConsumerState createState() => _BiometricSettingsScreenState(); } class _BiometricSettingsScreenState extends ConsumerState { final BiometricService _biometricService = BiometricService(); bool _isLoading = false; BiometricAvailability? _availability; bool _isEnabled = false; String _statusMessage = ''; List _availableBiometrics = []; local_auth.BiometricType? _primaryBiometricType; @override void initState() { super.initState(); _loadBiometricStatus(); } Future _loadBiometricStatus() async { setState(() => _isLoading = true); try { final availability = await _biometricService.checkAvailability(); final isEnabled = await _biometricService.isBiometricEnabled(); final statusMessage = await _biometricService.getBiometricStatusMessage(); final availableBiometrics = await _biometricService.getAvailableBiometrics(); final primaryBiometricType = await _biometricService.getPrimaryBiometricType(); setState(() { _availability = availability; _isEnabled = isEnabled; _statusMessage = statusMessage; _availableBiometrics = availableBiometrics; _primaryBiometricType = primaryBiometricType; _isLoading = false; }); } catch (e) { setState(() => _isLoading = false); } } Future _toggleBiometric() async { if (_availability != BiometricAvailability.available) { return; } setState(() => _isLoading = true); try { final authController = ref.read(authControllerProvider.notifier); if (_isEnabled) { // Disable biometric final success = await authController.disableBiometric(); if (success) { setState(() => _isEnabled = false); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Biometric login disabled')), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Failed to disable biometric login')), ); } } else { // Enable biometric final success = await authController.enableBiometric(); if (success) { setState(() => _isEnabled = true); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Biometric login enabled successfully')), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Failed to enable biometric login')), ); } } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error: ${e.toString()}')), ); } finally { setState(() => _isLoading = false); } } Future _testBiometric() async { if (!_isEnabled) return; setState(() => _isLoading = true); try { final authController = ref.read(authControllerProvider.notifier); final success = await authController.signInWithBiometric(); if (success) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Biometric login successful')), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Biometric login failed')), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error: ${e.toString()}')), ); } finally { setState(() => _isLoading = false); } } String _getBiometricTypeEmoji(local_auth.BiometricType type) { switch (type) { case local_auth.BiometricType.fingerprint: return '👆'; case local_auth.BiometricType.face: return '👤'; case local_auth.BiometricType.iris: return '👁️'; default: return '🔒'; } } String _getBiometricTypeName(local_auth.BiometricType type) { switch (type) { case local_auth.BiometricType.fingerprint: return 'Fingerprint'; case local_auth.BiometricType.face: return 'Face ID'; case local_auth.BiometricType.iris: return 'Iris Scanner'; default: return 'Biometric'; } } Color _getStatusColor() { switch (_availability) { case BiometricAvailability.available: return _isEnabled ? Colors.green : Colors.orange; case BiometricAvailability.notAvailable: return Colors.grey; case BiometricAvailability.notEnrolled: return Colors.orange; case BiometricAvailability.lockedOut: return Colors.red; case BiometricAvailability.permanentlyUnavailable: return Colors.red; case null: return Colors.grey; } } @override Widget build(BuildContext context) { return AppScaffold( title: 'Biometric Login', body: _isLoading ? const Center(child: CircularProgressIndicator()) : ListView( padding: const EdgeInsets.all(16), children: [ // Status Card Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( _primaryBiometricType != null ? Icons.fingerprint : Icons.lock, size: 32, color: _getStatusColor(), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Biometric Status', style: Theme.of(context).textTheme.titleMedium, ), Text( _statusMessage, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: _getStatusColor(), ), ), ], ), ), ], ), const SizedBox(height: 16), if (_availability == BiometricAvailability.available) SwitchListTile( title: const Text('Enable Biometric Login'), subtitle: const Text('Use fingerprint or face ID for quick access'), value: _isEnabled, onChanged: (value) => _toggleBiometric(), secondary: Icon( _isEnabled ? Icons.lock_open : Icons.lock, color: _getStatusColor(), ), ), ], ), ), ), const SizedBox(height: 16), // Available Biometrics if (_availableBiometrics.isNotEmpty) Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Available Biometrics', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 12), ..._availableBiometrics.map((type) => Padding( padding: const EdgeInsets.only(bottom: 8), child: Row( children: [ Text( _getBiometricTypeEmoji(type), style: const TextStyle(fontSize: 24), ), const SizedBox(width: 12), Text( _getBiometricTypeName(type), style: Theme.of(context).textTheme.bodyLarge, ), const Spacer(), if (type == _primaryBiometricType) Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: Theme.of(context).colorScheme.primary, borderRadius: BorderRadius.circular(12), ), child: Text( 'Primary', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onPrimary, ), ), ), ], ), )), ], ), ), ), const SizedBox(height: 16), // Test Biometric (if enabled) if (_isEnabled) Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Test Biometric Login', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 8), Text( 'Test your biometric authentication to make sure it\'s working properly.', style: Theme.of(context).textTheme.bodySmall, ), const SizedBox(height: 16), SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: _testBiometric, icon: const Icon(Icons.fingerprint), label: const Text('Test Biometric Login'), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 12), ), ), ), ], ), ), ), const SizedBox(height: 16), // Information Card Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'About Biometric Login', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 12), Text( '• Biometric login allows you to sign in quickly using your fingerprint or face ID.\n' '• Your biometric data is stored securely on your device and never sent to our servers.\n' '• You can disable biometric login at any time in these settings.\n' '• If you change your password, you may need to re-enable biometric login.', style: Theme.of(context).textTheme.bodySmall, ), ], ), ), ), ], ), ); } }