import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../../shared/design_system/unionflow_design_system.dart'; import '../../../../core/di/injection_container.dart'; import '../../../../features/authentication/presentation/bloc/auth_bloc.dart'; import '../../../../features/authentication/data/models/user_role.dart'; import '../../data/models/system_metrics_model.dart'; import '../bloc/system_settings_bloc.dart'; import '../bloc/system_settings_event.dart'; import '../bloc/system_settings_state.dart'; import '../../../backup/presentation/pages/backup_page.dart'; /// Page Paramètres Système - UnionFlow Mobile /// /// Le BlocProvider est créé ici (StatelessWidget) afin que this.context /// dans _SystemSettingsViewState soit toujours sous le provider. class SystemSettingsPage extends StatelessWidget { const SystemSettingsPage({super.key}); @override Widget build(BuildContext context) { return BlocProvider( create: (_) => sl() ..add(LoadSystemConfig()) ..add(LoadSystemMetrics()), child: const _SystemSettingsView(), ); } } class _SystemSettingsView extends StatefulWidget { const _SystemSettingsView(); @override State<_SystemSettingsView> createState() => _SystemSettingsViewState(); } class _SystemSettingsViewState extends State<_SystemSettingsView> with TickerProviderStateMixin { late TabController _tabController; // Métriques système en temps réel SystemMetricsModel? _metrics; // États des paramètres système bool _maintenanceMode = false; bool _debugMode = false; bool _analyticsEnabled = true; bool _crashReportingEnabled = true; bool _sslEnforced = true; bool _apiLoggingEnabled = false; bool _performanceMonitoring = true; bool _alertCpuHigh = true; bool _alertLowMemory = true; bool _alertDiskFull = true; bool _alertFailedConnections = false; String _selectedLogLevel = 'INFO'; String _selectedCacheStrategy = 'Intelligent'; final List _logLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR']; final List _cacheStrategies = ['Agressif', 'Intelligent', 'Conservateur', 'Désactivé']; @override void initState() { super.initState(); _tabController = TabController(length: 5, vsync: this); _loadSystemSettings(); } @override void dispose() { _tabController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, authState) { // Accès réservé aux super administrateurs (configuration système globale) if (authState is! AuthAuthenticated || authState.effectiveRole != UserRole.superAdmin) { return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: UFAppBar( title: 'Paramètres Système', moduleGradient: ModuleColors.parametresGradient, ), body: Center( child: Padding( padding: const EdgeInsets.all(SpacingTokens.xxxl), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.lock_outline, size: 64, color: (Theme.of(context).brightness == Brightness.dark ? AppColors.textSecondaryDark : AppColors.textSecondary).withOpacity(0.5), ), const SizedBox(height: SpacingTokens.xl), Text( 'Accès réservé', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Theme.of(context).brightness == Brightness.dark ? AppColors.textPrimaryDark : AppColors.textPrimary, ), textAlign: TextAlign.center, ), const SizedBox(height: SpacingTokens.md), Text( 'Les paramètres système sont réservés aux administrateurs plateforme.', style: TextStyle( fontSize: 14, color: Theme.of(context).brightness == Brightness.dark ? AppColors.textSecondaryDark : AppColors.textSecondary, ), textAlign: TextAlign.center, ), ], ), ), ), ); } return BlocConsumer( listener: (context, state) { if (state is SystemMetricsLoaded) { setState(() { _metrics = state.metrics; }); } else if (state is SystemConfigLoaded) { setState(() { _maintenanceMode = state.config.maintenanceMode ?? false; _analyticsEnabled = state.config.metricsCollectionEnabled ?? true; _crashReportingEnabled = state.config.performanceOptimizationEnabled ?? true; _sslEnforced = state.config.twoFactorAuthEnabled ?? true; _apiLoggingEnabled = state.config.detailedLoggingEnabled ?? false; _performanceMonitoring = state.config.realTimeMonitoringEnabled ?? true; _alertCpuHigh = state.config.cpuHighAlertEnabled ?? true; _alertLowMemory = state.config.memoryLowAlertEnabled ?? true; _alertDiskFull = state.config.criticalErrorAlertEnabled ?? true; _alertFailedConnections = state.config.connectionFailureAlertEnabled ?? false; if (state.config.logLevel != null) _selectedLogLevel = state.config.logLevel!; // Backup config retiré — géré dans BackupPage }); } else if (state is SystemSettingsSuccess) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.message), backgroundColor: AppColors.success, behavior: SnackBarBehavior.floating, ), ); } else if (state is SystemSettingsError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.error), backgroundColor: AppColors.error, behavior: SnackBarBehavior.floating, ), ); } }, builder: (context, state) { return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: UFAppBar( title: 'Paramètres Système', moduleGradient: ModuleColors.parametresGradient, automaticallyImplyLeading: true, actions: [ IconButton( icon: const Icon(Icons.monitor_heart, color: AppColors.onGradient), onPressed: () => _showSystemStatus(), tooltip: 'État du système', ), IconButton( icon: const Icon(Icons.download, color: AppColors.onGradient), onPressed: () => _exportSystemConfig(), tooltip: 'Exporter la configuration', ), ], ), body: SafeArea( top: false, child: Column( children: [ _buildSystemIndicators(), _buildTabBar(), Expanded( child: TabBarView( controller: _tabController, children: [ _buildGeneralTab(), _buildSecurityTab(), _buildPerformanceTab(), _buildMaintenanceTab(), _buildMonitoringTab(), ], ), ), ], ), ), ); }, ); }, ); } /// Bande d'indicateurs système (sous l'AppBar) Widget _buildSystemIndicators() { final isDark = Theme.of(context).brightness == Brightness.dark; return Container( margin: const EdgeInsets.fromLTRB(SpacingTokens.lg, SpacingTokens.md, SpacingTokens.lg, 0), padding: const EdgeInsets.symmetric(horizontal: SpacingTokens.md, vertical: SpacingTokens.md), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), border: Border.all(color: isDark ? AppColors.borderDark : AppColors.border), boxShadow: const [BoxShadow(color: AppColors.shadow, blurRadius: 8, offset: Offset(0, 2))], ), child: Row( children: [ Expanded( child: _buildSystemIndicator( 'Statut', _metrics?.systemStatus ?? (_maintenanceMode ? 'MAINTENANCE' : 'OPERATIONAL'), _maintenanceMode ? Icons.build : Icons.check_circle, _maintenanceMode ? AppColors.warning : AppColors.success, ), ), Container(width: 1, height: 40, color: isDark ? AppColors.borderDark : AppColors.border), Expanded( child: _buildSystemIndicator( 'Charge CPU', _metrics != null ? '${_metrics!.cpuUsagePercent?.toStringAsFixed(0) ?? '0'}%' : '-', Icons.memory, AppColors.info, ), ), Container(width: 1, height: 40, color: isDark ? AppColors.borderDark : AppColors.border), Expanded( child: _buildSystemIndicator( 'Utilisateurs', _metrics?.activeUsersCount?.toString() ?? '-', Icons.people, AppColors.accent, ), ), ], ), ); } /// Indicateur système — conçu pour la bande de KPIs dans le body Widget _buildSystemIndicator(String label, String value, IconData icon, Color color) { final isDark = Theme.of(context).brightness == Brightness.dark; return Column( mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.all(SpacingTokens.md), decoration: BoxDecoration( color: color.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon(icon, color: color, size: 18), ), const SizedBox(height: SpacingTokens.sm), Text( value, style: TextStyle( fontSize: 13, fontWeight: FontWeight.bold, color: isDark ? AppColors.textPrimaryDark : AppColors.textPrimary, ), ), Text( label, style: TextStyle( fontSize: 10, color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondary, ), ), ], ); } /// Barre d'onglets Widget _buildTabBar() { return Container( margin: const EdgeInsets.fromLTRB(SpacingTokens.lg, SpacingTokens.md, SpacingTokens.lg, 0), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(SpacingTokens.radiusXl), boxShadow: const [ BoxShadow( color: AppColors.shadow, blurRadius: 10, offset: Offset(0, 2), ), ], ), child: TabBar( controller: _tabController, labelColor: AppColors.primary, unselectedLabelColor: Theme.of(context).brightness == Brightness.dark ? AppColors.textSecondaryDark : AppColors.textSecondary, indicatorColor: AppColors.primary, indicatorWeight: 3, indicatorSize: TabBarIndicatorSize.tab, labelStyle: const TextStyle( fontWeight: FontWeight.w600, fontSize: 10, ), unselectedLabelStyle: const TextStyle( fontWeight: FontWeight.normal, fontSize: 10, ), tabs: const [ Tab( icon: Icon(Icons.tune, size: 16), text: 'Général', ), Tab( icon: Icon(Icons.security, size: 16), text: 'Sécurité', ), Tab( icon: Icon(Icons.speed, size: 16), text: 'Performance', ), Tab( icon: Icon(Icons.build, size: 16), text: 'Maintenance', ), Tab( icon: Icon(Icons.analytics, size: 16), text: 'Monitoring', ), ], ), ); } /// Onglet général Widget _buildGeneralTab() { return SingleChildScrollView( padding: const EdgeInsets.all(SpacingTokens.lg), child: Column( children: [ const SizedBox(height: SpacingTokens.xl), // Configuration de base _buildSettingsSection( 'Configuration de base', 'Paramètres fondamentaux du système', Icons.settings, [ _buildSwitchSetting( 'Mode maintenance', 'Désactiver l\'accès utilisateur pour maintenance', _maintenanceMode, (value) { setState(() => _maintenanceMode = value); context.read().add(UpdateSystemConfig({'maintenanceMode': value})); _showMaintenanceModeDialog(value); }, isWarning: true, ), _buildSwitchSetting( 'Mode debug', 'Activer les logs détaillés et outils de débogage', _debugMode, (value) { setState(() => _debugMode = value); context.read().add(UpdateSystemConfig({'detailedLoggingEnabled': value})); _showSuccessSnackBar('Mode debug ${value ? 'activé' : 'désactivé'}'); }, ), _buildDropdownSetting( 'Niveau de logs', 'Détail des informations enregistrées', _selectedLogLevel, _logLevels, (value) => setState(() => _selectedLogLevel = value!), ), ], ), const SizedBox(height: SpacingTokens.xl), // Gestion des données _buildSettingsSection( 'Gestion des données', 'Configuration du stockage et cache', Icons.storage, [ _buildDropdownSetting( 'Stratégie de cache', 'Politique de mise en cache des données', _selectedCacheStrategy, _cacheStrategies, (value) => setState(() => _selectedCacheStrategy = value!), ), _buildActionSetting( 'Vider le cache système', _metrics != null ? 'Supprimer tous les fichiers temporaires (${_metrics!.totalCacheSizeFormatted ?? "0 B"})' : 'Supprimer tous les fichiers temporaires', Icons.delete_sweep, AppColors.warning, () => _clearSystemCache(), ), _buildActionSetting( 'Optimiser la base de données', 'Réorganiser et compacter la base de données', Icons.tune, AppColors.primary, () => _optimizeDatabase(), ), ], ), const SizedBox(height: SpacingTokens.xl), // Configuration réseau _buildSettingsSection( 'Configuration réseau', 'Paramètres de connectivité', Icons.network_check, [ _buildInfoSetting('Serveur API', _metrics?.apiBaseUrl ?? 'Non configuré'), _buildInfoSetting('Serveur d\'authentification', _metrics?.authServerUrl ?? 'Non configuré'), _buildInfoSetting('CDN Assets', _metrics?.cdnUrl ?? 'Non configuré'), _buildActionSetting( 'Tester la connectivité', 'Vérifier la connexion aux services', Icons.network_ping, AppColors.success, () => _testConnectivity(), ), ], ), const SizedBox(height: 80), ], ), ); } /// Onglet sécurité Widget _buildSecurityTab() { return SingleChildScrollView( padding: const EdgeInsets.all(SpacingTokens.lg), child: Column( children: [ const SizedBox(height: SpacingTokens.xl), // Sécurité réseau _buildSettingsSection( 'Sécurité réseau', 'Protection des communications', Icons.security, [ _buildSwitchSetting( 'Forcer HTTPS/SSL', 'Obliger les connexions sécurisées', _sslEnforced, (value) { setState(() => _sslEnforced = value); context.read().add(UpdateSystemConfig({'twoFactorAuthEnabled': value})); _showSuccessSnackBar('SSL ${value ? 'obligatoire' : 'optionnel'}'); }, ), _buildSwitchSetting( 'Logs des API', 'Enregistrer toutes les requêtes API', _apiLoggingEnabled, (value) { setState(() => _apiLoggingEnabled = value); context.read().add(UpdateSystemConfig({'detailedLoggingEnabled': value})); _showSuccessSnackBar('Logs API ${value ? 'activés' : 'désactivés'}'); }, ), _buildActionSetting( 'Régénérer les clés API', 'Créer de nouvelles clés d\'authentification', Icons.vpn_key, AppColors.warning, () => _regenerateApiKeys(), ), ], ), const SizedBox(height: SpacingTokens.xl), // Authentification _buildSettingsSection( 'Authentification', 'Gestion des accès utilisateurs', Icons.login, [ _buildInfoSetting( 'Sessions actives', _metrics != null ? '${_metrics!.activeSessionsCount ?? 0} sessions actives' : 'Chargement...', ), _buildInfoSetting( 'Tentatives échouées', _metrics != null ? '${_metrics!.failedLoginAttempts24h ?? 0} dans les dernières 24h' : 'Chargement...', ), _buildActionSetting( 'Forcer la déconnexion globale', 'Déconnecter tous les utilisateurs', Icons.logout, AppColors.error, () => _forceGlobalLogout(), ), _buildActionSetting( 'Réinitialiser les sessions', 'Nettoyer les sessions expirées', Icons.refresh, AppColors.primary, () => _resetSessions(), ), ], ), const SizedBox(height: SpacingTokens.xl), // Audit et conformité _buildSettingsSection( 'Audit et conformité', 'Traçabilité et réglementation', Icons.fact_check, [ _buildActionSetting( 'Générer rapport d\'audit', 'Créer un rapport complet des activités', Icons.assessment, AppColors.primary, () => _generateAuditReport(), ), _buildActionSetting( 'Export RGPD', 'Exporter toutes les données utilisateurs', Icons.download, AppColors.success, () => _exportGDPRData(), ), _buildActionSetting( 'Purge des données', 'Supprimer les données expirées (RGPD)', Icons.auto_delete, AppColors.warning, () => _purgeExpiredData(), ), ], ), const SizedBox(height: 80), ], ), ); } /// Onglet performance Widget _buildPerformanceTab() { return SingleChildScrollView( padding: const EdgeInsets.all(SpacingTokens.lg), child: Column( children: [ const SizedBox(height: SpacingTokens.xl), // Monitoring système _buildSettingsSection( 'Monitoring système', 'Surveillance des performances', Icons.monitor, [ _buildSwitchSetting( 'Monitoring des performances', 'Surveiller CPU, mémoire et réseau', _performanceMonitoring, (value) { setState(() => _performanceMonitoring = value); context.read().add(UpdateSystemConfig({'realTimeMonitoringEnabled': value})); _showSuccessSnackBar('Monitoring ${value ? 'activé' : 'désactivé'}'); }, ), _buildSwitchSetting( 'Rapports de crash', 'Envoyer automatiquement les rapports d\'erreur', _crashReportingEnabled, (value) { setState(() => _crashReportingEnabled = value); context.read().add(UpdateSystemConfig({'performanceOptimizationEnabled': value})); _showSuccessSnackBar('Rapports de crash ${value ? 'activés' : 'désactivés'}'); }, ), _buildSwitchSetting( 'Analytics système', 'Collecter des données d\'utilisation anonymes', _analyticsEnabled, (value) { setState(() => _analyticsEnabled = value); context.read().add(UpdateSystemConfig({'metricsCollectionEnabled': value})); _showSuccessSnackBar('Analytics ${value ? 'activées' : 'désactivées'}'); }, ), ], ), // Note : les "Métriques en temps réel" (CPU/RAM/Disque/Réseau) sont // disponibles dans Logs & Monitoring (consultation = read-only). const SizedBox(height: SpacingTokens.xl), // Optimisation _buildSettingsSection( 'Optimisation', 'Améliorer les performances', Icons.tune, [ _buildActionSetting( 'Analyser les performances', 'Scanner les goulots d\'étranglement', Icons.analytics, AppColors.primary, () => _analyzePerformance(), ), _buildActionSetting( 'Nettoyer les logs anciens', 'Supprimer les logs de plus de 30 jours', Icons.cleaning_services, AppColors.warning, () => _cleanOldLogs(), ), _buildActionSetting( 'Redémarrer les services', 'Relancer tous les services système', Icons.restart_alt, AppColors.error, () => _restartServices(), ), ], ), const SizedBox(height: 80), ], ), ); } /// Onglet maintenance Widget _buildMaintenanceTab() { return SingleChildScrollView( padding: const EdgeInsets.all(SpacingTokens.lg), child: Column( children: [ const SizedBox(height: SpacingTokens.xl), // Sauvegarde & restauration — gérée intégralement dans l'écran // dédié BackupPage (Drawer → Système → Sauvegarde & Restauration). // On garde uniquement un raccourci pour éviter la duplication. _buildSettingsSection( 'Sauvegarde & restauration', 'Configuration et historique des sauvegardes', Icons.backup, [ _buildActionSetting( 'Ouvrir Sauvegarde & Restauration', 'Planification, sauvegardes manuelles et restauration', Icons.open_in_new, ModuleColors.backup, () => _restoreFromBackup(), ), ], ), const SizedBox(height: SpacingTokens.xl), // Maintenance système _buildSettingsSection( 'Maintenance système', 'Opérations de maintenance', Icons.build, [ _buildInfoSetting( 'Dernière maintenance', _metrics?.lastMaintenance ?? 'Aucune maintenance récente', ), _buildInfoSetting( 'Prochaine maintenance', _metrics?.nextScheduledMaintenance ?? 'Non planifiée', ), _buildActionSetting( 'Planifier une maintenance', 'Programmer une fenêtre de maintenance', Icons.schedule, AppColors.primary, () => _scheduleMaintenance(), ), _buildActionSetting( 'Maintenance d\'urgence', 'Lancer immédiatement une maintenance', Icons.warning, AppColors.error, () => _emergencyMaintenance(), ), ], ), const SizedBox(height: SpacingTokens.xl), // Mise à jour système _buildSettingsSection( 'Mise à jour système', 'Gestion des versions', Icons.system_update, [ _buildInfoSetting( 'Version actuelle', _metrics != null ? 'UnionFlow Server ${_metrics!.applicationVersion ?? "N/A"}' : 'Chargement...', ), _buildInfoSetting( 'Uptime', _metrics?.uptimeFormatted ?? 'Chargement...', ), _buildActionSetting( 'Vérifier les mises à jour', 'Rechercher les nouvelles versions', Icons.refresh, AppColors.primary, () => _checkUpdates(), ), _buildActionSetting( 'Historique des mises à jour', 'Voir les versions précédentes', Icons.history, AppColors.primary, () => _showUpdateHistory(), ), ], ), const SizedBox(height: 80), ], ), ); } /// Onglet monitoring Widget _buildMonitoringTab() { return SingleChildScrollView( padding: const EdgeInsets.all(SpacingTokens.lg), child: Column( children: [ const SizedBox(height: SpacingTokens.xl), // Alertes système _buildSettingsSection( 'Alertes système', 'Notifications d\'état critique', Icons.notifications_active, [ _buildAlertItem( 'CPU élevé', 'Alerte si CPU > 80% pendant 5 min', _alertCpuHigh, AppColors.warning, onChanged: (value) => setState(() => _alertCpuHigh = value), ), _buildAlertItem( 'Mémoire faible', 'Alerte si RAM < 20% disponible', _alertLowMemory, AppColors.warning, onChanged: (value) => setState(() => _alertLowMemory = value), ), _buildAlertItem( 'Disque plein', 'Alerte si stockage > 90%', _alertDiskFull, AppColors.error, onChanged: (value) => setState(() => _alertDiskFull = value), ), _buildAlertItem( 'Connexions échouées', 'Alerte si > 100 échecs/min', _alertFailedConnections, AppColors.primary, onChanged: (value) => setState(() => _alertFailedConnections = value), ), ], ), const SizedBox(height: SpacingTokens.xl), // Note : les compteurs de logs (Erreurs/Warnings/Infos/Debug), // les statistiques d'utilisation et la consultation des logs // sont accessibles dans Logs & Monitoring (CONSULTATION). // Les rapports d'utilisation détaillés sont dans Plus → Rapports & Analytics. const SizedBox(height: 80), ], ), ); } // ==================== MÉTHODES DE CONSTRUCTION DES COMPOSANTS ==================== /// Section de paramètres Widget _buildSettingsSection( String title, String subtitle, IconData icon, List children, ) { return Container( padding: const EdgeInsets.all(SpacingTokens.xl), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(SpacingTokens.radiusXl), boxShadow: const [ BoxShadow( color: AppColors.shadow, blurRadius: 10, offset: Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, color: Theme.of(context).colorScheme.onSurfaceVariant, size: 20), const SizedBox(width: SpacingTokens.md), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Theme.of(context).colorScheme.onSurface, ), ), Text( subtitle, style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ), ), ], ), const SizedBox(height: SpacingTokens.xl), ...children.map((child) => Padding( padding: const EdgeInsets.only(bottom: SpacingTokens.lg), child: child, )), ], ), ); } /// Paramètre avec switch Widget _buildSwitchSetting( String title, String subtitle, bool value, Function(bool) onChanged, { bool isWarning = false, }) { final isDark = Theme.of(context).brightness == Brightness.dark; return Container( padding: const EdgeInsets.all(SpacingTokens.lg), decoration: BoxDecoration( color: isWarning ? AppColors.warningContainer : Theme.of(context).colorScheme.surfaceContainerLow, borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), border: isWarning ? Border.all(color: AppColors.warningUI) : null, ), child: Row( children: [ if (isWarning) const Icon(Icons.warning, color: AppColors.warning, size: 20) else const Icon(Icons.toggle_on, color: AppColors.primary, size: 20), const SizedBox(width: SpacingTokens.lg), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: isWarning ? AppColors.warning : (isDark ? AppColors.textPrimaryDark : AppColors.textPrimary), ), ), Text( subtitle, style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ), ), Switch( value: value, onChanged: onChanged, activeColor: isWarning ? AppColors.warning : AppColors.primary, ), ], ), ); } /// Paramètre avec dropdown Widget _buildDropdownSetting( String title, String subtitle, String value, List options, Function(String?) onChanged, ) { final isDark = Theme.of(context).brightness == Brightness.dark; return Container( padding: const EdgeInsets.all(SpacingTokens.lg), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceContainerLow, borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.arrow_drop_down, color: AppColors.primary, size: 20), const SizedBox(width: SpacingTokens.lg), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: isDark ? AppColors.textPrimaryDark : AppColors.textPrimary, ), ), Text( subtitle, style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ), ), ], ), const SizedBox(height: SpacingTokens.md), Container( padding: const EdgeInsets.symmetric(horizontal: SpacingTokens.lg), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), border: Border.all(color: isDark ? AppColors.borderDark : AppColors.border), ), child: DropdownButtonHideUnderline( child: DropdownButton( value: value, isExpanded: true, onChanged: onChanged, items: options.map((option) { return DropdownMenuItem( value: option, child: Text(option), ); }).toList(), ), ), ), ], ), ); } /// Paramètre d'action Widget _buildActionSetting( String title, String subtitle, IconData icon, Color color, VoidCallback onTap, ) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), child: Container( padding: const EdgeInsets.all(SpacingTokens.lg), decoration: BoxDecoration( color: color.withOpacity(0.05), borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), border: Border.all(color: color.withOpacity(0.1)), ), child: Row( children: [ Icon(icon, color: color, size: 20), const SizedBox(width: SpacingTokens.lg), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: color, ), ), Text( subtitle, style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ), ), Icon(Icons.arrow_forward_ios, color: Theme.of(context).colorScheme.onSurfaceVariant, size: 16), ], ), ), ); } /// Paramètre d'information Widget _buildInfoSetting(String title, String value) { final isDark = Theme.of(context).brightness == Brightness.dark; return Container( padding: const EdgeInsets.all(SpacingTokens.lg), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceContainerLow, borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), ), child: Row( children: [ Icon(Icons.info_outline, color: Theme.of(context).colorScheme.onSurfaceVariant, size: 20), const SizedBox(width: SpacingTokens.lg), Expanded( child: Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: isDark ? AppColors.textPrimaryDark : AppColors.textPrimary, ), ), ), Text( value, style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, fontWeight: FontWeight.w600, ), ), ], ), ); } /// Élément d'alerte Widget _buildAlertItem(String title, String subtitle, bool enabled, Color color, {Function(bool)? onChanged}) { return Container( padding: const EdgeInsets.all(SpacingTokens.lg), decoration: BoxDecoration( color: enabled ? color.withOpacity(0.05) : Theme.of(context).colorScheme.surfaceContainerLow, borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), border: Border.all( color: enabled ? color.withOpacity(0.3) : Theme.of(context).colorScheme.outlineVariant, ), ), child: Row( children: [ Icon( enabled ? Icons.notifications_active : Icons.notifications_off, color: enabled ? color : Theme.of(context).colorScheme.onSurfaceVariant, size: 20, ), const SizedBox(width: SpacingTokens.lg), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: enabled ? color : Theme.of(context).colorScheme.onSurface, ), ), Text( subtitle, style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ), ), Switch( value: enabled, onChanged: (value) { onChanged?.call(value); _showSuccessSnackBar('Alerte ${value ? 'activée' : 'désactivée'}'); }, activeColor: color, ), ], ), ); } // ==================== MÉTHODES D'ACTION ==================== /// Charger les paramètres système void _loadSystemSettings() { // Simuler le chargement des paramètres depuis le serveur // En production, ceci ferait appel à l'API } /// Afficher l'état du système void _showSystemStatus() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('État du système'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildStatusItem('Serveur API', 'Opérationnel', AppColors.success), _buildStatusItem('Base de données', 'Opérationnel', AppColors.success), _buildStatusItem('Authentification', 'Opérationnel', AppColors.success), _buildStatusItem('CDN', 'Dégradé', AppColors.warning), _buildStatusItem('Monitoring', 'Opérationnel', AppColors.success), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Fermer'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _showSuccessSnackBar('État du système actualisé'); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, foregroundColor: AppColors.onPrimary, ), child: const Text('Actualiser'), ), ], ), ); } /// Élément de statut Widget _buildStatusItem(String service, String status, Color color) { return Padding( padding: const EdgeInsets.symmetric(vertical: SpacingTokens.sm), child: Row( children: [ Icon(Icons.circle, color: color, size: 12), const SizedBox(width: SpacingTokens.md), Expanded(child: Text(service)), Text( status, style: TextStyle( color: color, fontWeight: FontWeight.w600, ), ), ], ), ); } /// Exporter la configuration système void _exportSystemConfig() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Exporter la configuration'), content: const Text( 'La configuration système sera exportée dans un fichier JSON. ' 'Ce fichier contient tous les paramètres actuels du système.', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Annuler'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _showSuccessSnackBar('Configuration exportée avec succès'); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, foregroundColor: AppColors.onPrimary, ), child: const Text('Exporter'), ), ], ), ); } /// Dialogue de mode maintenance void _showMaintenanceModeDialog(bool enabled) { if (enabled) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Mode maintenance activé'), content: const Text( 'ATTENTION : Le mode maintenance va bloquer l\'accès à tous les utilisateurs. ' 'Seuls les administrateurs système pourront accéder à l\'application.', ), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); setState(() => _maintenanceMode = false); }, child: const Text('Annuler'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _showSuccessSnackBar('Mode maintenance activé - Utilisateurs bloqués'); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.warning, foregroundColor: AppColors.onPrimary, ), child: const Text('Confirmer'), ), ], ), ); } else { _showSuccessSnackBar('Mode maintenance désactivé - Accès restauré'); } } // Actions générales void _clearSystemCache() { context.read().add(ClearCache()); } void _optimizeDatabase() => context.read().add(OptimizeDatabase()); void _testConnectivity() { context.read().add(TestDatabaseConnection()); } // Actions de sécurité void _regenerateApiKeys() { _showWarningDialog('Régénérer les clés API', 'Cette action invalidera toutes les clés existantes.', onConfirm: () { context.read().add(CleanupSessions()); }); } void _forceGlobalLogout() { _showWarningDialog('Déconnexion globale', 'Tous les utilisateurs seront déconnectés immédiatement.', onConfirm: () { context.read().add(ForceGlobalLogout()); }); } void _resetSessions() => context.read().add(CleanupSessions()); void _generateAuditReport() => context.read().add(GenerateAuditReport()); void _exportGDPRData() => context.read().add(ExportGDPRData()); void _purgeExpiredData() { _showWarningDialog('Purge des données', 'Les données expirées seront définitivement supprimées.', onConfirm: () { context.read().add(PurgeExpiredData()); }); } // Actions de performance void _analyzePerformance() => context.read().add(AnalyzePerformance()); void _cleanOldLogs() => context.read().add(CleanOldLogs()); void _restartServices() { _showWarningDialog('Redémarrer les services', 'Cette action causera une interruption temporaire du service.', onConfirm: () { _showSuccessSnackBar('Demande de redémarrage envoyée aux services'); }); } // Actions de maintenance void _restoreFromBackup() { Navigator.of(context).push(MaterialPageRoute(builder: (_) => const BackupPage())); } void _scheduleMaintenance() { final now = DateTime.now().add(const Duration(hours: 2)); final scheduledAt = '${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')} ${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}'; context.read().add(ScheduleMaintenance(scheduledAt: scheduledAt, reason: 'Maintenance de routine')); } void _emergencyMaintenance() { _showWarningDialog('Maintenance d\'urgence', 'Le système sera immédiatement mis en maintenance.', onConfirm: () { context.read().add(EmergencyMaintenance()); }); } void _checkUpdates() => context.read().add(CheckUpdates()); void _showUpdateHistory() => _showSuccessSnackBar('Fonctionnalité disponible prochainement'); // Actions de monitoring (consultation, export, rapports) déplacées vers // Logs & Monitoring (Drawer → Système → Logs & Monitoring) et // Plus → Rapports & Analytics. /// Dialogue d'avertissement générique void _showWarningDialog(String title, String message, {VoidCallback? onConfirm}) { showDialog( context: context, builder: (context) => AlertDialog( title: Text(title), content: Text(message), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Annuler'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); if (onConfirm != null) { onConfirm(); } else { _showSuccessSnackBar('Opération confirmée'); } }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.error, foregroundColor: AppColors.onError, ), child: const Text('Confirmer'), ), ], ), ); } /// Afficher un message de succès void _showSuccessSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: AppColors.success, behavior: SnackBarBehavior.floating, ), ); } /// Afficher un message d'erreur void _showErrorSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: AppColors.error, behavior: SnackBarBehavior.floating, ), ); } }