import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_fonts/google_fonts.dart'; import '../../../providers/mobile_settings_providers.dart'; import '../../../../core/providers/theme_provider.dart'; import '../../../../core/theme/app_colors.dart'; import '../screens/mobile_playlist_selection_screen.dart'; /// Simplified mobile settings tab - no auth, local storage only class MobileSettingsTab extends ConsumerStatefulWidget { const MobileSettingsTab({super.key}); @override ConsumerState createState() => _MobileSettingsTabState(); } class _MobileSettingsTabState extends ConsumerState { late TextEditingController _liveTvController; late TextEditingController _moviesController; late TextEditingController _seriesController; bool _initialized = false; @override void initState() { super.initState(); _liveTvController = TextEditingController(); _moviesController = TextEditingController(); _seriesController = TextEditingController(); } @override void dispose() { _liveTvController.dispose(); _moviesController.dispose(); _seriesController.dispose(); super.dispose(); } void _syncControllers(MobileSettings settings) { if (!_initialized) { _liveTvController.text = settings.liveTvKeywords.join(', '); _moviesController.text = settings.moviesKeywords.join(', '); _seriesController.text = settings.seriesKeywords.join(', '); _initialized = true; } } List _parseKeywords(String text) { return text.split(',').map((s) => s.trim()).where((s) => s.isNotEmpty).toList(); } @override Widget build(BuildContext context) { final settings = ref.watch(mobileSettingsProvider); final themeState = ref.watch(themeProvider); final themeNotifier = ref.read(themeProvider.notifier); final isDark = Theme.of(context).brightness == Brightness.dark; WidgetsBinding.instance.addPostFrameCallback((_) { if (!_initialized) _syncControllers(settings); }); return SafeArea( child: ListView( padding: const EdgeInsets.all(16), children: [ // Header Padding( padding: const EdgeInsets.only(bottom: 24), child: Text( 'Paramètres', style: Theme.of(context).textTheme.headlineMedium?.copyWith( color: AppColors.textPrimary, ), ), ), // App Info Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), ), child: Row( children: [ Container( width: 48, height: 48, decoration: BoxDecoration( color: AppColors.primary.withOpacity(0.2), borderRadius: BorderRadius.circular(12), ), child: const Icon(Icons.play_circle_filled, color: AppColors.primary, size: 28), ), const SizedBox(width: 16), const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'XtremFlow Mobile', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), ), SizedBox(height: 4), Text( 'Version 1.1.11', style: TextStyle( fontSize: 13, color: AppColors.textSecondary, ), ), ], ), ), ], ), ), const SizedBox(height: 24), // Appearance const _SectionHeader(title: 'Apparence'), Container( decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), ), child: SwitchListTile( title: const Text('Mode Sombre', style: TextStyle(color: AppColors.textPrimary)), secondary: Icon(isDark ? Icons.dark_mode : Icons.light_mode, color: AppColors.primary), value: isDark, onChanged: (_) => themeNotifier.toggleTheme(), activeColor: AppColors.primary, ), ), const SizedBox(height: 8), Container( decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), ), child: SwitchListTile( title: const Text('Afficher l\'heure', style: TextStyle(color: AppColors.textPrimary)), secondary: const Icon(Icons.access_time, color: AppColors.primary), value: settings.showClock, onChanged: (val) => ref.read(mobileSettingsProvider.notifier).toggleShowClock(val), activeColor: AppColors.primary, ), ), const SizedBox(height: 24), // Playback Settings const _SectionHeader(title: 'Lecture Vidéo'), Container( decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), ), child: Column( children: [ ListTile( leading: const Icon(Icons.rocket_launch, color: AppColors.primary), title: const Text('Moteur Vidéo', style: TextStyle(color: AppColors.textPrimary)), subtitle: Text( settings.playerEngine == 'ultra' ? 'Ultra (MPV) - Puissant' : 'Lite (ExoPlayer) - Léger', style: const TextStyle(color: AppColors.textSecondary), ), trailing: DropdownButton( value: settings.playerEngine, dropdownColor: AppColors.surface, underline: const SizedBox(), icon: const Icon(Icons.arrow_drop_down, color: AppColors.primary), items: const [ DropdownMenuItem(value: 'ultra', child: Text('Ultra', style: TextStyle(color: AppColors.textPrimary))), DropdownMenuItem(value: 'lite', child: Text('Lite', style: TextStyle(color: AppColors.textPrimary))), ], onChanged: (val) { if (val != null) { ref.read(mobileSettingsProvider.notifier).setPlayerEngine(val); } }, ), ), Divider(height: 1, color: AppColors.textSecondary.withOpacity(0.2)), SwitchListTile( title: const Text('Stats pour Nerds', style: TextStyle(color: AppColors.textPrimary)), subtitle: const Text('Infos techniques (FPS, Buffer)', style: TextStyle(color: AppColors.textSecondary, fontSize: 12)), secondary: const Icon(Icons.bug_report, color: AppColors.primary), value: settings.showDebugStats, onChanged: (val) => ref.read(mobileSettingsProvider.notifier).toggleShowDebugStats(val), activeColor: AppColors.primary, ), Divider(height: 1, color: AppColors.textSecondary.withOpacity(0.2)), ListTile( leading: const Icon(Icons.memory, color: AppColors.primary), title: const Text('Décodeur Vidéo', style: TextStyle(color: AppColors.textPrimary)), subtitle: Text( settings.decoderMode == 'auto' ? 'Automatique (Recommandé)' : settings.decoderMode == 'mediacodec' ? 'Matériel (Hardware)' : 'Logiciel (Software)', style: const TextStyle(color: AppColors.textSecondary), ), trailing: DropdownButton( value: settings.decoderMode, dropdownColor: AppColors.surface, underline: const SizedBox(), icon: const Icon(Icons.arrow_drop_down, color: AppColors.primary), items: const [ DropdownMenuItem(value: 'auto', child: Text('Auto', style: TextStyle(color: AppColors.textPrimary))), DropdownMenuItem(value: 'mediacodec', child: Text('Hardware', style: TextStyle(color: AppColors.textPrimary))), DropdownMenuItem(value: 'no', child: Text('Software', style: TextStyle(color: AppColors.textPrimary))), ], onChanged: (val) { if (val != null) { ref.read(mobileSettingsProvider.notifier).setDecoderMode(val); } }, ), ), Divider(height: 1, color: AppColors.textSecondary.withOpacity(0.2)), ListTile( leading: const Icon(Icons.speed, color: AppColors.primary), title: const Text('Mise en mémoire tampon (Cache)', style: TextStyle(color: AppColors.textPrimary)), subtitle: Text( settings.bufferDuration == 0 ? 'Auto (Défaut)' : '${settings.bufferDuration} secondes', style: const TextStyle(color: AppColors.textSecondary), ), trailing: DropdownButton( value: settings.bufferDuration, dropdownColor: AppColors.surface, underline: const SizedBox(), icon: const Icon(Icons.arrow_drop_down, color: AppColors.primary), items: const [ DropdownMenuItem(value: 0, child: Text('Auto', style: TextStyle(color: AppColors.textPrimary))), DropdownMenuItem(value: 15, child: Text('15s', style: TextStyle(color: AppColors.textPrimary))), DropdownMenuItem(value: 30, child: Text('30s', style: TextStyle(color: AppColors.textPrimary))), DropdownMenuItem(value: 60, child: Text('60s', style: TextStyle(color: AppColors.textPrimary))), ], onChanged: (val) { if (val != null) { ref.read(mobileSettingsProvider.notifier).setBufferDuration(val); } }, ), ), ], ), ), const SizedBox(height: 24), // Content Filters const _SectionHeader(title: 'Filtres de Contenu'), Container( decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), ), padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Utilisez des mots-clés pour filtrer les catégories (séparés par des virgules)', style: TextStyle( fontSize: 12, color: AppColors.textSecondary, ), ), const SizedBox(height: 16), _FilterInput( label: 'TV en Direct', hint: 'Ex: FR, HD, SPORT', icon: Icons.live_tv, controller: _liveTvController, onChanged: (val) { ref.read(mobileSettingsProvider.notifier) .setLiveTvKeywords(_parseKeywords(val)); }, ), const SizedBox(height: 16), _FilterInput( label: 'Films', hint: 'Ex: FR, VF, 4K', icon: Icons.movie, controller: _moviesController, onChanged: (val) { ref.read(mobileSettingsProvider.notifier) .setMoviesKeywords(_parseKeywords(val)); }, ), const SizedBox(height: 16), _FilterInput( label: 'Séries', hint: 'Ex: FR, VF', icon: Icons.tv, controller: _seriesController, onChanged: (val) { ref.read(mobileSettingsProvider.notifier) .setSeriesKeywords(_parseKeywords(val)); }, ), ], ), ), const SizedBox(height: 24), // Change Playlist InkWell( onTap: () { // Open Playlist Selection in Manage Mode Navigator.push( context, MaterialPageRoute( builder: (_) => const MobilePlaylistSelectionScreen(manageMode: true), ), ); }, borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(12), ), child: const Row( children: [ Icon(Icons.playlist_play, color: AppColors.textPrimary), SizedBox(width: 16), Text( 'Gérer les Playlists', style: TextStyle( fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), Spacer(), Icon(Icons.chevron_right, color: AppColors.textSecondary), ], ), ), ), const SizedBox(height: 100), ], ), ); } } class _SectionHeader extends StatelessWidget { final String title; const _SectionHeader({required this.title}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(left: 8, bottom: 8), child: Text( title, style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.w600, color: AppColors.textSecondary, ), ), ); } } class _FilterInput extends StatefulWidget { final String label; final String hint; final IconData icon; final TextEditingController controller; final ValueChanged onChanged; const _FilterInput({ required this.label, required this.hint, required this.icon, required this.controller, required this.onChanged, }); @override State<_FilterInput> createState() => _FilterInputState(); } class _FilterInputState extends State<_FilterInput> { late FocusNode _navFocus; late FocusNode _inputFocus; bool _isEditing = false; @override void initState() { super.initState(); _navFocus = FocusNode(); _inputFocus = FocusNode(); _inputFocus.addListener(() { if (!_inputFocus.hasFocus && _isEditing) { setState(() => _isEditing = false); _navFocus.requestFocus(); } }); } @override void dispose() { _navFocus.dispose(); _inputFocus.dispose(); super.dispose(); } void _activateInput() { setState(() => _isEditing = true); WidgetsBinding.instance.addPostFrameCallback((_) { _inputFocus.requestFocus(); }); } @override Widget build(BuildContext context) { return Focus( focusNode: _navFocus, onKeyEvent: (node, event) { if (event is KeyDownEvent) { final key = event.logicalKey; if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter || key == LogicalKeyboardKey.space) { _activateInput(); return KeyEventResult.handled; } } return KeyEventResult.ignored; }, child: Builder( builder: (context) { final isFocused = Focus.of(context).hasFocus; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(widget.icon, size: 18, color: isFocused ? AppColors.primary : AppColors.textSecondary), const SizedBox(width: 8), Text(widget.label, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: isFocused ? AppColors.primary : AppColors.textPrimary, ), ), ], ), const SizedBox(height: 8), GestureDetector( onTap: _activateInput, child: Container( decoration: BoxDecoration( border: isFocused ? Border.all(color: AppColors.primary, width: 2) : null, borderRadius: BorderRadius.circular(8), ), child: ExcludeFocus( excluding: !_isEditing, child: TextField( controller: widget.controller, focusNode: _inputFocus, readOnly: !_isEditing, showCursor: _isEditing, style: const TextStyle(fontSize: 14, color: AppColors.textPrimary), decoration: InputDecoration( isDense: true, hintText: widget.hint, hintStyle: const TextStyle(color: AppColors.textTertiary), filled: true, fillColor: AppColors.background, contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 10), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), ), onChanged: widget.onChanged, onSubmitted: (_) { setState(() => _isEditing = false); _navFocus.requestFocus(); }, ), ), ), ), ], ); }, ), ); } }