523 lines
21 KiB
Dart
523 lines
21 KiB
Dart
import 'package:ef/ef.dart';
|
||
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:vbvs_app/common/color/appConstants.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/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);
|
||
}),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
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",
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|