2080 lines
79 KiB
Dart
2080 lines
79 KiB
Dart
import 'package:ef/ef.dart';
|
||
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutterflow_ui/flutterflow_ui.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/base/SleepCalendarWidget.dart';
|
||
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||
import 'package:vbvs_app/controller/device/device_calibration_controller.dart';
|
||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||
import 'package:vbvs_app/pages/policy/privacy_policy.dart';
|
||
|
||
getOnePicker(BuildContext context, List arr, int checkIndex,
|
||
Function onSelectedItemChanged,
|
||
{bool looping = false, String unit = ''}) {
|
||
ThemeController themeController = Get.find();
|
||
return CupertinoPicker(
|
||
key: UniqueKey(),
|
||
useMagnifier: false,
|
||
itemExtent: 90.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) {
|
||
bool isSelected = index == checkIndex;
|
||
Color textColor = isSelected ? Color(0XFF011D33) : Color(0xFF9AA0B3);
|
||
return Container(
|
||
alignment: Alignment.center,
|
||
width: 400.rpx,
|
||
// decoration: BoxDecoration(
|
||
// border: Border(
|
||
// bottom: index != arr.length
|
||
// ? BorderSide(color: stringToColor("#8D95B0"))
|
||
// : BorderSide.none,
|
||
// ),
|
||
// ),
|
||
child: Text("${arr[index]}$unit",
|
||
style: TextStyle(
|
||
fontFamily: 'Readex Pro',
|
||
color: textColor,
|
||
letterSpacing: 0,
|
||
fontSize: 30.rpx)),
|
||
);
|
||
})
|
||
],
|
||
);
|
||
}
|
||
|
||
// Widget getOnePickers(
|
||
// BuildContext context,
|
||
// List arr,
|
||
// RxInt selectedIndex, {
|
||
// String unit = '',
|
||
// bool looping = false,
|
||
// void Function(int)? onChanged,
|
||
// bool isMonthName = false,
|
||
// Key? pickerKey,
|
||
// }) {
|
||
// ThemeController themeController = Get.find();
|
||
// final bool isEn = Get.locale?.languageCode.startsWith('en') ?? false;
|
||
|
||
// return Obx(() {
|
||
// final dynamicKey = ValueKey('picker_${arr.length}_${selectedIndex.value}');
|
||
// return CupertinoPicker.builder(
|
||
// key: pickerKey ?? dynamicKey,
|
||
// itemExtent: 90.rpx,
|
||
// useMagnifier: false,
|
||
// magnification: 1,
|
||
// diameterRatio: 1.3,
|
||
// squeeze: 1,
|
||
// scrollController:
|
||
// FixedExtentScrollController(initialItem: selectedIndex.value),
|
||
// selectionOverlay: Container(),
|
||
// onSelectedItemChanged: (int index) {
|
||
// selectedIndex.value = index;
|
||
// if (onChanged != null) onChanged(index);
|
||
// },
|
||
// childCount: arr.length,
|
||
// itemBuilder: (context, index) {
|
||
// bool isSelected = index == selectedIndex.value;
|
||
|
||
// // 处理显示文本
|
||
// String displayText;
|
||
// if (isMonthName && isEn && arr[index] is int) {
|
||
// displayText = DateFormat.MMMM('en').format(DateTime(0, arr[index]));
|
||
// } else {
|
||
// // displayText = isEn ? "${arr[index]}" : "${arr[index]}$unit"; // 中文附带单位
|
||
// displayText = "${arr[index]}$unit"; // 中文附带单位
|
||
// }
|
||
|
||
// return Center(
|
||
// child: Text(
|
||
// displayText,
|
||
// style: TextStyle(
|
||
// fontFamily: 'Readex Pro',
|
||
// color: isSelected
|
||
// ? themeController.currentColor.sc3
|
||
// : const Color(0xFF9AA0B3),
|
||
// fontSize: 30.rpx,
|
||
// fontWeight: FontWeight.normal,
|
||
// ),
|
||
// ),
|
||
// );
|
||
// },
|
||
// );
|
||
// });
|
||
// }
|
||
|
||
Widget getOnePickers(
|
||
BuildContext context,
|
||
List arr,
|
||
RxInt selectedIndex, {
|
||
String unit = '',
|
||
bool looping = false,
|
||
void Function(int)? onChanged,
|
||
bool isMonthName = false,
|
||
Key? pickerKey,
|
||
|
||
/// ⭐ 新增:可选的自定义显示,但不影响旧用法
|
||
String Function(dynamic value)? customDisplay,
|
||
}) {
|
||
ThemeController themeController = Get.find();
|
||
final bool isEn = Get.locale?.languageCode.startsWith('en') ?? false;
|
||
|
||
return Obx(() {
|
||
final dynamicKey = ValueKey('picker_${arr.length}_${selectedIndex.value}');
|
||
return CupertinoPicker.builder(
|
||
key: pickerKey ?? dynamicKey,
|
||
itemExtent: 90.rpx,
|
||
useMagnifier: false,
|
||
magnification: 1,
|
||
diameterRatio: 1.3,
|
||
squeeze: 1,
|
||
scrollController:
|
||
FixedExtentScrollController(initialItem: selectedIndex.value),
|
||
selectionOverlay: Container(),
|
||
onSelectedItemChanged: (int index) {
|
||
selectedIndex.value = index;
|
||
if (onChanged != null) onChanged(index);
|
||
},
|
||
childCount: arr.length,
|
||
itemBuilder: (context, index) {
|
||
bool isSelected = index == selectedIndex.value;
|
||
|
||
String value = arr[index].toString();
|
||
String displayText = "";
|
||
|
||
// ⭐ 1. 优先使用自定义展示
|
||
if (customDisplay != null) {
|
||
String? custom = customDisplay(arr[index]);
|
||
if (custom != null && custom.isNotEmpty) {
|
||
displayText = custom;
|
||
}
|
||
}
|
||
|
||
// ⭐ 2. 若自定义没给或返回空,则使用你原本的逻辑
|
||
if (displayText.isEmpty) {
|
||
if (isMonthName && isEn && arr[index] is int) {
|
||
// 英文月份
|
||
displayText = DateFormat.MMMM('en').format(DateTime(0, arr[index]));
|
||
} else {
|
||
// 中文 + 单位(你原来的逻辑)
|
||
displayText = "$value$unit";
|
||
}
|
||
}
|
||
|
||
return Center(
|
||
child: Text(
|
||
displayText,
|
||
style: TextStyle(
|
||
fontFamily: 'Readex Pro',
|
||
color: isSelected
|
||
? themeController.currentColor.sc3
|
||
: const Color(0xFF9AA0B3),
|
||
fontSize: 30.rpx,
|
||
fontWeight: FontWeight.normal,
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
});
|
||
}
|
||
|
||
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: const Color(0xFF003058),
|
||
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: stringToColor("#84F5FF"))),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
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: const Color(0xFF84F5FF),
|
||
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: "日",
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
Future showMonthSelectionDialog(
|
||
BuildContext context, {
|
||
required DateTime checkDate,
|
||
Function(DateTime)? checkChange,
|
||
String title = "选择月份",
|
||
}) {
|
||
ThemeController themeController = Get.find();
|
||
|
||
final currentYear = DateTime.now().year;
|
||
final currentMonth = DateTime.now().month;
|
||
final colors = _getDialogColors(AppConstants().ent_type); // 获取颜色配置
|
||
final List<int> years = List.generate(100, (i) => DateTime.now().year - i)
|
||
..sort();
|
||
|
||
final RxList<int> months = <int>[].obs;
|
||
|
||
// 初始化 yearIndex
|
||
final int initYearIndex = years.indexOf(checkDate.year);
|
||
final RxInt yearIndex = (initYearIndex >= 0 ? initYearIndex : 0).obs;
|
||
final RxInt monthIndex = 0.obs;
|
||
|
||
bool isInit = true;
|
||
|
||
void updateMonthList() {
|
||
final selectedYear = years[yearIndex.value];
|
||
final maxMonth = selectedYear == currentYear ? currentMonth : 12;
|
||
final newMonths = List.generate(maxMonth, (i) => i + 1);
|
||
months.value = newMonths;
|
||
|
||
if (isInit) {
|
||
final int newMonthIndex = newMonths.indexOf(checkDate.month);
|
||
monthIndex.value = newMonthIndex >= 0 ? newMonthIndex : 0;
|
||
isInit = false;
|
||
} else {
|
||
if (monthIndex.value >= newMonths.length) {
|
||
monthIndex.value = newMonths.length - 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
updateMonthList();
|
||
|
||
ever(yearIndex, (_) => updateMonthList());
|
||
|
||
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: colors.primaryColor,
|
||
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],
|
||
);
|
||
Navigator.of(context).pop();
|
||
checkChange?.call(selectedDate);
|
||
},
|
||
child: Container(
|
||
width: 110.rpx,
|
||
height: 60.rpx,
|
||
alignment: Alignment.center,
|
||
child: Text(
|
||
"确定".tr,
|
||
style: TextStyle(
|
||
fontSize: 30.rpx, color: colors.textColor),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
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: colors.highlightColor,
|
||
borderRadius: BorderRadius.circular(16.rpx),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
// 滚轮选择器
|
||
SizedBox(
|
||
height: 240.rpx,
|
||
child: Padding(
|
||
padding: EdgeInsets.symmetric(horizontal: 95.rpx),
|
||
child: Row(
|
||
children: [
|
||
Expanded(
|
||
child: getOnePickers(
|
||
context,
|
||
years,
|
||
yearIndex,
|
||
unit: "年".tr,
|
||
),
|
||
),
|
||
Expanded(
|
||
child: getOnePickers(
|
||
context,
|
||
months, // 注意这里取 .value
|
||
monthIndex,
|
||
unit: "月".tr,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
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: Color(0xFF003058),
|
||
insetPadding: EdgeInsets.zero,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(0),
|
||
),
|
||
child: Container(
|
||
padding: EdgeInsets.fromLTRB(30.rpx, 10.rpx, 30.rpx, 90.rpx),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
// 标题 + 按钮
|
||
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: stringToColor("#84F5FF"),
|
||
),
|
||
),
|
||
)),
|
||
],
|
||
),
|
||
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: Color(0xFF84F5FF),
|
||
borderRadius: BorderRadius.circular(16.rpx),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
SizedBox(
|
||
height: 240.rpx,
|
||
child: getOnePickers(
|
||
context,
|
||
weights,
|
||
tempIndex, // ✅ 传入 RxInt
|
||
unit: "kg",
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
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: Color(0xFF003058),
|
||
insetPadding: EdgeInsets.zero,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(0),
|
||
),
|
||
child: Container(
|
||
padding: EdgeInsets.fromLTRB(30.rpx, 10.rpx, 30.rpx, 90.rpx),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
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: stringToColor("#84F5FF"),
|
||
),
|
||
),
|
||
)),
|
||
],
|
||
),
|
||
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: Color(0xFF84F5FF),
|
||
borderRadius: BorderRadius.circular(16.rpx),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
SizedBox(
|
||
height: 240.rpx,
|
||
child: getOnePickers(
|
||
context,
|
||
heights,
|
||
tempIndex, // ✅ 传入 RxInt
|
||
unit: "cm",
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
Future showDayTimeSelectionDialog(
|
||
BuildContext context, {
|
||
required List<int> dayTimeArr,
|
||
Function(List<int>)? checkChange,
|
||
String title = "选择时间",
|
||
}) {
|
||
ThemeController themeController = Get.find();
|
||
Color checkColor = stringToColor("#D3B684");
|
||
|
||
final List<int> hours = List.generate(24, (i) => i);
|
||
final List<int> minutes = List.generate(60, (i) => i);
|
||
|
||
final RxInt hoursIndex = hours.indexOf(dayTimeArr[0]).obs;
|
||
final RxInt minutesIndex = minutes.indexOf(dayTimeArr[1]).obs;
|
||
|
||
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: const Color(0xFF003058),
|
||
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.tr,
|
||
style: TextStyle(
|
||
fontFamily: 'Readex Pro',
|
||
color: themeController.currentColor.sc3,
|
||
fontSize: 30.rpx,
|
||
),
|
||
),
|
||
ClickableContainer(
|
||
backgroundColor: Colors.transparent,
|
||
highlightColor: Colors.transparent,
|
||
padding: EdgeInsets.zero,
|
||
onTap: () {
|
||
checkChange?.call([
|
||
hours[hoursIndex.value],
|
||
minutes[minutesIndex.value],
|
||
]);
|
||
Get.back();
|
||
},
|
||
child: Container(
|
||
width: 110.rpx,
|
||
height: 60.rpx,
|
||
alignment: Alignment.center,
|
||
child: Text("确定".tr,
|
||
style: TextStyle(
|
||
fontSize: 30.rpx,
|
||
color: stringToColor("#84F5FF"))),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
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: const Color(0xFF84F5FF),
|
||
borderRadius: BorderRadius.circular(16.rpx),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
SizedBox(
|
||
height: 240.rpx,
|
||
child: Padding(
|
||
padding: EdgeInsets.symmetric(horizontal: 95.rpx),
|
||
child: Row(
|
||
children: [
|
||
Expanded(
|
||
child: getOnePickers(
|
||
context,
|
||
hours,
|
||
hoursIndex,
|
||
unit: "时".tr,
|
||
),
|
||
),
|
||
Expanded(
|
||
child: getOnePickers(
|
||
context,
|
||
minutes,
|
||
minutesIndex,
|
||
unit: "分".tr,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
Future showOneSelectionDialog(
|
||
BuildContext context, {
|
||
required List arr,
|
||
int checkIndex = 0,
|
||
Function? checkChange,
|
||
String title = "选择性别",
|
||
}) {
|
||
ThemeController themeController = Get.find();
|
||
Color checkColor = stringToColor("#D3B684");
|
||
|
||
final RxInt selectedIndex = checkIndex.obs; // ✅ 用RxInt变量监听选中项
|
||
|
||
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: const Color(0xFF003058),
|
||
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,
|
||
children: <Widget>[
|
||
// 顶部标题 + 按钮
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
ClickableContainer(
|
||
backgroundColor: Colors.transparent,
|
||
highlightColor: Colors.transparent,
|
||
padding: EdgeInsets.zero,
|
||
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.tr,
|
||
style: TextStyle(
|
||
fontFamily: 'Readex Pro',
|
||
color: Colors.white,
|
||
fontSize: 30.rpx,
|
||
)),
|
||
ClickableContainer(
|
||
backgroundColor: Colors.transparent,
|
||
highlightColor: Colors.transparent,
|
||
padding: EdgeInsets.zero,
|
||
onTap: () {
|
||
checkChange?.call(selectedIndex.value);
|
||
Get.back();
|
||
},
|
||
child: Container(
|
||
alignment: Alignment.center,
|
||
width: 110.rpx,
|
||
height: 60.rpx,
|
||
child: Text("确定".tr,
|
||
style: TextStyle(
|
||
fontSize: 30.rpx,
|
||
color: stringToColor("#84F5FF"))),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
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: const Color(0xFF84F5FF),
|
||
borderRadius: BorderRadius.circular(16.rpx),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
Container(
|
||
height: 240.rpx,
|
||
margin: EdgeInsets.only(
|
||
top: 60.rpx,
|
||
bottom: 60.rpx,
|
||
left: 30.rpx,
|
||
right: 30.rpx),
|
||
child: getOnePickers(
|
||
context,
|
||
arr,
|
||
selectedIndex,
|
||
unit: '',
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
enum ConfirmDialogIcon {
|
||
none,
|
||
danger,
|
||
success,
|
||
warn;
|
||
|
||
get uname {
|
||
String v = "";
|
||
switch (this) {
|
||
case ConfirmDialogIcon.danger:
|
||
v = "danger";
|
||
break;
|
||
case ConfirmDialogIcon.success:
|
||
v = "success";
|
||
break;
|
||
case ConfirmDialogIcon.warn:
|
||
v = "warn";
|
||
break;
|
||
case ConfirmDialogIcon.none:
|
||
v = "";
|
||
break;
|
||
}
|
||
return v;
|
||
}
|
||
}
|
||
|
||
Future showCustomConfirmDialog(BuildContext context, String name,
|
||
{String btnName = "确定",
|
||
ConfirmDialogIcon icon = ConfirmDialogIcon.warn}) async {
|
||
ThemeController themeController = Get.find();
|
||
return showDialog(
|
||
context: context,
|
||
barrierDismissible: true,
|
||
builder: (BuildContext context) {
|
||
return Dialog(
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(10.0),
|
||
),
|
||
child: Container(
|
||
width: 660.rpx,
|
||
padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: <Widget>[
|
||
Container(
|
||
alignment: Alignment.centerRight,
|
||
child: closeIcon,
|
||
),
|
||
SizedBox(height: 60.rpx),
|
||
if ("${icon.uname}".isNotEmpty)
|
||
Center(
|
||
child: Container(
|
||
margin: EdgeInsets.only(bottom: 39.rpx),
|
||
width: 50.rpx,
|
||
height: 50.rpx,
|
||
child: Image.asset("assets/images/toast/${icon.uname}.png"),
|
||
),
|
||
),
|
||
Center(
|
||
child: Text(
|
||
'${name}',
|
||
style: TextStyle(fontSize: 16),
|
||
),
|
||
),
|
||
SizedBox(height: 20.rpx),
|
||
Container(
|
||
margin: EdgeInsets.only(top: 50.rpx, bottom: 40.rpx),
|
||
alignment: Alignment.center,
|
||
// child: InkWell(
|
||
// onTap: () {
|
||
// Get.back(result: "confirm");
|
||
// },
|
||
// child: Container(
|
||
// width: 260.rpx,
|
||
// height: 60.rpx,
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// borderRadius: BorderRadius.circular(6),
|
||
// color: stringToColor("#D3B684")),
|
||
// child: Text(
|
||
// '$btnName',
|
||
// style: TextStyle(
|
||
// color: themeController.currentColor.sc3,
|
||
// fontSize: 30.rpx),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
child: CustomCard(
|
||
borderRadius: AppConstants().button_container_radius,
|
||
onTap: () {
|
||
Get.back(result: "confirm");
|
||
},
|
||
colors: [
|
||
Color(0xFF1592AA),
|
||
Color(0xFF0C83A7),
|
||
Color(0xFF006FA3)
|
||
],
|
||
child: Container(
|
||
width: 260.rpx,
|
||
height: 60.rpx,
|
||
child: Row(
|
||
mainAxisSize: MainAxisSize.max,
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Text(
|
||
"确定".tr,
|
||
style: TextStyle(
|
||
color: themeController.currentColor.sc3,
|
||
fontFamily: 'Inter',
|
||
fontSize: AppConstants().normal_text_fontSize,
|
||
letterSpacing: 0.0,
|
||
),
|
||
),
|
||
].divide(SizedBox(width: 17.rpx)),
|
||
),
|
||
),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
Future showCustomConfirmDialogTH(BuildContext context, String name,
|
||
{String btnName = "确定",
|
||
ConfirmDialogIcon icon = ConfirmDialogIcon.warn}) async {
|
||
ThemeController themeController = Get.find();
|
||
return showDialog(
|
||
context: context,
|
||
barrierDismissible: true,
|
||
builder: (BuildContext context) {
|
||
return Dialog(
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius:
|
||
BorderRadius.circular(AppConstants().normal_container_radius),
|
||
),
|
||
backgroundColor: themeController.currentColor.sc17, // 在这里设置背景色
|
||
child: Container(
|
||
width: 660.rpx,
|
||
padding: EdgeInsets.fromLTRB(60.rpx, 0, 60.rpx, 32.rpx),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: <Widget>[
|
||
Container(
|
||
// color: themeController.currentColor.sc9,
|
||
alignment: Alignment.centerRight,
|
||
child: closeIconWhite,
|
||
),
|
||
SizedBox(height: 60.rpx),
|
||
if ("${icon.uname}".isNotEmpty)
|
||
Center(
|
||
child: Container(
|
||
margin: EdgeInsets.only(bottom: 39.rpx),
|
||
width: 50.rpx,
|
||
height: 50.rpx,
|
||
child: Image.asset(
|
||
"assets/images/toast/${icon.uname}.png",
|
||
color: themeController.currentColor.sc9,
|
||
),
|
||
),
|
||
),
|
||
Center(
|
||
child: Text(
|
||
'${name}',
|
||
style: TextStyle(
|
||
fontSize: 16, color: themeController.currentColor.sc3),
|
||
),
|
||
),
|
||
SizedBox(height: 20.rpx),
|
||
Container(
|
||
margin: EdgeInsets.only(top: 50.rpx, bottom: 40.rpx),
|
||
alignment: Alignment.center,
|
||
child: CustomCard(
|
||
borderRadius: AppConstants().button_container_radius,
|
||
onTap: () {
|
||
Get.back(result: "confirm");
|
||
},
|
||
colors: AppConstants().thNormalButton,
|
||
child: Container(
|
||
width: 260.rpx,
|
||
height: 60.rpx,
|
||
child: Row(
|
||
mainAxisSize: MainAxisSize.max,
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Text(
|
||
"确定".tr,
|
||
style: TextStyle(
|
||
color: themeController.currentColor.sc3,
|
||
fontFamily: 'Inter',
|
||
fontSize: AppConstants().normal_text_fontSize,
|
||
letterSpacing: 0.0,
|
||
),
|
||
),
|
||
].divide(SizedBox(width: 17.rpx)),
|
||
),
|
||
),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
Future showCustomConfirmAndCancelDialog(BuildContext context, String name,
|
||
{String confirmName = "确定",
|
||
String cancelName = "取消",
|
||
ConfirmDialogIcon icon = ConfirmDialogIcon.warn}) async {
|
||
ThemeController themeController = Get.find();
|
||
return showDialog(
|
||
context: context,
|
||
barrierDismissible: true,
|
||
builder: (BuildContext context) {
|
||
return Dialog(
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(10.0),
|
||
),
|
||
child: Container(
|
||
width: 660.rpx,
|
||
padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: <Widget>[
|
||
Container(
|
||
alignment: Alignment.centerRight,
|
||
child: closeIcon,
|
||
),
|
||
SizedBox(height: 40.rpx),
|
||
if ("${icon.uname}".isNotEmpty)
|
||
Center(
|
||
child: Container(
|
||
margin: EdgeInsets.only(bottom: 39.rpx),
|
||
width: 50.rpx,
|
||
height: 50.rpx,
|
||
child: Image.asset("assets/images/toast/${icon.uname}.png"),
|
||
),
|
||
),
|
||
Center(
|
||
child: Text(
|
||
'${name}',
|
||
style: TextStyle(fontSize: 16),
|
||
),
|
||
),
|
||
SizedBox(height: 20.rpx),
|
||
Container(
|
||
margin: EdgeInsets.only(top: 50.rpx, bottom: 40.rpx),
|
||
alignment: Alignment.center,
|
||
child: InkWell(
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
InkWell(
|
||
onTap: () {
|
||
Get.back(result: "cancel");
|
||
},
|
||
child: Container(
|
||
width: 200.rpx,
|
||
height: 60.rpx,
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(6),
|
||
border: Border.all(color: Colors.black12)),
|
||
child: Text(
|
||
'$cancelName',
|
||
style:
|
||
TextStyle(color: Colors.black, fontSize: 30.rpx),
|
||
),
|
||
),
|
||
),
|
||
SizedBox(
|
||
width: 80.rpx,
|
||
),
|
||
InkWell(
|
||
onTap: () {
|
||
Get.back(result: "confirm");
|
||
},
|
||
child: Container(
|
||
width: 200.rpx,
|
||
height: 60.rpx,
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(6),
|
||
color: stringToColor("#D3B684")),
|
||
child: Text(
|
||
'$confirmName',
|
||
style: TextStyle(
|
||
color: themeController.currentColor.sc3,
|
||
fontSize: 30.rpx),
|
||
),
|
||
),
|
||
)
|
||
],
|
||
)),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
//权限说明弹窗
|
||
void showPermissionInfoDialog(BuildContext context, List data) {
|
||
ThemeController themeController = Get.find();
|
||
showDialog(
|
||
context: context,
|
||
barrierDismissible: false, // 点击对话框外部可关闭
|
||
builder: (BuildContext context) {
|
||
return Stack(
|
||
children: [
|
||
Positioned(
|
||
top: 30.rpx, // 控制弹窗距离顶部的位置
|
||
left: 0,
|
||
right: 0,
|
||
child: Material(
|
||
color: Colors.transparent,
|
||
child: Dialog(
|
||
backgroundColor: themeController.currentColor.sc3,
|
||
insetPadding: EdgeInsets.fromLTRB(0, 0, 0, 0),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(10.0),
|
||
),
|
||
child: Container(
|
||
constraints: BoxConstraints(maxHeight: 500.rpx),
|
||
padding: EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(10),
|
||
),
|
||
child: SingleChildScrollView(
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: <Widget>[
|
||
...List.generate(data.length, (index) {
|
||
return Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
"${data[index][0]}",
|
||
style: TextStyle(
|
||
fontSize: 30.rpx,
|
||
color: stringToColor("#333333"),
|
||
),
|
||
),
|
||
SizedBox(
|
||
height: 4.rpx,
|
||
),
|
||
Text(
|
||
"${data[index][1]}",
|
||
style: TextStyle(
|
||
fontSize: 26.rpx,
|
||
color: stringToColor("#A4AABC"),
|
||
),
|
||
),
|
||
if (index != data.length - 1)
|
||
SizedBox(
|
||
height: 18.rpx,
|
||
),
|
||
],
|
||
);
|
||
}),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
void showProgressDialog(
|
||
BuildContext context,
|
||
ValueNotifier<double> progressNotifier,
|
||
ValueNotifier<bool> failureNotifier,
|
||
) {
|
||
ThemeController themeController = Get.find();
|
||
DeviceCalibrationController deviceCalibrationController = Get.find();
|
||
showDialog(
|
||
context: context,
|
||
barrierDismissible: false, // 点击对话框外部不可关闭
|
||
builder: (BuildContext dialogContext) {
|
||
return Stack(
|
||
children: [
|
||
Positioned(
|
||
top: MediaQuery.of(context).size.height * 0.4,
|
||
left: MediaQuery.of(context).size.width * 0.05,
|
||
right: MediaQuery.of(context).size.width * 0.05,
|
||
child: Material(
|
||
color: Colors.transparent,
|
||
child: Dialog(
|
||
backgroundColor: Colors.transparent,
|
||
insetPadding: EdgeInsets.zero,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(10.0),
|
||
),
|
||
child: Container(
|
||
padding: EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(10),
|
||
),
|
||
child: ValueListenableBuilder<double>(
|
||
valueListenable: progressNotifier,
|
||
builder: (context, progress, _) {
|
||
return ValueListenableBuilder<bool>(
|
||
valueListenable: failureNotifier,
|
||
builder: (context, isFailure, __) {
|
||
// 关闭弹窗的逻辑
|
||
if (isFailure) {
|
||
// 延迟关闭弹窗和提示错误
|
||
Future.delayed(Duration(milliseconds: 300), () {
|
||
if (Navigator.canPop(dialogContext)) {
|
||
Navigator.of(dialogContext).pop();
|
||
}
|
||
});
|
||
} else if (progress >= 100) {
|
||
// 延迟关闭弹窗和提示成功(可选)
|
||
Future.delayed(Duration(milliseconds: 300), () {
|
||
if (Navigator.canPop(dialogContext)) {
|
||
Navigator.of(dialogContext).pop();
|
||
}
|
||
});
|
||
}
|
||
return Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: <Widget>[
|
||
Text(
|
||
isFailure
|
||
? '失败'.tr
|
||
: '${(progress).toStringAsFixed(0)}%',
|
||
style: TextStyle(
|
||
fontSize: 26.rpx,
|
||
color: isFailure
|
||
? Colors.red
|
||
: themeController.currentColor.sc3,
|
||
),
|
||
),
|
||
SizedBox(height: 40.rpx),
|
||
Stack(
|
||
children: [
|
||
Container(
|
||
width: double.infinity,
|
||
height: 21.rpx,
|
||
decoration: BoxDecoration(
|
||
color: stringToColor("#D9D9D9"),
|
||
borderRadius: BorderRadius.circular(
|
||
AppConstants().button_container_radius,
|
||
),
|
||
),
|
||
),
|
||
Container(
|
||
width: progress /
|
||
100 *
|
||
MediaQuery.of(context).size.width *
|
||
0.8,
|
||
height: 21.rpx,
|
||
decoration: BoxDecoration(
|
||
gradient: LinearGradient(
|
||
colors: isFailure
|
||
? [themeController.currentColor.sc9]
|
||
: [
|
||
themeController
|
||
.currentColor.sc2,
|
||
themeController
|
||
.currentColor.sc2,
|
||
],
|
||
begin: Alignment.centerLeft,
|
||
end: Alignment.centerRight,
|
||
),
|
||
borderRadius: BorderRadius.circular(
|
||
AppConstants().button_container_radius,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
},
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
void showSleepCalendarBottomSheet({
|
||
required BuildContext context,
|
||
int? timestamp,
|
||
int? type = 1,
|
||
String? mac,
|
||
required void Function(DateTime selectedDate) onDateSelected,
|
||
}) {
|
||
showGeneralDialog(
|
||
context: context,
|
||
barrierDismissible: true,
|
||
barrierLabel: 'Dismiss',
|
||
barrierColor: Colors.black.withOpacity(0.4), // 移到这里,替代 Scaffold 背景
|
||
transitionDuration: const Duration(milliseconds: 300),
|
||
pageBuilder: (context, animation, secondaryAnimation) {
|
||
return GestureDetector(
|
||
onTap: () {
|
||
Navigator.of(context).pop(); // 点击空白关闭
|
||
},
|
||
child: Material(
|
||
type: MaterialType.transparency,
|
||
child: Align(
|
||
alignment: Alignment.bottomCenter,
|
||
child: GestureDetector(
|
||
onTap: () {}, // 阻止点击透传到外部(避免误关)
|
||
child: FractionallySizedBox(
|
||
widthFactor: 1.0,
|
||
heightFactor: 0.55,
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: const Color(0xFF242835),
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(20.rpx),
|
||
topRight: Radius.circular(20.rpx),
|
||
),
|
||
),
|
||
child: SleepCalendarWidget(
|
||
timestamp: timestamp,
|
||
type: type,
|
||
mac: mac,
|
||
onDateSelected: onDateSelected,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
// Future showCustomConfirmOfWebViewDialog(
|
||
// BuildContext context, String name, String webviewUrl,
|
||
// {String btnName = "确定",
|
||
// bool showCancel = false,
|
||
// String cancelName = "取消",
|
||
// ConfirmDialogIcon icon = ConfirmDialogIcon.warn}) async {
|
||
// return showDialog(
|
||
// context: context,
|
||
// barrierDismissible: true,
|
||
// builder: (BuildContext context) {
|
||
// return Dialog(
|
||
// backgroundColor: Colors.white,
|
||
// insetPadding: EdgeInsets.all(0),
|
||
// shape: RoundedRectangleBorder(
|
||
// borderRadius: BorderRadius.circular(10.0),
|
||
// ),
|
||
// child: Container(
|
||
// width: 640.rpx,
|
||
// padding: EdgeInsets.fromLTRB(22.rpx, 0, 20.rpx, 10.rpx),
|
||
// child: Column(
|
||
// mainAxisSize: MainAxisSize.min,
|
||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||
// children: <Widget>[
|
||
// Container(
|
||
// alignment: Alignment.centerRight,
|
||
// child: closeIcon,
|
||
// ),
|
||
// SizedBox(height: 40.rpx),
|
||
// Container(
|
||
// height: MediaQuery.of(context).size.height * 0.4,
|
||
// child: PrivacyPolicyNewPage(
|
||
// sleepUri: webviewUrl,
|
||
// showAppbar: false,
|
||
// ),
|
||
// ),
|
||
// SizedBox(height: 20.rpx),
|
||
// Row(
|
||
// mainAxisAlignment: MainAxisAlignment.center,
|
||
// children: [
|
||
// if (showCancel)
|
||
// Container(
|
||
// margin: EdgeInsets.only(
|
||
// top: 50.rpx, bottom: 40.rpx, right: 100.rpx),
|
||
// alignment: Alignment.center,
|
||
// child: InkWell(
|
||
// onTap: () {
|
||
// Get.back();
|
||
// },
|
||
// child: Container(
|
||
// width: 200.rpx,
|
||
// height: 60.rpx,
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// borderRadius: BorderRadius.circular(6),
|
||
// border: Border.all(color: Colors.black12)),
|
||
// child: Text(
|
||
// '$cancelName',
|
||
// style: TextStyle(
|
||
// color: Colors.black, fontSize: 30.rpx),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// Container(
|
||
// margin: EdgeInsets.only(top: 50.rpx, bottom: 40.rpx),
|
||
// alignment: Alignment.center,
|
||
// child: InkWell(
|
||
// onTap: () {
|
||
// Get.back(result: "confirm");
|
||
// },
|
||
// child: Container(
|
||
// width: 200.rpx,
|
||
// height: 60.rpx,
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// borderRadius: BorderRadius.circular(6),
|
||
// color: stringToColor("#D3B684")),
|
||
// child: Text(
|
||
// '$btnName',
|
||
// style:
|
||
// TextStyle(color: Colors.white, fontSize: 30.rpx),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// )
|
||
// ],
|
||
// )
|
||
// ],
|
||
// ),
|
||
// ),
|
||
// );
|
||
// },
|
||
// );
|
||
// }
|
||
|
||
Future showCustomConfirmOfWebViewDialog(
|
||
BuildContext context, String name, String webviewUrl,
|
||
{String btnName = "确定",
|
||
bool showCancel = false,
|
||
String cancelName = "取消",
|
||
ConfirmDialogIcon icon = ConfirmDialogIcon.warn}) async {
|
||
return showDialog(
|
||
context: context,
|
||
barrierDismissible: true,
|
||
builder: (BuildContext context) {
|
||
final screenSize = MediaQuery.of(context).size;
|
||
return Dialog(
|
||
backgroundColor: Colors.white,
|
||
insetPadding: EdgeInsets.zero, // 移除默认的内边距
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(10.0),
|
||
),
|
||
child: Container(
|
||
width: screenSize.width, // 使用屏幕宽度
|
||
height: screenSize.height, // 使用屏幕高度
|
||
padding: EdgeInsets.fromLTRB(22.rpx, 0, 20.rpx, 10.rpx),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: <Widget>[
|
||
// Container(
|
||
// alignment: Alignment.centerRight,
|
||
// child: closeIcon,
|
||
// ),
|
||
// SizedBox(height: 40.rpx),
|
||
Expanded(
|
||
// 使用 Expanded 让 WebView 占据剩余空间
|
||
child: PrivacyPolicyNewPage(
|
||
sleepUri: webviewUrl,
|
||
showAppbar: false,
|
||
),
|
||
),
|
||
SizedBox(height: 20.rpx),
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
if (showCancel)
|
||
Container(
|
||
margin: EdgeInsets.only(
|
||
top: 50.rpx, bottom: 40.rpx, right: 100.rpx),
|
||
alignment: Alignment.center,
|
||
child: InkWell(
|
||
onTap: () {
|
||
Get.back();
|
||
},
|
||
child: Container(
|
||
width: 200.rpx,
|
||
height: 60.rpx,
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(6),
|
||
border: Border.all(color: Colors.black12)),
|
||
child: Text(
|
||
'$cancelName',
|
||
style: TextStyle(
|
||
color: Colors.black, fontSize: 30.rpx),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
// Container(
|
||
// margin: EdgeInsets.only(top: 50.rpx, bottom: 40.rpx),
|
||
// alignment: Alignment.center,
|
||
// child: InkWell(
|
||
// onTap: () {
|
||
// Get.back(result: "confirm");
|
||
// },
|
||
// child: Container(
|
||
// width: 200.rpx,
|
||
// height: 60.rpx,
|
||
// alignment: Alignment.center,
|
||
// decoration: BoxDecoration(
|
||
// borderRadius: BorderRadius.circular(6),
|
||
// color: stringToColor("#D3B684")),
|
||
// child: Text(
|
||
// '$btnName',
|
||
// style:
|
||
// TextStyle(color: Colors.white, fontSize: 30.rpx),
|
||
// ),
|
||
// ),
|
||
// ),
|
||
// )
|
||
CustomCard(
|
||
borderRadius: 12.rpx, // 圆角半径
|
||
onTap: () {
|
||
Get.back(result: "confirm");
|
||
},
|
||
colors: AppConstants().mhtNormalButton, // 渐变背景
|
||
gradientDirection: GradientDirection.horizontal,
|
||
child: Container(
|
||
// width: MediaQuery.sizeOf(context).width * 0.5, // 宽度占屏幕一半
|
||
// height: MediaQuery.sizeOf(context).height * 0.055,
|
||
constraints: BoxConstraints(
|
||
minWidth: 200.rpx,
|
||
minHeight: 60.rpx,
|
||
),
|
||
alignment: Alignment.center,
|
||
child: Text(
|
||
'$btnName',
|
||
style: TextStyle(
|
||
color: Colors.white, // 文字颜色
|
||
fontFamily: 'Inter',
|
||
fontSize: AppConstants().normal_text_fontSize, // 字体大小
|
||
fontWeight: FontWeight.w600,
|
||
letterSpacing: 0.0,
|
||
),
|
||
),
|
||
),
|
||
)
|
||
],
|
||
)
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
class DialogColorScheme {
|
||
final Color primaryColor; // 背景色
|
||
final Color highlightColor; // 高亮色(选择框背景)
|
||
final Color textColor; // 文本色(如"确定"按钮)
|
||
|
||
DialogColorScheme({
|
||
required this.primaryColor,
|
||
required this.highlightColor,
|
||
required this.textColor,
|
||
});
|
||
}
|
||
|
||
// 根据 ent_type 获取颜色配置
|
||
DialogColorScheme _getDialogColors(int entType) {
|
||
switch (entType) {
|
||
case 1: // 企业类型1
|
||
return DialogColorScheme(
|
||
primaryColor: themeController.currentColor.sc17, // 深紫背景
|
||
highlightColor: themeController.currentColor.sc2, // 浅紫高亮
|
||
textColor: themeController.currentColor.sc2, // 浅紫文本
|
||
);
|
||
|
||
case 2: // 企业类型2
|
||
return DialogColorScheme(
|
||
primaryColor: const Color(0xFF003058), // 深蓝背景
|
||
highlightColor: const Color(0xFF84F5FF), // 浅蓝高亮
|
||
textColor: const Color(0xFF84F5FF), // 浅蓝文本
|
||
);
|
||
default: // 默认配置
|
||
return DialogColorScheme(
|
||
primaryColor: const Color(0xFF003058),
|
||
highlightColor: const Color(0xFF84F5FF),
|
||
textColor: const Color(0xFF84F5FF),
|
||
);
|
||
}
|
||
}
|
||
|
||
Future showTHDayTimeSelectionDialog(
|
||
BuildContext context, {
|
||
required List<int> dayTimeArr,
|
||
Function(List<int>)? checkChange,
|
||
String title = "选择时间",
|
||
}) {
|
||
ThemeController themeController = Get.find();
|
||
|
||
final List<int> hours = List.generate(24, (i) => i);
|
||
final List<int> minutes = List.generate(60, (i) => i);
|
||
|
||
final RxInt hoursIndex = hours.indexOf(dayTimeArr[0]).obs;
|
||
final RxInt minutesIndex = minutes.indexOf(dayTimeArr[1]).obs;
|
||
|
||
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(0.rpx, 0.rpx, 0.rpx, 90.rpx),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: <Widget>[
|
||
// 顶部栏:取消 - 标题 - 确定
|
||
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.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.tr,
|
||
style: TextStyle(
|
||
fontFamily: 'Readex Pro',
|
||
color: themeController
|
||
.currentColor.sc3, // 修改:使用主题颜色
|
||
fontSize: 30.rpx,
|
||
),
|
||
),
|
||
ClickableContainer(
|
||
backgroundColor: Colors.transparent,
|
||
highlightColor: Colors.transparent,
|
||
padding: EdgeInsets.zero,
|
||
onTap: () {
|
||
checkChange?.call([
|
||
hours[hoursIndex.value],
|
||
minutes[minutesIndex.value],
|
||
]);
|
||
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: 95.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: [
|
||
Expanded(
|
||
child: getOnePickers(
|
||
context,
|
||
hours,
|
||
hoursIndex,
|
||
unit: "时".tr,
|
||
),
|
||
),
|
||
Expanded(
|
||
child: getOnePickers(
|
||
context,
|
||
minutes,
|
||
minutesIndex,
|
||
unit: "分".tr,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|