import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import '../../../../core/theme/design_tokens.dart'; import '../../../../core/di/injection.dart'; import '../../../../shared/widgets/app_button.dart'; import '../../../../shared/widgets/app_loading_indicator.dart'; import '../../../../shared/widgets/toast/toast.dart'; import '../../../../shared/widgets/toast/toast_type.dart'; import '../../../users/data/models/user_response.dart'; import '../../../users/data/users_api.dart'; import '../widgets/account_section_card.dart'; import '../widgets/account_surface_scaffold.dart'; class EditProfileScreen extends StatefulWidget { const EditProfileScreen({super.key}); @override State createState() => _EditProfileScreenState(); } class _EditProfileScreenState extends State { final _usernameController = TextEditingController(); final _bioController = TextEditingController(); final _usersApi = sl(); UserResponse? _user; bool _isLoading = true; bool _isSaving = false; bool _hasChanges = false; @override void initState() { super.initState(); _loadUser(); } Future _loadUser() async { try { final user = await _usersApi.getMe(); if (mounted) { setState(() { _user = user; _usernameController.text = user.username; _bioController.text = user.bio ?? ''; _isLoading = false; }); } } catch (e) { if (mounted) { setState(() { _isLoading = false; }); Toast.show(context, '加载用户信息失败', type: ToastType.error); } } } void _onFieldChanged() { if (_user == null) return; final usernameChanged = _usernameController.text != _user!.username; final bioChanged = _bioController.text != (_user!.bio ?? ''); if ((usernameChanged || bioChanged) != _hasChanges) { setState(() { _hasChanges = usernameChanged || bioChanged; }); } } Future _saveProfile() async { if (!_hasChanges || _user == null) return; final newUsername = _usernameController.text.trim(); final newBio = _bioController.text.trim(); if (newUsername.isEmpty) { Toast.show(context, '用户名不能为空', type: ToastType.warning); return; } if (newUsername.length < 3 || newUsername.length > 30) { Toast.show(context, '用户名需要3-30个字符', type: ToastType.warning); return; } setState(() { _isSaving = true; }); try { final request = UserUpdateRequest( username: newUsername, bio: newBio.isEmpty ? null : newBio, ); await _usersApi.updateMe(request); if (mounted) { Toast.show(context, '保存成功', type: ToastType.success); context.pop(true); } } catch (e) { if (mounted) { Toast.show(context, '保存失败,请重试', type: ToastType.error); } } finally { if (mounted) { setState(() { _isSaving = false; }); } } } @override void dispose() { _usernameController.dispose(); _bioController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AccountSurfaceScaffold( title: '编辑资料', subtitle: '完善公开信息,让好友更容易认识你', onBack: () => context.pop(), body: _isLoading ? const Center( child: AppLoadingIndicator(variant: AppLoadingVariant.surface), ) : Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildProfileSummarySection(), const SizedBox(height: AppSpacing.lg), _buildBasicInfoSection(), const SizedBox(height: AppSpacing.lg), _buildBioSection(), ], ), footer: SizedBox( width: double.infinity, height: 52, child: AppButton( text: '保存修改', onPressed: _hasChanges && !_isSaving ? _saveProfile : null, isLoading: _isSaving, ), ), ); } Widget _buildProfileSummarySection() { final username = _user?.username ?? '未设置用户名'; final email = _user?.email; return AccountSectionCard( title: '资料概览', description: '展示你的公开身份信息', backgroundColor: AppColors.white, borderColor: AppColors.borderSecondary, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: 64, height: 64, decoration: BoxDecoration( gradient: const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [AppColors.blue100, AppColors.surfaceInfoLight], ), borderRadius: BorderRadius.circular(AppRadius.full), border: Border.all(color: AppColors.borderQuaternary), ), child: const Icon( Icons.person, size: 28, color: AppColors.blue600, ), ), const SizedBox(width: AppSpacing.lg), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( username, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: AppColors.slate900, ), overflow: TextOverflow.ellipsis, ), const SizedBox(height: AppSpacing.xs), Text( email ?? '邮箱未绑定', style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w500, color: AppColors.slate500, ), overflow: TextOverflow.ellipsis, ), ], ), ), ], ), ], ), ); } Widget _buildBasicInfoSection() { return AccountSectionCard( title: '基础信息', description: '用户名会在个人资料和社交场景中展示', backgroundColor: AppColors.white, borderColor: AppColors.borderSecondary, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '用户名', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w700, color: AppColors.slate700, ), ), const SizedBox(height: AppSpacing.sm), TextField( controller: _usernameController, onChanged: (_) => _onFieldChanged(), style: const TextStyle(fontSize: 15, color: AppColors.slate900), decoration: _buildInputDecoration('请输入用户名'), ), ], ), ); } Widget _buildBioSection() { return AccountSectionCard( title: '个人简介', description: '一句话介绍自己,帮助他人快速了解你', backgroundColor: AppColors.white, borderColor: AppColors.borderSecondary, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '简介内容', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w700, color: AppColors.slate700, ), ), const SizedBox(height: AppSpacing.sm), TextField( controller: _bioController, onChanged: (_) => _onFieldChanged(), maxLines: 4, maxLength: 200, style: const TextStyle(fontSize: 15, color: AppColors.slate900), decoration: _buildInputDecoration( '介绍一下自己吧', ).copyWith(contentPadding: const EdgeInsets.all(AppSpacing.lg)), ), ], ), ); } InputDecoration _buildInputDecoration(String hintText) { return InputDecoration( hintText: hintText, hintStyle: const TextStyle(fontSize: 14, color: AppColors.slate400), filled: true, fillColor: AppColors.surfaceSecondary, contentPadding: const EdgeInsets.symmetric( horizontal: AppSpacing.lg, vertical: AppSpacing.lg, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(AppRadius.lg), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(AppRadius.lg), borderSide: const BorderSide(color: AppColors.borderTertiary), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(AppRadius.lg), borderSide: const BorderSide(color: AppColors.blue500), ), ); } }