Files
tuiche/lib/pages/person/select_time.dart
2025-11-21 10:34:18 +08:00

824 lines
36 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'dart:typed_data';
import 'package:ef/ef.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/pojo/city.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/language/AppLanguage.dart';
import 'package:vbvs_app/pages/common/selectDialog.dart';
// Future showDateSelectionDialog(BuildContext context,
// {required DateTime checkDate, Function? checkChange, String title = "生日"}) {
// ThemeController themeController = Get.find();
// List years = [], months = [], days = [];
// var days_select = [].obs;
// int day_len = 31;
// int year = DateTime.now().year;
// for (var i = 0; i < 100; i++) {
// years.insert(0, year - i);
// }
// for (var i = 1; i < 13; i++) {
// months.add(i);
// }
// for (var i = 1; i < 32; i++) {
// days.add(i);
// }
// int yearIndex = years.lastIndexOf(checkDate.year);
// int monthIndex = months.lastIndexOf(checkDate.month);
// day_len = DateTime.fromMillisecondsSinceEpoch(
// DateTime(years[yearIndex], months[monthIndex] + 1)
// .millisecondsSinceEpoch -
// 1000)
// .day;
// days_select.value = days.sublist(0, day_len);
// int dayIndex = days.lastIndexOf(checkDate.day);
// return showDialog(
// context: context,
// barrierDismissible: true, // 点击对话框外部可关闭
// builder: (BuildContext context) {
// return Stack(
// children: [
// Positioned(
// bottom: 0, // 控制弹窗距离顶部的位置
// left: 0,
// right: 0,
// child: Material(
// color: Colors.transparent,
// child: Dialog(
// backgroundColor: themeController.currentColor.sc17,
// insetPadding: EdgeInsets.zero,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(0),
// ),
// child: Container(
// width: double.infinity,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.only(
// topLeft: Radius.circular(
// AppConstants().normal_container_radius),
// topRight: Radius.circular(
// AppConstants().normal_container_radius),
// bottomLeft: Radius.circular(0.rpx),
// bottomRight: Radius.circular(0.rpx),
// ),
// ),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.center,
// children: <Widget>[
// Container(
// color: themeController.currentColor.sc5,
// alignment: Alignment.centerLeft,
// height: 80.rpx,
// child: Padding(
// padding: EdgeInsets.only(left: 30.rpx, right: 30.rpx),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// crossAxisAlignment: CrossAxisAlignment.center,
// children: [
// InkWell(
// child: Text(
// "日期.取消".tr,
// style: TextStyle(
// fontFamily: 'Readex Pro',
// color: themeController.currentColor.sc3,
// letterSpacing: 0,
// fontSize:
// AppConstants().normal_text_fontSize),
// ),
// onTap: () {
// Get.back();
// },
// ),
// Text(
// "$title",
// style: TextStyle(
// fontFamily: 'Readex Pro',
// color: themeController.currentColor.sc3,
// letterSpacing: 0,
// fontSize:
// AppConstants().title_text_fontSize),
// ),
// // closeIconWhite,
// InkWell(
// child: Text(
// "日期.确定".tr,
// style: TextStyle(
// fontFamily: 'Readex Pro',
// color: themeController.currentColor.sc2,
// letterSpacing: 0,
// fontSize:
// AppConstants().normal_text_fontSize),
// ),
// onTap: () {
// checkChange?.call(DateTime(years[yearIndex],
// months[monthIndex], days[dayIndex]));
// Get.back();
// },
// )
// ],
// ),
// ),
// ),
// // Container(
// // height: 240.rpx,
// // margin: EdgeInsets.only(top: 60.rpx, bottom: 60.rpx),
// // padding: EdgeInsets.symmetric(horizontal: 30.rpx),
// // child: Row(
// // mainAxisAlignment: MainAxisAlignment.center, // ✅ 整体居中
// // crossAxisAlignment: CrossAxisAlignment.center,
// // children: [
// // Row(
// // children: [
// // SizedBox(
// // width: 120.rpx,
// // child: getOnePicker(context, years, yearIndex,
// // (d) {
// // yearIndex = d;
// // dayIndex = 0;
// // day_len =
// // DateTime.fromMillisecondsSinceEpoch(
// // DateTime(
// // years[yearIndex],
// // months[monthIndex] +
// // 1)
// // .millisecondsSinceEpoch -
// // 1000)
// // .day;
// // days_select.value =
// // days.sublist(0, day_len);
// // }, "".tr),
// // ),
// // ],
// // ),
// // SizedBox(width: 100.rpx),
// // // 月
// // Row(
// // children: [
// // SizedBox(
// // width: 80.rpx,
// // child: getOnePicker(
// // context, months, monthIndex, (d) {
// // monthIndex = d;
// // dayIndex = 0;
// // day_len =
// // DateTime.fromMillisecondsSinceEpoch(
// // DateTime(
// // years[yearIndex],
// // months[monthIndex] +
// // 1)
// // .millisecondsSinceEpoch -
// // 1000)
// // .day;
// // days_select.value =
// // days.sublist(0, day_len);
// // }, "".tr),
// // ),
// // ],
// // ),
// // SizedBox(width: 100.rpx),
// // Row(
// // children: [
// // SizedBox(
// // width: 80.rpx,
// // child: Obx(() {
// // return getOnePicker(
// // context, days_select, dayIndex, (d) {
// // dayIndex = d;
// // }, "".tr);
// // }),
// // ),
// // ],
// // ),
// // ],
// // ),
// // )
// //-----
// Container(
// height: 240.rpx,
// margin: EdgeInsets.only(top: 60.rpx, bottom: 60.rpx),
// padding: EdgeInsets.symmetric(horizontal: 30.rpx),
// child: Stack(
// children: [
// // ✅ 选中行背景色
// Positioned.fill(
// child: IgnorePointer(
// child: Center(
// child: Container(
// height: 90.rpx, // 对齐选中行高度
// margin: EdgeInsets.symmetric(
// horizontal: 10.rpx),
// decoration: BoxDecoration(
// color: themeController.currentColor.sc2,
// borderRadius:
// BorderRadius.circular(16.rpx),
// ),
// ),
// ),
// ),
// ),
// // ✅ 三列 Picker
// Row(
// mainAxisAlignment:
// MainAxisAlignment.center, // 整体居中
// crossAxisAlignment: CrossAxisAlignment.center,
// children: [
// // 年
// SizedBox(
// width: 120.rpx,
// child: getOnePicker(context, years, yearIndex,
// (d) {
// yearIndex = d;
// dayIndex = 0;
// day_len =
// DateTime.fromMillisecondsSinceEpoch(
// DateTime(
// years[yearIndex],
// months[monthIndex] +
// 1)
// .millisecondsSinceEpoch -
// 1000)
// .day;
// days_select.value =
// days.sublist(0, day_len);
// }, "".tr),
// ),
// SizedBox(width: 100.rpx),
// // 月
// SizedBox(
// width: 80.rpx,
// child: getOnePicker(
// context, months, monthIndex, (d) {
// monthIndex = d;
// dayIndex = 0;
// day_len =
// DateTime.fromMillisecondsSinceEpoch(
// DateTime(
// years[yearIndex],
// months[monthIndex] +
// 1)
// .millisecondsSinceEpoch -
// 1000)
// .day;
// days_select.value =
// days.sublist(0, day_len);
// }, "".tr),
// ),
// SizedBox(width: 100.rpx),
// // 日
// SizedBox(
// width: 80.rpx,
// child: Obx(() {
// return getOnePicker(
// context, days_select, dayIndex, (d) {
// dayIndex = d;
// }, "".tr);
// }),
// ),
// ],
// ),
// ],
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// ),
// ],
// );
// },
// );
// }
Future showDateSelectionDialog(BuildContext context,
{required DateTime checkDate,
Function? checkChange,
String title = "选择生日"}) {
ThemeController themeController = Get.find();
final bool isEn = Get.locale?.languageCode.startsWith('en') ?? false;
Color checkColor = stringToColor("#D3B684");
final List<int> years = List.generate(100, (i) => DateTime.now().year - i)
..sort();
final List<int> months = List.generate(12, (i) => i + 1);
final List<int> days = List.generate(31, (i) => i + 1);
final RxList<int> daysSelect = <int>[].obs;
final RxInt yearIndex = years.indexOf(checkDate.year).obs;
final RxInt monthIndex = months.indexOf(checkDate.month).obs;
final RxInt dayIndex = days.indexOf(checkDate.day).obs;
void updateDays() {
final int daysInMonth =
DateTime(years[yearIndex.value], months[monthIndex.value] + 1, 0).day;
daysSelect.value = days.sublist(0, daysInMonth);
if (dayIndex.value >= daysInMonth) {
dayIndex.value = daysInMonth - 1;
}
}
updateDays();
return showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return Stack(
children: [
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Material(
color: Colors.transparent,
child: Dialog(
backgroundColor: themeController.currentColor.sc17,
insetPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
child: Container(
width: double.infinity,
padding: EdgeInsets.fromLTRB(30.rpx, 10.rpx, 30.rpx, 90.rpx),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
padding: EdgeInsets.zero,
onTap: () => Navigator.of(context).pop(),
child: Container(
width: 110.rpx,
height: 60.rpx,
alignment: Alignment.center,
child: Text("取消".tr,
style: TextStyle(
fontSize: 30.rpx, color: Colors.white)),
),
),
Text(
title,
style: TextStyle(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
fontSize: 30.rpx,
),
),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
padding: EdgeInsets.zero,
onTap: () {
final selectedDate = DateTime(
years[yearIndex.value],
months[monthIndex.value],
daysSelect[dayIndex.value],
);
checkChange?.call(selectedDate);
Get.back();
},
child: Container(
width: 110.rpx,
height: 60.rpx,
alignment: Alignment.center,
child: Text("确定".tr,
style: TextStyle(
fontSize: 30.rpx,
color: themeController.currentColor.sc2,
)),
),
),
],
),
SizedBox(height: 20.rpx),
Stack(
children: [
Positioned.fill(
child: IgnorePointer(
child: Center(
child: Container(
height: 90.rpx,
margin:
EdgeInsets.symmetric(horizontal: 70.rpx),
decoration: BoxDecoration(
color: themeController.currentColor.sc2,
borderRadius: BorderRadius.circular(16.rpx),
),
),
),
),
),
SizedBox(
height: 240.rpx,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 95.rpx),
child: Row(
children: isEn
? [
Expanded(
child: getOnePickers(
context,
months,
monthIndex,
isMonthName: true,
onChanged: (_) => updateDays(),
),
),
Expanded(
child: getOnePickers(
context,
daysSelect,
dayIndex,
),
),
Expanded(
child: getOnePickers(
context,
years,
yearIndex,
onChanged: (_) => updateDays(),
),
),
]
: [
Expanded(
child: getOnePickers(
context,
years,
yearIndex,
unit: "",
onChanged: (_) => updateDays(),
),
),
Expanded(
child: getOnePickers(
context,
months,
monthIndex,
unit: "",
onChanged: (_) => updateDays(),
),
),
Expanded(
child: getOnePickers(
context,
daysSelect,
dayIndex,
unit: "",
),
),
],
),
),
),
],
),
],
),
),
),
),
),
],
);
},
);
}
TextStyle _unitStyle(BuildContext context) {
return TextStyle(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
fontSize: 30.rpx,
letterSpacing: 0,
);
}
getOnePicker(BuildContext context, List arr, int checkIndex,
Function onSelectedItemChanged, String unit,
{bool looping = false}) {
ThemeController themeController = Get.find();
return CupertinoPicker(
key: UniqueKey(),
useMagnifier: false,
itemExtent: 80.rpx,
magnification: 1,
diameterRatio: 3,
squeeze: 1,
looping: looping,
scrollController: FixedExtentScrollController(initialItem: checkIndex),
selectionOverlay: Container(), // 不要默认选中遮罩
onSelectedItemChanged: (int value) {
onSelectedItemChanged.call(value);
},
children: List.generate(arr.length, (index) {
return Container(
alignment: Alignment.center,
child: Text(
"${arr[index]}$unit", // ✅ 每项都带单位
style: TextStyle(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
fontSize: 30.rpx,
),
),
);
}),
);
}
Future<void> showHeightPickerDialog(
BuildContext context, {
required int initialHeight, // 初始身高单位cm
required Function(int selectedHeight) onConfirm,
String title = "选择身高",
}) async {
List<int> heights = List.generate(101, (index) => 120 + index); // 120~220cm
int selectedIndex = heights.indexOf(initialHeight);
// int tempIndex = selectedIndex;
final RxInt tempIndex = RxInt(selectedIndex); // ✅ 改为 RxInt
ThemeController themeController = Get.find();
await showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return Stack(
children: [
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Material(
color: Colors.transparent,
child: Dialog(
backgroundColor: themeController.currentColor.sc17,
insetPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
child: Container(
padding: EdgeInsets.fromLTRB(0.rpx, 0.rpx, 0.rpx, 90.rpx),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding:
EdgeInsets.fromLTRB(30.rpx, 0.rpx, 30.rpx, 0.rpx),
color: themeController.currentColor.sc5,
height: 80.rpx,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
padding: EdgeInsets.only(top: 0),
onTap: () {
Get.back();
},
child: Container(
alignment: Alignment.center,
width: 110.rpx,
height: 60.rpx,
child: Text(
"取消".tr,
style: TextStyle(
fontSize: 30.rpx,
color: Colors.white,
),
),
)),
Text(title,
style: TextStyle(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
fontSize: 30.rpx,
)),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
padding: EdgeInsets.only(top: 0),
onTap: () {
onConfirm(
heights[tempIndex.value]); // ✅ 使用 .value
Get.back();
},
child: Container(
alignment: Alignment.center,
width: 110.rpx,
height: 60.rpx,
child: Text(
"确定".tr,
style: TextStyle(
fontSize: 30.rpx,
color: themeController.currentColor.sc2,
),
),
)),
],
),
),
SizedBox(height: 20.rpx),
Stack(
children: [
Positioned.fill(
child: IgnorePointer(
child: Center(
child: Container(
height: 90.rpx,
margin:
EdgeInsets.symmetric(horizontal: 95.rpx),
decoration: BoxDecoration(
color: themeController.currentColor.sc2,
borderRadius: BorderRadius.circular(16.rpx),
),
),
),
),
),
SizedBox(
height: 240.rpx,
child: getOnePickers(
context,
heights,
tempIndex, // ✅ 传入 RxInt
unit: "cm",
),
),
],
),
],
),
),
),
),
),
],
);
},
);
}
Future<void> showWeightPickerDialog(
BuildContext context, {
required String initialWeight, // 初始体重单位kg
required Function(int selectedWeight) onConfirm,
String title = "选择体重",
}) async {
List<int> weights = List.generate(151, (index) => 30 + index); // 30~180kg
int selectedIndex = weights.indexOf(int.tryParse(initialWeight) ?? 50);
final RxInt tempIndex = RxInt(selectedIndex); // ✅ 改为 RxInt
ThemeController themeController = Get.find();
await showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return Stack(
children: [
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Material(
color: Colors.transparent,
child: Dialog(
backgroundColor: themeController.currentColor.sc17,
insetPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
child: Container(
padding: EdgeInsets.fromLTRB(0.rpx, 0.rpx, 0.rpx, 90.rpx),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 标题 + 按钮
Container(
padding:
EdgeInsets.fromLTRB(30.rpx, 0.rpx, 30.rpx, 0.rpx),
color: themeController.currentColor.sc5,
height: 80.rpx,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
padding: EdgeInsets.only(top: 0),
onTap: () {
Navigator.of(context).pop();
},
child: Container(
alignment: Alignment.center,
width: 110.rpx,
height: 60.rpx,
child: Text(
"取消".tr,
style: TextStyle(
fontSize: 30.rpx,
color: Colors.white,
),
),
)),
Text(title.tr,
style: TextStyle(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
fontSize: 30.rpx,
)),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.transparent,
padding: EdgeInsets.only(top: 0),
onTap: () {
onConfirm(
weights[tempIndex.value]); // ✅ 回调返回选中值
Get.back();
},
child: Container(
alignment: Alignment.center,
width: 110.rpx,
height: 60.rpx,
child: Text(
"确定".tr,
style: TextStyle(
fontSize: 30.rpx,
color: themeController.currentColor.sc2,
),
),
)),
],
),
),
SizedBox(height: 20.rpx),
Stack(
children: [
Positioned.fill(
child: IgnorePointer(
child: Center(
child: Container(
height: 90.rpx,
margin:
EdgeInsets.symmetric(horizontal: 95.rpx),
decoration: BoxDecoration(
color: themeController.currentColor.sc2,
borderRadius: BorderRadius.circular(16.rpx),
),
),
),
),
),
SizedBox(
height: 240.rpx,
child: getOnePickers(
context,
weights,
tempIndex, // ✅ 传入 RxInt
unit: "kg",
),
),
],
),
],
),
),
),
),
),
],
);
},
);
}