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/page_header.dart' as widgets; 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'; 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 Scaffold( backgroundColor: AppColors.surfaceSecondary, body: SafeArea( child: Column( children: [ _buildHeader(), Expanded( child: _isLoading ? const Center(child: AppLoadingIndicator(size: 22)) : SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( children: [ _buildAvatarSection(), const SizedBox(height: 24), _buildFormSection(), const SizedBox(height: 32), SizedBox( width: double.infinity, height: 52, child: AppButton( text: '保存修改', onPressed: _hasChanges && !_isSaving ? _saveProfile : null, isLoading: _isSaving, ), ), ], ), ), ), ], ), ), ); } Widget _buildHeader() { return SizedBox( height: 64, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Row( children: [ widgets.BackButton(onPressed: () => context.pop()), const SizedBox(width: 12), const Text( '编辑资料', style: TextStyle( fontSize: 17, fontWeight: FontWeight.w600, color: AppColors.slate900, ), ), ], ), ), ); } Widget _buildAvatarSection() { return Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColors.white, borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.borderSecondary), ), child: Column( children: [ Container( width: 72, height: 72, decoration: BoxDecoration( gradient: const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFFEAF1FF), Color(0xFFF8FBFF)], ), borderRadius: BorderRadius.circular(36), border: Border.all(color: const Color(0xFFD9E5FA)), ), child: const Icon(Icons.person, size: 36, color: AppColors.blue500), ), const SizedBox(height: 12), Text( '点击更换头像', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w500, color: AppColors.slate500, ), ), ], ), ); } Widget _buildFormSection() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.white, borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.borderSecondary), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '用户名', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: AppColors.slate700, ), ), const SizedBox(height: 8), TextField( controller: _usernameController, onChanged: (_) => _onFieldChanged(), decoration: InputDecoration( hintText: '请输入用户名', filled: true, fillColor: AppColors.surfaceSecondary, contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 14, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: AppColors.blue500, width: 1, ), ), ), ), const SizedBox(height: 20), const Text( '个人简介', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: AppColors.slate700, ), ), const SizedBox(height: 8), TextField( controller: _bioController, onChanged: (_) => _onFieldChanged(), maxLines: 4, maxLength: 200, decoration: InputDecoration( hintText: '介绍一下自己吧', filled: true, fillColor: AppColors.surfaceSecondary, contentPadding: const EdgeInsets.all(16), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: AppColors.blue500, width: 1, ), ), ), ), ], ), ); } }