import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_text_styles.dart'; import '../../../core/theme/app_dimensions.dart'; import '../../../core/widgets/custom_button.dart'; import '../../../core/widgets/custom_text_field.dart'; import '../providers/auth_provider.dart'; import '../../../core/models/user_model.dart'; /// 个人信息管理页面 class ProfileScreen extends ConsumerStatefulWidget { const ProfileScreen({super.key}); @override ConsumerState createState() => _ProfileScreenState(); } class _ProfileScreenState extends ConsumerState with SingleTickerProviderStateMixin { late TabController _tabController; final _formKey = GlobalKey(); // 个人信息控制器 final _usernameController = TextEditingController(); final _emailController = TextEditingController(); final _phoneController = TextEditingController(); final _bioController = TextEditingController(); // 密码修改控制器 final _currentPasswordController = TextEditingController(); final _newPasswordController = TextEditingController(); final _confirmPasswordController = TextEditingController(); bool _isLoading = false; bool _isEditing = false; bool _obscureCurrentPassword = true; bool _obscureNewPassword = true; bool _obscureConfirmPassword = true; @override void initState() { super.initState(); _tabController = TabController(length: 3, vsync: this); _loadUserData(); } @override void dispose() { _tabController.dispose(); _usernameController.dispose(); _emailController.dispose(); _phoneController.dispose(); _bioController.dispose(); _currentPasswordController.dispose(); _newPasswordController.dispose(); _confirmPasswordController.dispose(); super.dispose(); } /// 加载用户数据 void _loadUserData() async { try { final authNotifier = await ref.read(authProvider.future); final user = authNotifier.state.user; if (user != null) { _usernameController.text = user.username; _emailController.text = user.email; _phoneController.text = user.profile?.phone ?? ''; _bioController.text = user.profile?.bio ?? ''; } } catch (e) { // 处理错误 } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.background, appBar: AppBar( backgroundColor: AppColors.surface, elevation: 0, title: Text( '个人信息', style: AppTextStyles.headlineSmall.copyWith( color: AppColors.onSurface, fontWeight: FontWeight.w600, ), ), actions: [ if (_tabController.index == 0) TextButton( onPressed: () { setState(() { _isEditing = !_isEditing; }); }, child: Text( _isEditing ? '取消' : '编辑', style: AppTextStyles.labelLarge.copyWith( color: AppColors.primary, ), ), ), ], bottom: TabBar( controller: _tabController, labelColor: AppColors.primary, unselectedLabelColor: AppColors.onSurfaceVariant, indicatorColor: AppColors.primary, tabs: const [ Tab(text: '基本信息'), Tab(text: '安全设置'), Tab(text: '学习偏好'), ], ), ), body: TabBarView( controller: _tabController, children: [ _buildBasicInfoTab(), _buildSecurityTab(), _buildPreferencesTab(), ], ), ); } /// 基本信息标签页 Widget _buildBasicInfoTab() { return Consumer(builder: (context, ref, child) { final authNotifierAsync = ref.watch(authProvider); return authNotifierAsync.when( data: (authNotifier) { final user = authNotifier.state.user; return SingleChildScrollView( padding: const EdgeInsets.all(AppDimensions.spacingXl), child: Form( key: _formKey, child: Column( children: [ // 头像 Center( child: Stack( children: [ CircleAvatar( radius: 60, backgroundColor: AppColors.surfaceVariant, backgroundImage: user?.profile?.avatar != null ? NetworkImage(user!.profile!.avatar!) : null, child: user?.profile?.avatar == null ? Icon( Icons.person, size: 60, color: AppColors.onSurfaceVariant, ) : null, ), if (_isEditing) Positioned( bottom: 0, right: 0, child: GestureDetector( onTap: _handleAvatarChange, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: AppColors.primary, shape: BoxShape.circle, border: Border.all( color: AppColors.surface, width: 2, ), ), child: Icon( Icons.camera_alt, size: 20, color: AppColors.onPrimary, ), ), ), ), ], ), ), const SizedBox(height: AppDimensions.spacingXl), // 用户名 CustomTextField( controller: _usernameController, labelText: '用户名', prefixIcon: Icons.person_outline, enabled: _isEditing, validator: (value) { if (value == null || value.isEmpty) { return '请输入用户名'; } if (value.length < 3) { return '用户名至少3个字符'; } return null; }, ), const SizedBox(height: AppDimensions.spacingMd), // 邮箱 CustomTextField( controller: _emailController, labelText: '邮箱', prefixIcon: Icons.email_outlined, enabled: false, // 邮箱不允许修改 keyboardType: TextInputType.emailAddress, ), const SizedBox(height: AppDimensions.spacingMd), // 手机号 CustomTextField( controller: _phoneController, labelText: '手机号', prefixIcon: Icons.phone_outlined, enabled: _isEditing, keyboardType: TextInputType.phone, validator: (value) { if (value != null && value.isNotEmpty) { if (!RegExp(r'^1[3-9]\d{9}$').hasMatch(value)) { return '请输入有效的手机号'; } } return null; }, ), const SizedBox(height: AppDimensions.spacingMd), // 个人简介 CustomTextField( controller: _bioController, labelText: '个人简介', prefixIcon: Icons.edit_outlined, enabled: _isEditing, maxLines: 3, hintText: '介绍一下自己吧...', ), const SizedBox(height: AppDimensions.spacingXl), // 保存按钮 if (_isEditing) CustomButton( text: '保存修改', onPressed: _handleSaveProfile, isLoading: _isLoading, width: double.infinity, ), ], ), ), ); }, loading: () => const Center(child: CircularProgressIndicator()), error: (error, stack) => Center( child: Text('加载失败: $error'), ), ); }); } /// 安全设置标签页 Widget _buildSecurityTab() { return SingleChildScrollView( padding: const EdgeInsets.all(AppDimensions.spacingXl), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 修改密码 Text( '修改密码', style: AppTextStyles.titleMedium.copyWith( color: AppColors.onSurface, fontWeight: FontWeight.w600, ), ), const SizedBox(height: AppDimensions.spacingMd), // 当前密码 CustomTextField( controller: _currentPasswordController, labelText: '当前密码', prefixIcon: Icons.lock_outline, obscureText: _obscureCurrentPassword, suffixIcon: IconButton( icon: Icon( _obscureCurrentPassword ? Icons.visibility_off : Icons.visibility, color: AppColors.onSurfaceVariant, ), onPressed: () { setState(() { _obscureCurrentPassword = !_obscureCurrentPassword; }); }, ), validator: (value) { if (value == null || value.isEmpty) { return '请输入当前密码'; } return null; }, ), const SizedBox(height: AppDimensions.spacingMd), // 新密码 CustomTextField( controller: _newPasswordController, labelText: '新密码', prefixIcon: Icons.lock_outline, obscureText: _obscureNewPassword, suffixIcon: IconButton( icon: Icon( _obscureNewPassword ? Icons.visibility_off : Icons.visibility, color: AppColors.onSurfaceVariant, ), onPressed: () { setState(() { _obscureNewPassword = !_obscureNewPassword; }); }, ), validator: (value) { if (value == null || value.isEmpty) { return '请输入新密码'; } if (value.length < 8) { return '密码至少8个字符'; } if (!RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)').hasMatch(value)) { return '密码必须包含大小写字母和数字'; } return null; }, ), const SizedBox(height: AppDimensions.spacingMd), // 确认新密码 CustomTextField( controller: _confirmPasswordController, labelText: '确认新密码', prefixIcon: Icons.lock_outline, obscureText: _obscureConfirmPassword, suffixIcon: IconButton( icon: Icon( _obscureConfirmPassword ? Icons.visibility_off : Icons.visibility, color: AppColors.onSurfaceVariant, ), onPressed: () { setState(() { _obscureConfirmPassword = !_obscureConfirmPassword; }); }, ), validator: (value) { if (value == null || value.isEmpty) { return '请确认新密码'; } if (value != _newPasswordController.text) { return '两次输入的密码不一致'; } return null; }, ), const SizedBox(height: AppDimensions.spacingXl), // 修改密码按钮 CustomButton( text: '修改密码', onPressed: _handleChangePassword, isLoading: _isLoading, width: double.infinity, ), const SizedBox(height: AppDimensions.spacingXl), // 其他安全选项 _buildSecurityOption( icon: Icons.security, title: '两步验证', subtitle: '为您的账户添加额外的安全保护', onTap: () => _showSnackBar('两步验证功能即将上线'), ), _buildSecurityOption( icon: Icons.devices, title: '设备管理', subtitle: '查看和管理已登录的设备', onTap: () => _showSnackBar('设备管理功能即将上线'), ), _buildSecurityOption( icon: Icons.history, title: '登录历史', subtitle: '查看最近的登录记录', onTap: () => _showSnackBar('登录历史功能即将上线'), ), ], ), ); } /// 学习偏好标签页 Widget _buildPreferencesTab() { return Consumer(builder: (context, ref, child) { final authNotifierAsync = ref.watch(authProvider); return authNotifierAsync.when( data: (authNotifier) { final user = authNotifier.state.user; final settings = user?.profile?.settings; return SingleChildScrollView( padding: const EdgeInsets.all(AppDimensions.spacingXl), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '学习设置', style: AppTextStyles.titleMedium.copyWith( color: AppColors.onSurface, fontWeight: FontWeight.w600, ), ), const SizedBox(height: AppDimensions.spacingMd), _buildPreferenceOption( icon: Icons.notifications, title: '学习提醒', subtitle: '每日学习提醒通知', value: settings?.notificationsEnabled ?? true, onChanged: (value) => _updateSetting('notificationsEnabled', value), ), _buildPreferenceOption( icon: Icons.volume_up, title: '音效', subtitle: '学习过程中的音效反馈', value: settings?.soundEnabled ?? true, onChanged: (value) => _updateSetting('soundEnabled', value), ), _buildPreferenceOption( icon: Icons.vibration, title: '震动反馈', subtitle: '操作时的震动反馈', value: settings?.vibrationEnabled ?? true, onChanged: (value) => _updateSetting('vibrationEnabled', value), ), const SizedBox(height: AppDimensions.spacingXl), Text( '学习目标', style: AppTextStyles.titleMedium.copyWith( color: AppColors.onSurface, fontWeight: FontWeight.w600, ), ), const SizedBox(height: AppDimensions.spacingMd), _buildGoalOption( title: '每日单词目标', value: '${settings?.dailyWordGoal ?? 20} 个', onTap: () => _showGoalDialog('dailyWordGoal', settings?.dailyWordGoal ?? 20), ), _buildGoalOption( title: '每日学习时长', value: '${settings?.dailyStudyMinutes ?? 30} 分钟', onTap: () => _showGoalDialog('dailyStudyMinutes', settings?.dailyStudyMinutes ?? 30), ), const SizedBox(height: AppDimensions.spacingXl), Text( '英语水平', style: AppTextStyles.titleMedium.copyWith( color: AppColors.onSurface, fontWeight: FontWeight.w600, ), ), const SizedBox(height: AppDimensions.spacingMd), _buildLevelOption( title: '当前水平', value: _getLevelText(user?.profile?.englishLevel ?? EnglishLevel.beginner), onTap: () => _showLevelDialog(), ), ], ), ); }, loading: () => const Center(child: CircularProgressIndicator()), error: (error, stack) => Center( child: Text('加载失败: $error'), ), ); }); } /// 构建安全选项 Widget _buildSecurityOption({ required IconData icon, required String title, required String subtitle, required VoidCallback onTap, }) { return ListTile( leading: Icon(icon, color: AppColors.primary), title: Text( title, style: AppTextStyles.bodyLarge.copyWith( color: AppColors.onSurface, ), ), subtitle: Text( subtitle, style: AppTextStyles.bodyMedium.copyWith( color: AppColors.onSurfaceVariant, ), ), trailing: Icon( Icons.arrow_forward_ios, size: 16, color: AppColors.onSurfaceVariant, ), onTap: onTap, ); } /// 构建偏好选项 Widget _buildPreferenceOption({ required IconData icon, required String title, required String subtitle, required bool value, required ValueChanged onChanged, }) { return ListTile( leading: Icon(icon, color: AppColors.primary), title: Text( title, style: AppTextStyles.bodyLarge.copyWith( color: AppColors.onSurface, ), ), subtitle: Text( subtitle, style: AppTextStyles.bodyMedium.copyWith( color: AppColors.onSurfaceVariant, ), ), trailing: Switch( value: value, onChanged: onChanged, activeColor: AppColors.primary, ), ); } /// 构建目标选项 Widget _buildGoalOption({ required String title, required String value, required VoidCallback onTap, }) { return ListTile( title: Text( title, style: AppTextStyles.bodyLarge.copyWith( color: AppColors.onSurface, ), ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Text( value, style: AppTextStyles.bodyMedium.copyWith( color: AppColors.primary, ), ), const SizedBox(width: 8), Icon( Icons.arrow_forward_ios, size: 16, color: AppColors.onSurfaceVariant, ), ], ), onTap: onTap, ); } /// 构建水平选项 Widget _buildLevelOption({ required String title, required String value, required VoidCallback onTap, }) { return ListTile( title: Text( title, style: AppTextStyles.bodyLarge.copyWith( color: AppColors.onSurface, ), ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Text( value, style: AppTextStyles.bodyMedium.copyWith( color: AppColors.primary, ), ), const SizedBox(width: 8), Icon( Icons.arrow_forward_ios, size: 16, color: AppColors.onSurfaceVariant, ), ], ), onTap: onTap, ); } /// 处理头像更改 void _handleAvatarChange() { // TODO: 实现头像更改功能 _showSnackBar('头像更改功能即将上线'); } /// 处理保存个人信息 Future _handleSaveProfile() async { if (!_formKey.currentState!.validate()) { return; } setState(() { _isLoading = true; }); try { final authNotifier = await ref.read(authProvider.future); await authNotifier.updateProfile( username: _usernameController.text.trim(), phone: _phoneController.text.trim(), ); if (mounted) { setState(() { _isEditing = false; }); _showSnackBar('个人信息更新成功', isSuccess: true); } } catch (e) { if (mounted) { _showSnackBar(e.toString()); } } finally { if (mounted) { setState(() { _isLoading = false; }); } } } /// 处理修改密码 Future _handleChangePassword() async { if (_currentPasswordController.text.isEmpty || _newPasswordController.text.isEmpty || _confirmPasswordController.text.isEmpty) { _showSnackBar('请填写所有密码字段'); return; } if (_newPasswordController.text != _confirmPasswordController.text) { _showSnackBar('两次输入的新密码不一致'); return; } setState(() { _isLoading = true; }); try { final authNotifier = await ref.read(authProvider.future); await authNotifier.changePassword( currentPassword: _currentPasswordController.text, newPassword: _newPasswordController.text, ); if (mounted) { _currentPasswordController.clear(); _newPasswordController.clear(); _confirmPasswordController.clear(); _showSnackBar('密码修改成功', isSuccess: true); } } catch (e) { if (mounted) { _showSnackBar(e.toString()); } } finally { if (mounted) { setState(() { _isLoading = false; }); } } } /// 更新设置 void _updateSetting(String key, bool value) { // TODO: 实现设置更新 _showSnackBar('设置已更新', isSuccess: true); } /// 显示目标设置对话框 void _showGoalDialog(String type, int currentValue) { // TODO: 实现目标设置对话框 _showSnackBar('目标设置功能即将上线'); } /// 显示水平选择对话框 void _showLevelDialog() { // TODO: 实现水平选择对话框 _showSnackBar('水平设置功能即将上线'); } /// 获取水平文本 String _getLevelText(EnglishLevel level) { switch (level) { case EnglishLevel.beginner: return '初级'; case EnglishLevel.elementary: return '基础'; case EnglishLevel.intermediate: return '中级'; case EnglishLevel.upperIntermediate: return '中高级'; case EnglishLevel.advanced: return '高级'; case EnglishLevel.proficient: return '精通'; case EnglishLevel.expert: return '专家'; } } /// 显示提示信息 void _showSnackBar(String message, {bool isSuccess = false}) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: isSuccess ? AppColors.success : AppColors.error, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppDimensions.radiusSm), ), ), ); } }