import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/api/api_error_mapper.dart'; import '../../../core/l10n/l10n.dart'; import '../../auth/data/auth_providers.dart'; import '../data/profile_repository.dart'; import '../domain/user_profile.dart'; enum _ProfileTab { profile } class ProfileScreen extends ConsumerStatefulWidget { const ProfileScreen({super.key}); @override ConsumerState createState() => _ProfileScreenState(); } class _ProfileScreenState extends ConsumerState { final _formKey = GlobalKey(); bool _isLoading = true; bool _isSaving = false; String? _error; UserProfile? _profile; _ProfileTab _activeTab = _ProfileTab.profile; late final TextEditingController _emailCtrl; late final TextEditingController _firstNameCtrl; late final TextEditingController _lastNameCtrl; @override void initState() { super.initState(); _emailCtrl = TextEditingController(); _firstNameCtrl = TextEditingController(); _lastNameCtrl = TextEditingController(); _loadProfile(); } @override void dispose() { _emailCtrl.dispose(); _firstNameCtrl.dispose(); _lastNameCtrl.dispose(); super.dispose(); } Future _loadProfile() async { setState(() { _isLoading = true; _error = null; }); try { final profile = await ref.read(profileRepositoryProvider).getMe(); if (!mounted) return; setState(() { _profile = profile; _emailCtrl.text = profile.email; _firstNameCtrl.text = profile.firstName ?? ''; _lastNameCtrl.text = profile.lastName ?? ''; }); } catch (e) { if (!mounted) return; setState(() => _error = mapErrorToUserMessage(e, context)); } finally { if (mounted) setState(() => _isLoading = false); } } Future _save() async { if (!_formKey.currentState!.validate()) return; setState(() => _isSaving = true); try { final updated = await ref.read(profileRepositoryProvider).updateMe( email: _emailCtrl.text.trim(), firstName: _firstNameCtrl.text.trim().isEmpty ? null : _firstNameCtrl.text.trim(), lastName: _lastNameCtrl.text.trim().isEmpty ? null : _lastNameCtrl.text.trim(), ); if (!mounted) return; setState(() => _profile = updated); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(context.l10n.profileSaved)), ); } catch (e) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(mapErrorToUserMessage(e, context))), ); } finally { if (mounted) setState(() => _isSaving = false); } } Future _logout() async { await ref.read(authStateProvider.notifier).logout(); if (!mounted) return; context.go('/login'); } List<_ProfileTab> _visibleTabs(bool isAdmin) { return [ _ProfileTab.profile, ]; } String _tabLabel(_ProfileTab tab) { switch (tab) { case _ProfileTab.profile: return context.l10n.profileMyProfileTab; } } Widget _buildTabBar(BuildContext context, List<_ProfileTab> tabs) { return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: tabs .map( (tab) => Padding( padding: const EdgeInsets.only(right: 8), child: ChoiceChip( label: Text(_tabLabel(tab)), selected: _activeTab == tab, onSelected: (_) => setState(() => _activeTab = tab), ), ), ) .toList(), ), ); } Widget _buildProfileForm(BuildContext context, ThemeData theme) { return Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( context.l10n.profileUsernameLabel, style: theme.textTheme.labelMedium?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 4), Text(_profile?.username ?? '', style: theme.textTheme.bodyLarge), const Divider(height: 32), TextFormField( controller: _emailCtrl, decoration: InputDecoration( labelText: context.l10n.profileEmailLabel, border: const OutlineInputBorder(), ), keyboardType: TextInputType.emailAddress, validator: (v) { if (v == null || v.isEmpty) return context.l10n.profileEmailHint; if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(v)) { return context.l10n.profileEmailInvalid; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: _firstNameCtrl, decoration: InputDecoration( labelText: context.l10n.profileFirstNameLabel, border: const OutlineInputBorder(), ), ), const SizedBox(height: 16), TextFormField( controller: _lastNameCtrl, decoration: InputDecoration( labelText: context.l10n.profileLastNameLabel, border: const OutlineInputBorder(), ), ), const SizedBox(height: 24), SizedBox( width: double.infinity, child: FilledButton( onPressed: _isSaving ? null : _save, child: _isSaving ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : Text(context.l10n.profileSaveAction), ), ), ], ), ); } Widget _buildActiveTabContent(BuildContext context, ThemeData theme) { switch (_activeTab) { case _ProfileTab.profile: return _buildProfileForm(context, theme); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); final tabs = _visibleTabs(_profile?.isAdmin == true); if (!tabs.contains(_activeTab)) { _activeTab = _ProfileTab.profile; } if (_isLoading) { return const Center(child: CircularProgressIndicator()); } if (_error != null) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(_error!, style: TextStyle(color: theme.colorScheme.error)), const SizedBox(height: 16), FilledButton(onPressed: _loadProfile, child: Text(context.l10n.retryAction)), ], ), ); } return ListView( padding: const EdgeInsets.all(16), children: [ Row( children: [ CircleAvatar( radius: 28, child: Text( (_profile?.username.isNotEmpty == true ? _profile!.username[0] : '?') .toUpperCase(), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _profile?.username ?? '', style: theme.textTheme.titleLarge, ), if ((_profile?.email ?? '').isNotEmpty) Text( _profile!.email, style: theme.textTheme.bodyMedium?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ], ), ), if (_profile?.isAdmin == true) Chip( label: const Text('Admin'), avatar: const Icon(Icons.shield_outlined, size: 16), backgroundColor: theme.colorScheme.primaryContainer, labelStyle: TextStyle(color: theme.colorScheme.onPrimaryContainer), ), ], ), const SizedBox(height: 16), _buildTabBar(context, tabs), const SizedBox(height: 16), _buildActiveTabContent(context, theme), const SizedBox(height: 24), SizedBox( width: double.infinity, child: OutlinedButton.icon( onPressed: _logout, icon: const Icon(Icons.logout), label: Text(context.l10n.logoutAction), ), ), ], ); } }