import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import '../../../../utils/utils.dart';
import '../../../components/operate_botton.dart';
import '../config/config.dart';
class TimeData {
final int hour;
final int minute;
final int second;
TimeData(this.hour, [this.minute = 0, this.second = 0])
: assert(hour >= 0 && hour <= 23),
assert(minute >= 0 && minute <= 59),
assert(second >= 0 && second <= 59);
factory TimeData.now() {
var now = DateTime.now();
return TimeData(now.hour, now.minute, now.second);
}
//判断时间先后
bool precede(TimeData other) {
return (hour < other.hour) ||
(hour == other.hour && minute < other.minute) ||
(hour == other.hour && minute == other.minute && second < other.second);
}
//转字符串
@override
String toString() {
return '$hour:$minute:$second';
}
}
class MyTimePicker extends StatefulWidget {
const MyTimePicker({
super.key,
this.width,
this.height,
this.endTime,
this.startTime,
this.isDialy = false,
this.selectedEndTime,
this.selectedStartTime,
required this.onSelected,
required this.disableperiod,
required this.timeLimited,
required this.editDate,
});
final double? width;
final double? height;
final bool? isDialy;
final bool timeLimited;
final TimeData? endTime;
final TimeData? startTime;
final TimeData? selectedEndTime;
final List<String> disableperiod;
final TimeData? selectedStartTime;
final DateTime editDate;
final Function(
{required String startAt,
required String endAt,
required String period}) onSelected;
@override
State<MyTimePicker> createState() => _MyTimePickerState();
}
class _MyTimePickerState extends State<MyTimePicker> {
late FixedExtentScrollController startHourScrollController;
late FixedExtentScrollController startMinuteScrollController;
late FixedExtentScrollController endHourScrollController;
late FixedExtentScrollController endMinuteScrollController;
List<int> hourList = [];
List<int> minuteList = [];
int startHourIndex = 0;
int startMinuteIndex = 0;
int endHourIndex = 0;
int endMinuteIndex = 0;
late TimeData startTime;
late TimeData endTime;
late TimeData selectedStartTime;
late TimeData selectedEndTime;
final double itemExtent = 44;
bool isOverlap(List<String> disablePeriod, String newPeriod) {
bool isOverlap = false;
for (String period in disablePeriod) {
List<String> parts = period.split(' - ');
List<String> newParts = newPeriod.split(' - ');
DateTime start1 = DateTime.parse('2024-01-01 ${parts[0]}');
DateTime end1 = DateTime.parse('2024-01-01 ${parts[1]}');
DateTime start2 = DateTime.parse('2024-01-01 ${newParts[0]}');
DateTime end2 = DateTime.parse('2024-01-01 ${newParts[1]}');
if (start1.isBefore(end2) && end1.isAfter(start2)) {
isOverlap = true;
break;
}
}
return isOverlap;
}
void initData() {
// 初始化时
for (int i = startTime.hour; i <= endTime.hour; i++) {
hourList.add(i);
}
int selectStarHour = selectedStartTime.hour;
// 初始化分
minuteList = getMinuteList(selectStarHour);
// 初始化时间索引
final List uniqueHourList = Set.from(hourList).toList();
final List uniqueMinuteList = Set.from(minuteList).toList();
// 获取索引
setState(() {
startHourIndex = uniqueHourList.indexOf(selectedStartTime.hour);
startMinuteIndex = uniqueMinuteList.indexOf(selectedStartTime.minute);
endHourIndex = uniqueHourList.indexOf(selectedEndTime.hour);
endMinuteIndex = uniqueMinuteList.indexOf(selectedEndTime.minute);
});
// 设置Picker初始值
startHourScrollController =
FixedExtentScrollController(initialItem: startHourIndex);
startMinuteScrollController =
FixedExtentScrollController(initialItem: startMinuteIndex);
endHourScrollController =
FixedExtentScrollController(initialItem: endHourIndex);
endMinuteScrollController =
FixedExtentScrollController(initialItem: endMinuteIndex);
}
List<int> getMinuteList(int selectHour) {
List<int> list = [];
if (selectHour == startTime.hour) {
for (int i = startTime.minute; i <= 59; i++) {
list.add(i);
}
} else if (selectHour == endTime.hour) {
for (int i = 0; i <= endTime.minute; i++) {
list.add(i);
}
} else {
for (int i = 0; i <= 59; i++) {
list.add(i);
}
}
return list;
}
void updateMinuteList() {
int selectHour = hourList[startHourIndex];
setState(() {
startMinuteIndex = 0;
minuteList = getMinuteList(selectHour);
if (startHourScrollController.positions.isNotEmpty) {
startMinuteScrollController.jumpTo(0);
}
});
}
@override
void initState() {
super.initState();
startTime = widget.startTime ?? TimeData(0, 0, 0);
endTime = widget.endTime ?? TimeData(23, 59, 59);
selectedStartTime = widget.selectedStartTime ??
TimeData(startTime.hour, startTime.minute, startTime.second);
selectedEndTime = widget.selectedEndTime ??
TimeData(endTime.hour, endTime.minute, endTime.second);
if (endTime.precede(startTime)) {
endTime = startTime;
}
if (selectedEndTime.precede(selectedStartTime)) {
selectedEndTime = selectedStartTime;
}
if (selectedStartTime.precede(startTime)) {
selectedStartTime = startTime;
}
if (endTime.precede(selectedStartTime)) {
selectedStartTime = endTime;
}
if (selectedEndTime.precede(startTime)) {
selectedEndTime = startTime;
}
if (endTime.precede(selectedEndTime)) {
selectedEndTime = endTime;
}
initData();
}
@override
void dispose() {
startHourScrollController.dispose();
startMinuteScrollController.dispose();
endHourScrollController.dispose();
endMinuteScrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
width: widget.width ?? 280,
height: widget.height ?? 280,
padding: const EdgeInsets.all(10),
child: Column(
children: [
SizedBox(
width: double.infinity,
height: widget.height != null ? widget.height! - 50 : 230,
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(child: Center(child: startHourPickerView())),
Text(':',
style: TextStyle(
color: textColor(context.isDarkMode),
fontSize: 16,
height: 1,
fontWeight: FontWeight.bold,
)),
Expanded(child: Center(child: startMinutePickerView())),
Text('至',
style: TextStyle(
color: textColor(context.isDarkMode),
fontSize: 16,
height: 1,
fontWeight: FontWeight.bold,
)),
Expanded(child: Center(child: endHourPickerView())),
Text(':',
style: TextStyle(
color: textColor(context.isDarkMode),
fontSize: 16,
height: 1,
fontWeight: FontWeight.bold,
)),
Expanded(child: Center(child: endMinutePickerView())),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
creatCancelButton(() {
SmartDialog.dismiss();
}),
const SizedBox(width: 10),
creatOkButton(
() async {
String startAt =
'${hourList[startHourIndex] > 9 ? hourList[startHourIndex] : '0${hourList[startHourIndex]}'}:${minuteList[startMinuteIndex] > 9 ? minuteList[startMinuteIndex] : '0${minuteList[startMinuteIndex]}'}';
String endAt =
'${hourList[endHourIndex] > 9 ? hourList[endHourIndex] : '0${hourList[endHourIndex]}'}:${minuteList[endMinuteIndex] > 9 ? minuteList[endMinuteIndex] : '0${minuteList[endMinuteIndex]}'}';
if (widget.isDialy!) {
DateTime now = DateTime.now();
if (widget.editDate.year == now.year &&
widget.editDate.month == now.month &&
widget.editDate.day == now.day &&
(hourList[startHourIndex] < now.hour ||
(hourList[startHourIndex] == now.hour &&
minuteList[startMinuteIndex] < now.minute))) {
throw '开始时间不可早于当前时间';
}
}
if (endHourIndex < startHourIndex ||
(endHourIndex == startHourIndex &&
endMinuteIndex < startMinuteIndex)) {
throw '结束时间不能早于开始时间';
}
String timeSlot = '$startAt - $endAt';
if (isOverlap(widget.disableperiod, timeSlot)) {
throw '时间段重复';
}
widget.onSelected(
startAt: startAt, endAt: endAt, period: timeSlot);
SmartDialog.dismiss();
},
snackbarOffset: Offset(0, Adaptive.getHeight(context) * .45),
)
],
),
],
),
);
}
Widget startHourPickerView() {
return ListWheelScrollView(
controller: startHourScrollController,
itemExtent: itemExtent,
physics: const FixedExtentScrollPhysics(
parent: BouncingScrollPhysics(),
),
diameterRatio: 1.2,
children: [
for (int i = 0; i < hourList.length; i++)
InkWell(
onTap: () {
startHourScrollController.jumpToItem(i);
},
child: Container(
height: itemExtent,
alignment: Alignment.center,
child: Text(
'${hourList[i]}时',
style: getTextStyle(i == startHourIndex),
maxLines: 1,
),
))
],
onSelectedItemChanged: (index) {
setState(() {
startHourIndex = index;
});
},
);
}
Widget startMinutePickerView() {
return ListWheelScrollView(
controller: startMinuteScrollController,
itemExtent: itemExtent,
physics: const FixedExtentScrollPhysics(
parent: BouncingScrollPhysics(),
),
diameterRatio: 1.2,
children: [
for (int i = 0; i < minuteList.length; i++)
InkWell(
onTap: () {
startMinuteScrollController.jumpToItem(i);
},
child: Container(
height: itemExtent,
alignment: Alignment.center,
child: Text(
'${minuteList[i]}分',
style: getTextStyle(i == startMinuteIndex),
maxLines: 1,
),
))
],
onSelectedItemChanged: (index) {
setState(() {
startMinuteIndex = index;
});
},
);
}
Widget endHourPickerView() {
return ListWheelScrollView(
controller: endHourScrollController,
itemExtent: itemExtent,
physics: const FixedExtentScrollPhysics(
parent: BouncingScrollPhysics(),
),
diameterRatio: 1.2,
children: [
for (int i = 0; i < hourList.length; i++)
InkWell(
onTap: () {
endHourScrollController.jumpToItem(i);
},
child: Container(
height: itemExtent,
alignment: Alignment.center,
child: Text(
'${hourList[i]}时',
style: getTextStyle(i == endHourIndex),
maxLines: 1,
),
))
],
onSelectedItemChanged: (index) {
setState(() {
endHourIndex = index;
});
},
);
}
Widget endMinutePickerView() {
return ListWheelScrollView(
controller: endMinuteScrollController,
itemExtent: itemExtent,
physics: const FixedExtentScrollPhysics(
parent: BouncingScrollPhysics(),
),
diameterRatio: 1.2,
children: [
for (int i = 0; i < minuteList.length; i++)
InkWell(
onTap: () {
endMinuteScrollController.jumpToItem(i);
},
child: Container(
height: itemExtent,
alignment: Alignment.center,
child: Text(
'${minuteList[i]}分',
style: getTextStyle(i == endMinuteIndex),
maxLines: 1,
),
))
],
onSelectedItemChanged: (index) {
setState(() {
endMinuteIndex = index;
});
// updateDayList();
},
);
}
TextStyle getTextStyle(bool sel) {
return TextStyle(
color: textColor(context.isDarkMode),
fontSize: textSizeConfig.contentTextSize,
height: 1,
fontWeight: sel ? FontWeight.bold : FontWeight.normal,
);
}
}