import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:airhub_app/theme/design_tokens.dart'; import 'package:airhub_app/widgets/animated_gradient_background.dart'; import 'package:airhub_app/widgets/ios_toast.dart'; import 'package:image_picker/image_picker.dart'; import 'dart:io'; class ProfileInfoPage extends StatefulWidget { const ProfileInfoPage({super.key}); @override State createState() => _ProfileInfoPageState(); } class _ProfileInfoPageState extends State { String _gender = '男'; String _birthday = '1994-12-09'; File? _avatarImage; final TextEditingController _nicknameController = TextEditingController( text: '土豆', ); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.transparent, body: Stack( children: [ // 动态渐变背景 const AnimatedGradientBackground(), Column( children: [ _buildHeader(context), Expanded( child: SingleChildScrollView( padding: EdgeInsets.only( top: 20, left: AppSpacing.lg, right: AppSpacing.lg, bottom: 40 + MediaQuery.of(context).padding.bottom, ), child: Column( children: [ const SizedBox(height: 20), _buildAvatarSection(), const SizedBox(height: 32), _buildFormCard(), ], ), ), ), ], ), ], ), ); } Widget _buildHeader(BuildContext context) { return Container( padding: EdgeInsets.only( top: MediaQuery.of(context).padding.top + 20, left: AppSpacing.lg, right: AppSpacing.lg, bottom: AppSpacing.md, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildBackButton(context), Text('个人信息', style: AppTextStyles.title), _buildSaveButton(), ], ), ); } Widget _buildBackButton(BuildContext context) { return GestureDetector( onTap: () => Navigator.pop(context), child: Container( width: 40, height: 40, decoration: BoxDecoration( color: AppColors.iconBtnBg, borderRadius: BorderRadius.circular(AppRadius.button), ), child: const Icon( Icons.arrow_back_ios_new, color: AppColors.textPrimary, size: 18, ), ), ); } Widget _buildSaveButton() { return GestureDetector( onTap: () { // Save logic - show success toast AppToast.show(context, '保存成功'); Navigator.pop(context); }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), decoration: BoxDecoration( gradient: const LinearGradient( colors: AppColors.saveBtnGradient, begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(20), ), child: const Text( '保存', style: TextStyle( color: Colors.white, fontWeight: FontWeight.w600, fontSize: 14, ), ), ), ); } Widget _buildAvatarSection() { return Stack( children: [ Container( width: 100, height: 100, decoration: const BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: AppColors.avatarGradient, begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: Color(0x338B5E3C), // rgba(139, 94, 60, 0.2) blurRadius: 24, offset: Offset(0, 8), ), ], ), child: ClipOval( child: _avatarImage != null ? Image.file(_avatarImage!, fit: BoxFit.cover) : Image.asset( 'assets/www/Capybara.png', fit: BoxFit.cover, errorBuilder: (ctx, err, stack) => const Icon(Icons.person, color: Colors.white, size: 40), ), ), ), Positioned( bottom: 0, right: 0, child: GestureDetector( onTap: _pickImage, child: Container( width: 32, height: 32, decoration: BoxDecoration( gradient: const LinearGradient( colors: AppColors.saveBtnGradient, ), shape: BoxShape.circle, border: Border.all(color: Colors.white, width: 3), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.15), offset: const Offset(0, 2), blurRadius: 8, ), ], ), child: const Icon( Icons.camera_alt, color: Colors.white, size: 14, ), ), ), ), ], ); } Future _pickImage() async { try { final ImagePicker picker = ImagePicker(); final XFile? image = await picker.pickImage(source: ImageSource.gallery); if (image != null) { setState(() { _avatarImage = File(image.path); }); } } catch (e) { if (mounted) { AppToast.show(context, '选择图片失败: $e', isError: true); } } } Widget _buildFormCard() { return Container( decoration: BoxDecoration( color: AppColors.cardSurface, borderRadius: BorderRadius.circular(AppRadius.card), boxShadow: const [AppShadows.card], ), child: Column( children: [ _buildInputItem('昵称', _nicknameController), _buildSelectionItem('性别', _gender, onTap: _showGenderModal), _buildSelectionItem( '生日', _birthday, showDivider: false, onTap: _showBirthdayInput, ), ], ), ); } Widget _buildInputItem(String label, TextEditingController controller) { return Container( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.lg, vertical: 18, ), decoration: const BoxDecoration( border: Border(bottom: BorderSide(color: AppColors.divider)), ), child: Row( children: [ SizedBox( width: 80, child: Text( label, style: const TextStyle(color: AppColors.formLabel, fontSize: 15), ), ), Expanded( child: TextField( controller: controller, textAlign: TextAlign.right, decoration: const InputDecoration.collapsed( hintText: '请输入', hintStyle: TextStyle(color: AppColors.textHint), ), style: const TextStyle( color: AppColors.textPrimary, fontSize: 15, ), ), ), ], ), ); } Widget _buildSelectionItem( String label, String value, { bool showDivider = true, VoidCallback? onTap, }) { return InkWell( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.lg, vertical: 18, ), decoration: showDivider ? const BoxDecoration( border: Border(bottom: BorderSide(color: AppColors.divider)), ) : null, child: Row( children: [ SizedBox( width: 80, child: Text( label, style: const TextStyle( color: AppColors.formLabel, fontSize: 15, ), ), ), Expanded( child: Text( value, textAlign: TextAlign.right, style: const TextStyle( color: AppColors.textPrimary, fontSize: 15, ), ), ), const SizedBox(width: 8), const Icon( Icons.chevron_right, color: AppColors.textHint, size: 18, ), ], ), ), ); } void _showGenderModal() { showModalBottomSheet( context: context, backgroundColor: Colors.transparent, builder: (context) => Container( padding: const EdgeInsets.fromLTRB(20, 24, 20, 20), decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFFFFFDF9), // warm white top Color(0xFFFFF8F0), // slightly warmer bottom ], ), borderRadius: BorderRadius.vertical(top: Radius.circular(24)), boxShadow: [ BoxShadow( color: Color(0x148B5E3C), blurRadius: 20, offset: Offset(0, -4), ), ], ), child: SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ // Handle bar Container( width: 36, height: 4, decoration: BoxDecoration( color: const Color(0xFFE8C9A8), borderRadius: BorderRadius.circular(2), ), ), const SizedBox(height: 20), Text('选择性别', style: AppTextStyles.title), const SizedBox(height: 24), // Male option _buildGenderOption('男'), const SizedBox(height: 12), // Female option _buildGenderOption('女'), const SizedBox(height: 16), // Cancel GestureDetector( onTap: () => Navigator.pop(context), child: Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 14), decoration: BoxDecoration( color: const Color(0xFFF5F0EB), borderRadius: BorderRadius.circular(16), ), alignment: Alignment.center, child: const Text( '取消', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFF6B7280), ), ), ), ), ], ), ), ), ); } Widget _buildGenderOption(String label) { final isSelected = _gender == label; return GestureDetector( onTap: () { setState(() => _gender = label); Navigator.pop(context); }, child: AnimatedContainer( duration: const Duration(milliseconds: 200), width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 16), decoration: BoxDecoration( color: isSelected ? const Color(0xFFFFF5EB) // warm selected bg : Colors.white.withOpacity(0.8), borderRadius: BorderRadius.circular(16), border: Border.all( color: isSelected ? const Color(0xFFECCFA8) // warm gold border : const Color(0xFFE5E7EB), width: isSelected ? 1.5 : 1, ), boxShadow: isSelected ? [ BoxShadow( color: const Color(0xFFECCFA8).withOpacity(0.25), blurRadius: 12, offset: const Offset(0, 4), ), ] : null, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( label, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: isSelected ? const Color(0xFFB07D5A) // warm brown text : const Color(0xFF374151), ), ), ], ), ), ); } // iOS-style wheel date picker void _showBirthdayInput() { DateTime tempDate = DateTime.tryParse(_birthday) ?? DateTime(1994, 12, 9); showModalBottomSheet( context: context, backgroundColor: Colors.transparent, builder: (context) => Container( height: 340, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFFFFFDF9), Color(0xFFFFF8F0), ], ), borderRadius: BorderRadius.vertical(top: Radius.circular(24)), boxShadow: [ BoxShadow( color: Color(0x148B5E3C), blurRadius: 20, offset: Offset(0, -4), ), ], ), child: Column( children: [ // Header Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), decoration: const BoxDecoration( border: Border( bottom: BorderSide(color: Color(0x0D000000)), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( onTap: () => Navigator.pop(context), child: const Text( '取消', style: TextStyle( fontSize: 16, color: Color(0xFF6B7280), ), ), ), Text( '选择生日', style: AppTextStyles.title.copyWith(fontSize: 17), ), GestureDetector( onTap: () { setState(() { _birthday = "${tempDate.year}-${tempDate.month.toString().padLeft(2, '0')}-${tempDate.day.toString().padLeft(2, '0')}"; }); Navigator.pop(context); }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( gradient: const LinearGradient( colors: AppColors.saveBtnGradient, ), borderRadius: BorderRadius.circular(16), ), child: const Text( '确定', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white, ), ), ), ), ], ), ), // Cupertino date picker wheel Expanded( child: CupertinoTheme( data: const CupertinoThemeData( textTheme: CupertinoTextThemeData( dateTimePickerTextStyle: TextStyle( fontSize: 20, color: Color(0xFF374151), ), ), ), child: CupertinoDatePicker( mode: CupertinoDatePickerMode.date, initialDateTime: tempDate, minimumDate: DateTime(1900), maximumDate: DateTime.now(), onDateTimeChanged: (DateTime date) { tempDate = date; }, ), ), ), ], ), ), ); } }