/// Page dédiée aux paramètres de langue /// Permet de changer la langue de l'interface et la région library language_settings_page; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../../../core/l10n/locale_provider.dart'; import '../../../../shared/design_system/unionflow_design_system.dart'; class LanguageSettingsPage extends StatefulWidget { const LanguageSettingsPage({super.key}); @override State createState() => _LanguageSettingsPageState(); } class _LanguageSettingsPageState extends State { String _selectedLanguage = 'Français'; static const _supportedLanguages = [ _LanguageOption('Français', 'fr', '🇫🇷', 'Langue par défaut'), _LanguageOption('English', 'en', '🇬🇧', 'Default language'), ]; @override void didChangeDependencies() { super.didChangeDependencies(); _syncFromProvider(); } void _syncFromProvider() { final lp = context.read(); if (lp.currentLanguageName != _selectedLanguage) { setState(() => _selectedLanguage = lp.currentLanguageName); } } Future _changeLanguage(String languageName, String code) async { final lp = context.read(); await lp.setLocale(Locale(code)); if (mounted) { setState(() => _selectedLanguage = languageName); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Langue changée en $languageName'), backgroundColor: AppColors.success, behavior: SnackBarBehavior.floating, ), ); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, body: SafeArea( top: false, child: Column( children: [ _buildHeader(), Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(12), child: Column( children: [ const SizedBox(height: 8), _buildLanguageList(), const SizedBox(height: 8), _buildInfoSection(), const SizedBox(height: 80), ], ), ), ), ], ), ), ); } Widget _buildHeader() { return Container( margin: const EdgeInsets.all(SpacingTokens.lg), padding: const EdgeInsets.all(SpacingTokens.xxl), decoration: BoxDecoration( gradient: LinearGradient( colors: ModuleColors.parametresGradient, begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(SpacingTokens.xl), boxShadow: [ BoxShadow( color: ModuleColors.parametres.withOpacity(0.3), blurRadius: 20, offset: const Offset(0, 8), ), ], ), child: SafeArea( bottom: false, child: Row( children: [ IconButton( onPressed: () => Navigator.of(context).pop(), icon: const Icon(Icons.arrow_back, color: Colors.white), ), Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(8), ), child: const Icon(Icons.language, color: Colors.white, size: 20), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Langue', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), Text( 'Langue actuelle : $_selectedLanguage', style: TextStyle( fontSize: 14, color: Colors.white.withOpacity(0.8), ), ), ], ), ), ], ), ), ); } Widget _buildLanguageList() { final isDark = Theme.of(context).brightness == Brightness.dark; final textPrimary = isDark ? AppColors.textPrimaryDark : AppColors.textPrimary; final textSecondary = isDark ? AppColors.textSecondaryDark : AppColors.textSecondary; return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: isDark ? AppColors.surfaceDark : Colors.white, borderRadius: BorderRadius.circular(10), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.translate, color: textSecondary, size: 20), const SizedBox(width: 8), Text( 'Langues disponibles', style: AppTypography.headerSmall.copyWith(fontWeight: FontWeight.w600, color: textPrimary), ), ], ), const SizedBox(height: 8), ..._supportedLanguages.map((lang) => _buildLanguageTile(lang)), ], ), ); } Widget _buildLanguageTile(_LanguageOption lang) { final isDark = Theme.of(context).brightness == Brightness.dark; final isSelected = _selectedLanguage == lang.name; final textPrimary = isDark ? AppColors.textPrimaryDark : AppColors.textPrimary; final textSecondary = isDark ? AppColors.textSecondaryDark : AppColors.textSecondary; return Padding( padding: const EdgeInsets.only(bottom: 6), child: InkWell( onTap: () => _changeLanguage(lang.name, lang.code), borderRadius: BorderRadius.circular(8), child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 7), decoration: BoxDecoration( color: isSelected ? AppColors.primary.withOpacity(0.08) : (isDark ? AppColors.backgroundSubtleDark : AppColors.backgroundSubtle), borderRadius: BorderRadius.circular(8), border: isSelected ? Border.all(color: AppColors.primary.withOpacity(0.4), width: 1.5) : Border.all(color: isDark ? AppColors.surfaceVariantDark : AppColors.surfaceVariant), ), child: Row( children: [ Text(lang.flag, style: const TextStyle(fontSize: 28)), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( lang.name, style: AppTypography.bodyTextSmall.copyWith( fontWeight: FontWeight.w600, color: isSelected ? AppColors.primary : textPrimary, ), ), Text( lang.description, style: AppTypography.subtitleSmall.copyWith(color: textSecondary), ), ], ), ), if (isSelected) const Icon(Icons.check_circle, color: AppColors.primary, size: 22), ], ), ), ), ); } Widget _buildInfoSection() { final isDark = Theme.of(context).brightness == Brightness.dark; final textPrimary = isDark ? AppColors.textPrimaryDark : AppColors.textPrimary; final textSecondary = isDark ? AppColors.textSecondaryDark : AppColors.textSecondary; return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: isDark ? AppColors.surfaceDark : Colors.white, borderRadius: BorderRadius.circular(10), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.info_outline, color: textSecondary, size: 20), const SizedBox(width: 8), Text( 'Information', style: AppTypography.headerSmall.copyWith(fontWeight: FontWeight.w600, color: textPrimary), ), ], ), const SizedBox(height: 8), Text( 'Le changement de langue s\'applique immédiatement à toute l\'interface. ' 'Les contenus générés par le serveur restent dans leur langue d\'origine.', style: AppTypography.subtitleSmall.copyWith(color: textSecondary, height: 1.5), ), ], ), ); } } class _LanguageOption { final String name; final String code; final String flag; final String description; const _LanguageOption(this.name, this.code, this.flag, this.description); }