import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter/services.dart'; import '../../core/theme/theme_provider.dart'; import 'dart:convert'; import 'package:crypto/crypto.dart'; import 'package:http/http.dart' as http; import '../../core/constants/app_constants.dart'; import '../../core/theme/app_theme.dart'; import '../../services/wallet_identity_service.dart'; import '../garage/weapon_list_screen.dart'; class SettingsScreen extends StatefulWidget { const SettingsScreen({super.key}); @override State createState() => _SettingsScreenState(); } class _SettingsScreenState extends State { final WalletIdentityService _walletService = WalletIdentityService(); String? _identityPhrase; int? _photoCount; bool _isLoadingStats = false; bool _isUploadEnabled = false; @override void initState() { super.initState(); _loadIdentity(); } Future _loadIdentity() async { final phrase = await _walletService.getIdentityPhrase(); final isEnabled = await _walletService.isUploadEnabled(); if (mounted) { setState(() { _identityPhrase = phrase; _isUploadEnabled = isEnabled; }); _fetchStats(phrase); } } Future _fetchStats(String phrase) async { setState(() => _isLoadingStats = true); try { final phraseBytes = utf8.encode(phrase); final walletHash = sha256.convert(phraseBytes).toString(); // Utilise 10.0.2.2 pour l'émulateur Android, sinon localhost final baseUrl = Theme.of(context).platform == TargetPlatform.android ? 'http://10.0.2.2:3000' : 'http://localhost:3000'; final response = await http.get(Uri.parse('$baseUrl/api/stats/$walletHash')); if (response.statusCode == 200) { final data = jsonDecode(response.body); if (mounted) { setState(() { _photoCount = data['stats']['photo_count'] ?? 0; _isLoadingStats = false; }); } } else { if (mounted) setState(() => _isLoadingStats = false); } } catch (e) { print('Erreur lors du chargement des statistiques: $e'); if (mounted) setState(() => _isLoadingStats = false); } } void _copyToClipboard() { if (_identityPhrase != null) { Clipboard.setData(ClipboardData(text: _identityPhrase!)); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Identité copiée dans le presse-papiers'), backgroundColor: AppTheme.successColor, ), ); } } void _showThemeDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Apparence'), content: Column( mainAxisSize: MainAxisSize.min, children: [ _buildThemeOption(ThemeMode.system, 'Automatique', Icons.brightness_auto), _buildThemeOption(ThemeMode.light, 'Clair', Icons.light_mode), _buildThemeOption(ThemeMode.dark, 'Sombre', Icons.dark_mode), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Fermer'), ), ], ), ); } Widget _buildThemeOption(ThemeMode mode, String label, IconData icon) { final themeProvider = context.watch(); final isSelected = themeProvider.themeMode == mode; return ListTile( leading: Icon(icon, color: isSelected ? AppTheme.primaryColor : null), title: Text(label, style: TextStyle( fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, color: isSelected ? AppTheme.primaryColor : null, )), trailing: isSelected ? const Icon(Icons.check, color: AppTheme.primaryColor) : null, onTap: () { themeProvider.setThemeMode(mode); Navigator.pop(context); }, ); } void _showIdentityDialog() { if (_identityPhrase == null) return; showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Votre Identité Unique', textAlign: TextAlign.center), content: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.security, size: 48, color: AppTheme.primaryColor), const SizedBox(height: 16), const Text( 'Cette phrase de 15 mots vous identifie de manière unique. Ne la partagez qu\'en cas de besoin.', textAlign: TextAlign.center, style: TextStyle(fontSize: 14, color: Colors.grey), ), const SizedBox(height: 24), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey.withAlpha(20), borderRadius: BorderRadius.circular(8), border: Border.all(color: AppTheme.primaryColor.withAlpha(100)), ), child: Text( _identityPhrase!, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, letterSpacing: 0.5, height: 1.5, ), textAlign: TextAlign.center, ), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Fermer'), ), ElevatedButton.icon( icon: const Icon(Icons.copy, size: 18), label: const Text('Copier'), onPressed: () { _copyToClipboard(); Navigator.pop(context); }, ), ], ), ); } void _showOptInDisclaimer(bool value) { if (!value) { // Si on désactive, pas besoin de disclaimer, on le fait direct. _walletService.setUploadEnabled(false); setState(() { _isUploadEnabled = false; }); return; } showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( title: const Text('Participer à l\'entraînement IA', textAlign: TextAlign.center), content: const Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.psychology, size: 48, color: AppTheme.primaryColor), SizedBox(height: 16), Text( 'En activant cette option, vous acceptez d\'envoyer vos photos de cibles à notre serveur sécurisé.', style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), SizedBox(height: 12), Text( '🔒 Anonymat Garanti : L\'envoi est totalement anonymisé. Votre identité est remplacée par un hash cryptographique incassable.', style: TextStyle(fontSize: 13), ), SizedBox(height: 12), Text( '🎁 Avantages Futurs : Votre contribution (Hash de Wallet) sera comptabilisée. Lors de la sortie publique de notre IA, les participants actifs recevront des fonctionnalités premium ou des badges exclusifs en récompense !', style: TextStyle(fontSize: 13), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Refuser', style: TextStyle(color: Colors.grey)), ), ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: AppTheme.primaryColor), onPressed: () { _walletService.setUploadEnabled(true); setState(() { _isUploadEnabled = true; }); Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Merci pour votre contribution !'), backgroundColor: AppTheme.successColor, ), ); }, child: const Text('J\'accepte', style: TextStyle(color: Colors.white)), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Paramètres'), ), body: ListView( padding: const EdgeInsets.all(AppConstants.defaultPadding), children: [ _buildSectionHeader('Identité'), _buildSettingsTile( context: context, icon: Icons.fingerprint, title: 'Identité Wallet', subtitle: _identityPhrase != null ? 'Phrase de 15 mots générée' : 'Génération en cours...', onTap: _showIdentityDialog, ), Consumer( builder: (context, themeProvider, child) { return _buildSettingsTile( context: context, icon: Icons.color_lens_outlined, title: 'Apparence', subtitle: themeProvider.themeModeName, onTap: _showThemeDialog, ); }, ), const SizedBox(height: 24), _buildSectionHeader('Gestion'), _buildSettingsTile( context: context, icon: Icons.shield_outlined, title: 'Mon Armurerie', subtitle: 'Gérer mes armes et équipements', onTap: () async { await Navigator.push( context, MaterialPageRoute(builder: (_) => const WeaponListScreen()), ); }, ), const SizedBox(height: 24), _buildSectionHeader('Configuration Serveur IA'), Card( elevation: 0, color: Colors.transparent, margin: const EdgeInsets.only(bottom: 8.0), child: SwitchListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0), title: const Text('Participer à l\'entraînement IA', style: TextStyle(fontWeight: FontWeight.w500)), subtitle: const Text('Aidez-nous à améliorer la détection tout en gagnant des avantages', style: TextStyle(fontSize: 12)), secondary: const Icon(Icons.psychology, color: AppTheme.textPrimary), value: _isUploadEnabled, activeColor: AppTheme.primaryColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), side: BorderSide(color: Colors.grey.withAlpha(50), width: 1), ), onChanged: _showOptInDisclaimer, ), ), if (_isUploadEnabled) _buildSettingsTile( context: context, icon: Icons.cloud_outlined, title: 'Adresse du Serveur IA', subtitle: 'http://localhost:3000/api/upload', onTap: () { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Changement d\'adresse à venir')), ); }, ), if (_isUploadEnabled) _buildSettingsTile( context: context, icon: Icons.data_usage, title: 'Photos Exportées', subtitle: _isLoadingStats ? 'Chargement...' : (_photoCount != null ? '$_photoCount photos envoyées à l\'IA' : 'Non disponible'), onTap: () { if (_identityPhrase != null) { _fetchStats(_identityPhrase!); } }, ), const SizedBox(height: 24), _buildSectionHeader('À propos'), _buildSettingsTile( context: context, icon: Icons.info_outline, title: 'Version de l\'application', subtitle: '1.0.0', onTap: () {}, ), _buildSettingsTile( context: context, icon: Icons.privacy_tip_outlined, title: 'Politique de confidentialité', onTap: () {}, ), ], ), ); } Widget _buildSectionHeader(String title) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0), child: Text( title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: AppTheme.primaryColor, ), ), ); } Widget _buildSettingsTile({ required BuildContext context, required IconData icon, required String title, String? subtitle, required VoidCallback onTap, }) { return Card( elevation: 0, color: Colors.transparent, margin: const EdgeInsets.only(bottom: 8.0), child: ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0), leading: Icon(icon, color: AppTheme.textPrimary), title: Text(title, style: const TextStyle(fontWeight: FontWeight.w500)), subtitle: subtitle != null ? Text(subtitle, style: const TextStyle(fontSize: 12)) : null, trailing: const Icon(Icons.chevron_right, color: Colors.grey), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), side: BorderSide(color: Colors.grey.withAlpha(50), width: 1), ), onTap: onTap, ), ); } }