You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
660 lines
27 KiB
660 lines
27 KiB
import 'package:cached_network_image/cached_network_image.dart';
|
|
import 'package:dating_touchme_app/extension/ex_widget.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:dating_touchme_app/generated/assets.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:dating_touchme_app/controller/mine/user_info_controller.dart';
|
|
import 'package:tdesign_flutter/tdesign_flutter.dart';
|
|
|
|
class UserInfoPage extends StatefulWidget {
|
|
const UserInfoPage({super.key});
|
|
|
|
@override
|
|
_UserInfoState createState() => _UserInfoState();
|
|
}
|
|
|
|
class _UserInfoState extends State<UserInfoPage> {
|
|
|
|
// 显示头像选择选项
|
|
void _showAvatarPopup(UserInfoController controller){
|
|
Navigator.of(Get.context!).push(
|
|
TDSlidePopupRoute(
|
|
slideTransitionFrom: SlideTransitionFrom.bottom,
|
|
builder: (context) {
|
|
return Container(
|
|
// color: TDTheme.of(context).bgColorContainer,
|
|
height: 490,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.only(
|
|
topLeft: Radius.circular(12.0),
|
|
topRight: Radius.circular(12.0),
|
|
),
|
|
),
|
|
child: Column(
|
|
children: [
|
|
const SizedBox(height: 4),
|
|
CachedNetworkImage(imageUrl: 'https://dating-agency-prod.oss-cn-shenzhen.aliyuncs.com/1A437A945667.jpg', width: 375, height: 314),
|
|
const TDDivider(),
|
|
TDCell(
|
|
arrow: false,
|
|
titleWidget: Center(
|
|
child: Text('拍照', style: TextStyle(fontSize: 16.w, color: const Color.fromRGBO(51, 51, 51, 1))),
|
|
),
|
|
onClick: (cell) async{
|
|
Navigator.pop(context);
|
|
await controller.handleCameraCapture();
|
|
},
|
|
),
|
|
const TDDivider(),
|
|
TDCell(
|
|
arrow: false,
|
|
titleWidget: Center(
|
|
child: Text('从相册选择'),
|
|
),
|
|
onClick: (cell) async{
|
|
Navigator.pop(context);
|
|
await controller.handleGallerySelection();
|
|
},
|
|
),
|
|
Expanded(
|
|
child: Container(
|
|
color: Color(0xFFF3F3F3),
|
|
),
|
|
),
|
|
TDCell(
|
|
arrow: false,
|
|
titleWidget: Center(
|
|
child: Text('取消'),
|
|
),
|
|
onClick: (cell){
|
|
Navigator.pop(context);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
// 显示学历选择弹框
|
|
Future _showEducationPicker(UserInfoController controller) async {
|
|
final List<String> educationOptions = ['大专以下', '大专', '本科', '硕士及以上'];
|
|
|
|
await showModalBottomSheet(
|
|
context: Get.context!,
|
|
shape: const RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.only(
|
|
topLeft: Radius.circular(8),
|
|
topRight: Radius.circular(8),
|
|
),
|
|
),
|
|
builder: (BuildContext context) {
|
|
return Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white, // 明确设置背景色
|
|
borderRadius: const BorderRadius.only(
|
|
topLeft: Radius.circular(8),
|
|
topRight: Radius.circular(8),
|
|
),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// 标题和关闭按钮
|
|
Stack(
|
|
alignment: Alignment.center,
|
|
children: [
|
|
// 关闭按钮 - 左对齐
|
|
Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: IconButton(
|
|
icon: const Icon(Icons.close),
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
},
|
|
),
|
|
),
|
|
// 标题 - 居中
|
|
Text(
|
|
'学历',
|
|
style: const TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
|
|
// 学历选项列表
|
|
for (String education in educationOptions)
|
|
Container(
|
|
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), // 左右10,上下6
|
|
child: ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: controller.education.value == education
|
|
? const Color.fromRGBO(123, 104, 238, 1) // 紫色
|
|
: const Color.fromRGBO(247, 247, 247, 1),
|
|
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 25), // 增加水平内边距
|
|
minimumSize: const Size(double.infinity, 48), // 宽度充满,最小高度48
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(32),
|
|
),
|
|
elevation: 0,
|
|
),
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
controller.selectEducation(education);
|
|
},
|
|
child: Text(
|
|
education,
|
|
style: TextStyle(
|
|
color: controller.education.value == education ? Colors.white : Colors.black,
|
|
fontSize: 16,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
// 底部间距
|
|
const SizedBox(height: 20),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
// 显示日期选择器
|
|
Future _showDatePicker(UserInfoController controller) async {
|
|
// 计算最小和最大日期
|
|
final now = DateTime.now();
|
|
final maxDate = DateTime(now.year - 18); // 最小18岁
|
|
final minDate = DateTime(now.year - 80); // 最大80岁
|
|
|
|
// 初始选择日期(默认为25岁)
|
|
DateTime initialDate = DateTime(now.year - 25);
|
|
if (controller.birthday.value.isNotEmpty) {
|
|
try {
|
|
final List<String> dateParts = controller.birthday.value.split('-');
|
|
if (dateParts.length == 3) {
|
|
initialDate = DateTime(
|
|
int.parse(dateParts[0]),
|
|
int.parse(dateParts[1]),
|
|
int.parse(dateParts[2]),
|
|
);
|
|
// 确保初始日期在有效范围内
|
|
if (initialDate.isBefore(minDate)) initialDate = minDate;
|
|
if (initialDate.isAfter(maxDate)) initialDate = maxDate;
|
|
}
|
|
} catch (e) {
|
|
print('解析日期失败: $e');
|
|
}
|
|
}
|
|
|
|
// 临时存储选择的日期
|
|
DateTime? selectedDate = initialDate;
|
|
|
|
await showCupertinoModalPopup(
|
|
context: Get.context!,
|
|
builder: (BuildContext context) {
|
|
return Container(
|
|
height: 300,
|
|
color: CupertinoColors.white,
|
|
child: Column(
|
|
children: [
|
|
// 头部按钮区域
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
CupertinoButton(
|
|
child: const Text('取消'),
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
},
|
|
),
|
|
CupertinoButton(
|
|
child: const Text('确定'),
|
|
onPressed: () {
|
|
Navigator.pop(context);
|
|
if (selectedDate != null) {
|
|
// 格式化为YYYY-MM-DD
|
|
final formattedDate = '${selectedDate!.year}-'
|
|
'${selectedDate!.month.toString().padLeft(2, '0')}-'
|
|
'${selectedDate!.day.toString().padLeft(2, '0')}';
|
|
controller.selectBirthday(formattedDate);
|
|
}
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
// 日期选择器
|
|
Expanded(
|
|
child: CupertinoDatePicker(
|
|
mode: CupertinoDatePickerMode.date,
|
|
initialDateTime: initialDate,
|
|
minimumDate: minDate,
|
|
maximumDate: maxDate,
|
|
onDateTimeChanged: (DateTime dateTime) {
|
|
selectedDate = dateTime;
|
|
},
|
|
use24hFormat: true,
|
|
backgroundColor: CupertinoColors.white,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
final FocusNode _blankFocusNode = FocusNode();
|
|
final TextEditingController _controller = TextEditingController();
|
|
final FocusNode _blankFocusNode2 = FocusNode();
|
|
final TextEditingController _controller2 = TextEditingController();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GetX<UserInfoController>(
|
|
init: UserInfoController(),
|
|
builder: (controller) {
|
|
return Scaffold(
|
|
extendBodyBehindAppBar: true,
|
|
appBar: AppBar(
|
|
title: const Text(
|
|
'完善信息',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: Color.fromRGBO(51, 51, 51, 1),
|
|
),
|
|
),
|
|
backgroundColor: Colors.transparent,
|
|
shadowColor: Colors.transparent,
|
|
elevation: 0,
|
|
centerTitle: true,
|
|
automaticallyImplyLeading: false,
|
|
),
|
|
body: Stack(
|
|
children: [
|
|
// 背景图 - 覆盖全页面包括AppBar
|
|
Image.asset(
|
|
Assets.imagesBgInformation,
|
|
fit: BoxFit.cover,
|
|
width: double.infinity,
|
|
height: double.infinity,
|
|
),
|
|
// 内容区域,顶部留出AppBar高度空间
|
|
SafeArea(
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
|
child: Column(
|
|
children: [
|
|
const SizedBox(height: 25),
|
|
// 头像
|
|
GestureDetector(
|
|
onTap: () => _showAvatarPopup(controller),
|
|
child: Stack(
|
|
children: [
|
|
Container(
|
|
width: 85,
|
|
height: 85,
|
|
decoration: const BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.grey,
|
|
),
|
|
child: ClipOval(
|
|
child: (controller.avatarUrl.value.startsWith('http')
|
|
? Image.network(
|
|
controller.avatarUrl.value,
|
|
fit: BoxFit.cover,
|
|
)
|
|
: Image.asset(
|
|
Assets.imagesUserAvatar,
|
|
fit: BoxFit.cover,
|
|
)),
|
|
),
|
|
),
|
|
Positioned(
|
|
bottom: 0,
|
|
right: 0,
|
|
child: Container(
|
|
width: 20,
|
|
height: 20,
|
|
child: Stack(
|
|
children: [
|
|
Center(
|
|
child: Image.asset(
|
|
Assets.imagesBgEditAvatars,
|
|
),
|
|
),
|
|
Center(
|
|
child: Image.asset(
|
|
Assets.imagesEditAvatarsIcon,
|
|
width: 12,
|
|
height: 12,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 25),
|
|
|
|
// 性别选择
|
|
const Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'性别 (注册后不可修改)',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
color: Color.fromRGBO(144, 144, 144, 1),
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
Row(
|
|
children: [
|
|
GestureDetector(
|
|
onTap: () => controller.selectGender('male'),
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(20),
|
|
color: controller.gender.value == 'male' ? Colors.black : Colors.grey[200],
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Image.asset(
|
|
Assets.imagesManIcon,
|
|
width: 20,
|
|
height: 20,
|
|
color: controller.gender.value == 'male' ? Colors.white : Colors.black,
|
|
),
|
|
const SizedBox(width: 5),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 20),
|
|
GestureDetector(
|
|
onTap: () => controller.selectGender('female'),
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(20),
|
|
color: controller.gender.value == 'female' ? Colors.pink : Colors.grey[200],
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Image.asset(
|
|
Assets.imagesWomenIcon,
|
|
width: 20,
|
|
height: 20,
|
|
color: controller.gender.value == 'female' ? Colors.white : Colors.black,
|
|
),
|
|
const SizedBox(width: 5),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
// 昵称
|
|
const Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'昵称',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
color: Color.fromRGBO(144, 144, 144, 1),
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(32),
|
|
color: Color.fromRGBO(247, 247, 247, 1),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: TextField(
|
|
focusNode: _blankFocusNode,
|
|
controller: _controller,
|
|
onChanged: (value) {
|
|
controller.nickname.value = value;
|
|
},
|
|
onTapOutside: (e){
|
|
_blankFocusNode.unfocus();
|
|
},
|
|
onTap: (){
|
|
// 确保光标在文本末尾
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
_controller.selection = TextSelection.fromPosition(
|
|
TextPosition(offset: _controller.text.length),
|
|
);
|
|
});
|
|
},
|
|
decoration: const InputDecoration(
|
|
border: InputBorder.none,
|
|
hintText: '请输入昵称',
|
|
hintStyle: TextStyle(color: Colors.grey),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
// 出生日期
|
|
const Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'年龄',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
color: Color.fromRGBO(144, 144, 144, 1),
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
GestureDetector(
|
|
onTap: () async {
|
|
// FocusScope.of(context).requestFocus(_blankFocusNode);
|
|
// 显示Cupertino日期选择器
|
|
// _blankFocusNode.unfocus();
|
|
await _showDatePicker(controller);
|
|
},
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(32),
|
|
color: Color.fromRGBO(247, 247, 247, 1),
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
controller.birthday.value.isEmpty ? '请选择你的出生日期' : controller.birthday.value,
|
|
style: TextStyle(
|
|
color: controller.birthday.value.isEmpty ? Colors.grey : Colors.black,
|
|
),
|
|
),
|
|
Image.asset(
|
|
Assets.imagesArrowForwardRight,
|
|
width: 5,
|
|
height: 10,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
// 学历
|
|
const Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'学历',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
color: Color.fromRGBO(144, 144, 144, 1),
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
GestureDetector(
|
|
onTap: () async {
|
|
// FocusScope.of(context).requestFocus(_blankFocusNode);
|
|
// _blankFocusNode.unfocus();
|
|
// 显示学历选择弹框
|
|
await _showEducationPicker(controller);
|
|
},
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(32),
|
|
color: Color.fromRGBO(247, 247, 247, 1),
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
controller.education.value.isEmpty ? '请选择你的学历' : controller.education.value,
|
|
style: TextStyle(
|
|
color: controller.education.value.isEmpty ? Colors.grey : Colors.black,
|
|
),
|
|
),
|
|
Image.asset(
|
|
Assets.imagesArrowForwardRight,
|
|
width: 5,
|
|
height: 10,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
// 邀请码
|
|
const Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'邀请码 (非必填)',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
color: Color.fromRGBO(144, 144, 144, 1),
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(32),
|
|
color: Color.fromRGBO(247, 247, 247, 1),
|
|
),
|
|
child: TextField(
|
|
focusNode: _blankFocusNode2,
|
|
controller: _controller2,
|
|
onChanged: (value) {
|
|
controller.invitationCode.value = value;
|
|
},
|
|
onTapOutside: (e){
|
|
_blankFocusNode2.unfocus();
|
|
},
|
|
onTap: (){
|
|
// 确保光标在文本末尾
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
_controller2.selection = TextSelection.fromPosition(
|
|
TextPosition(offset: _controller2.text.length),
|
|
);
|
|
});
|
|
},
|
|
decoration: const InputDecoration(
|
|
hintText: '请输入邀请码',
|
|
hintStyle: TextStyle(color: Colors.grey),
|
|
border: InputBorder.none,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 24),
|
|
|
|
// 开始交友按钮
|
|
SizedBox(
|
|
width: double.infinity,
|
|
height: 50,
|
|
child: ElevatedButton(
|
|
onPressed: controller.isSubmitting.value
|
|
? null
|
|
: controller.submitUserInfo,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.blue,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(25),
|
|
),
|
|
),
|
|
child: controller.isSubmitting.value
|
|
? const SizedBox(
|
|
width: 20,
|
|
height: 20,
|
|
child: CircularProgressIndicator(
|
|
color: Colors.white,
|
|
strokeWidth: 2,
|
|
),
|
|
)
|
|
: const Text(
|
|
'开始交友',
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
// TODO: implement dispose
|
|
super.dispose();
|
|
_blankFocusNode.dispose();
|
|
_controller.dispose();
|
|
_blankFocusNode2.dispose();
|
|
_controller2.dispose();
|
|
}
|
|
}
|