210 lines
8.4 KiB
Dart
210 lines
8.4 KiB
Dart
import 'dart:io';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:image_picker/image_picker.dart';
|
||
|
||
import '../services/auth_service.dart';
|
||
import '../utils/constants.dart';
|
||
import 'activity_list_screen.dart';
|
||
|
||
class ProfileSetupScreen extends StatefulWidget {
|
||
const ProfileSetupScreen({super.key});
|
||
@override
|
||
State<ProfileSetupScreen> createState() => _ProfileSetupScreenState();
|
||
}
|
||
|
||
class _ProfileSetupScreenState extends State<ProfileSetupScreen> {
|
||
final _pageController = PageController();
|
||
int _currentStep = 0;
|
||
final _nicknameController = TextEditingController();
|
||
final ImagePicker _picker = ImagePicker();
|
||
String? _gender;
|
||
int? _birthYear;
|
||
XFile? _avatar;
|
||
final Set<String> _selectedInterests = {};
|
||
|
||
Future<void> _pickAvatar() async {
|
||
final XFile? avatar = await _picker.pickImage(source: ImageSource.gallery, imageQuality: 85);
|
||
if (avatar != null) {
|
||
setState(() => _avatar = avatar);
|
||
}
|
||
}
|
||
|
||
void _nextStep() {
|
||
if (_currentStep < 2) {
|
||
setState(() => _currentStep++);
|
||
_pageController.animateToPage(_currentStep, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
|
||
} else {
|
||
_finishSetup();
|
||
}
|
||
}
|
||
|
||
void _finishSetup() async {
|
||
await AuthService.updateProfile(
|
||
nickname: _nicknameController.text.trim().isEmpty ? null : _nicknameController.text.trim(),
|
||
birthYear: _birthYear,
|
||
gender: _gender,
|
||
interests: _selectedInterests.toList(),
|
||
);
|
||
if (mounted) {
|
||
Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => ActivityListScreen()));
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
title: Text('完善资料 (${_currentStep + 1}/3)'),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: _finishSetup,
|
||
child: const Text('跳过', style: TextStyle(fontSize: 16)),
|
||
),
|
||
],
|
||
),
|
||
body: PageView(
|
||
controller: _pageController,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
children: [
|
||
// Step 1: Nickname
|
||
Padding(
|
||
padding: const EdgeInsets.all(32),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
const Text('给自己取个昵称吧', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
|
||
const SizedBox(height: 8),
|
||
const Text('其他人将通过昵称认识您', style: TextStyle(fontSize: 16, color: Color(0xFF999999))),
|
||
const SizedBox(height: 32),
|
||
Center(
|
||
child: GestureDetector(
|
||
onTap: _pickAvatar,
|
||
child: CircleAvatar(
|
||
radius: 50,
|
||
backgroundImage: _avatar != null ? FileImage(File(_avatar!.path)) : null,
|
||
backgroundColor: const Color(0xFFE3F2FD),
|
||
child: _avatar == null ? const Icon(Icons.camera_alt, size: 32, color: Color(0xFF1976D2)) : null,
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
const Center(child: Text('点击设置头像', style: TextStyle(fontSize: 14, color: Color(0xFF999999)))),
|
||
const SizedBox(height: 24),
|
||
TextField(
|
||
controller: _nicknameController,
|
||
style: const TextStyle(fontSize: 20),
|
||
maxLength: 20,
|
||
decoration: const InputDecoration(hintText: '输入您的昵称', counterText: ''),
|
||
),
|
||
const Spacer(),
|
||
SizedBox(width: double.infinity, height: 52, child: ElevatedButton(onPressed: _nextStep, child: const Text('下一步'))),
|
||
],
|
||
),
|
||
),
|
||
// Step 2: Birth year + Gender
|
||
Padding(
|
||
padding: const EdgeInsets.all(32),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
const Text('基本信息', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
|
||
const SizedBox(height: 32),
|
||
const Text('性别', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600)),
|
||
const SizedBox(height: 12),
|
||
Row(
|
||
children: [
|
||
Expanded(child: _genderButton('男', 'male', Icons.male)),
|
||
const SizedBox(width: 16),
|
||
Expanded(child: _genderButton('女', 'female', Icons.female)),
|
||
],
|
||
),
|
||
const SizedBox(height: 32),
|
||
const Text('出生年份', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600)),
|
||
const SizedBox(height: 12),
|
||
DropdownButtonFormField<int>(
|
||
value: _birthYear,
|
||
style: const TextStyle(fontSize: 18, color: Color(0xFF333333)),
|
||
decoration: const InputDecoration(hintText: '选择出生年份'),
|
||
items: List.generate(50, (i) => 1945 + i)
|
||
.map((y) => DropdownMenuItem(value: y, child: Text('$y年')))
|
||
.toList(),
|
||
onChanged: (v) => setState(() => _birthYear = v),
|
||
),
|
||
const Spacer(),
|
||
SizedBox(width: double.infinity, height: 52, child: ElevatedButton(onPressed: _nextStep, child: const Text('下一步'))),
|
||
],
|
||
),
|
||
),
|
||
// Step 3: Interests
|
||
Padding(
|
||
padding: const EdgeInsets.all(32),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
const Text('选择您的兴趣', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
|
||
const SizedBox(height: 8),
|
||
const Text('至少选1个,最多5个', style: TextStyle(fontSize: 16, color: Color(0xFF999999))),
|
||
const SizedBox(height: 24),
|
||
Wrap(
|
||
spacing: 12, runSpacing: 12,
|
||
children: AppConstants.interestTags.map((tag) {
|
||
final selected = _selectedInterests.contains(tag);
|
||
return ChoiceChip(
|
||
label: Text(tag, style: TextStyle(fontSize: 16, color: selected ? Colors.white : const Color(0xFF666666))),
|
||
selected: selected,
|
||
selectedColor: const Color(0xFF1976D2),
|
||
backgroundColor: const Color(0xFFF5F5F5),
|
||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||
onSelected: (s) {
|
||
setState(() {
|
||
if (s && _selectedInterests.length < 5) {
|
||
_selectedInterests.add(tag);
|
||
} else {
|
||
_selectedInterests.remove(tag);
|
||
}
|
||
});
|
||
},
|
||
);
|
||
}).toList(),
|
||
),
|
||
const Spacer(),
|
||
SizedBox(
|
||
width: double.infinity, height: 52,
|
||
child: ElevatedButton(
|
||
onPressed: _selectedInterests.isNotEmpty ? _nextStep : null,
|
||
child: const Text('完成'),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _genderButton(String label, String value, IconData icon) {
|
||
final selected = _gender == value;
|
||
return GestureDetector(
|
||
onTap: () => setState(() => _gender = value),
|
||
child: Container(
|
||
height: 64,
|
||
decoration: BoxDecoration(
|
||
color: selected ? const Color(0xFFE3F2FD) : Colors.white,
|
||
borderRadius: BorderRadius.circular(12),
|
||
border: Border.all(color: selected ? const Color(0xFF1976D2) : const Color(0xFFDDDDDD), width: selected ? 2 : 1),
|
||
),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Icon(icon, color: selected ? const Color(0xFF1976D2) : const Color(0xFF999999), size: 28),
|
||
const SizedBox(width: 8),
|
||
Text(label, style: TextStyle(fontSize: 18, color: selected ? const Color(0xFF1976D2) : const Color(0xFF666666), fontWeight: selected ? FontWeight.w600 : FontWeight.normal)),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|