Files
tuiche/lib/component/base/SleepCalendarWidget.dart
2025-05-20 14:00:44 +08:00

292 lines
9.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.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/date/CalendarController.dart';
import 'SleepdateWidget.dart';
class SleepCalendarWidget extends StatefulWidget {
final int? timestamp;
final ValueChanged<DateTime>? onDateSelected;
final int? type; // 新增参数,默认日历类型为日
final Color highlightColor; // ✅ 新增
const SleepCalendarWidget({
super.key,
this.timestamp,
this.onDateSelected,
this.type = 1,
this.highlightColor = Colors.black, // ✅ 默认值
});
@override
State<SleepCalendarWidget> createState() => _SleepCalendarWidgetState();
}
class _SleepCalendarWidgetState extends State<SleepCalendarWidget> {
CalendarController calendarController = Get.find();
@override
void initState() {
super.initState();
final initialDate = widget.timestamp != null
? DateTime.fromMillisecondsSinceEpoch(widget.timestamp!)
: DateTime.now();
calendarController.displayedMonth.value = initialDate;
calendarController.selectedDate.value = initialDate;
}
@override
Widget build(BuildContext context) {
List<Map<String, dynamic>> showLabel = [
{"level": 1, "name": "优秀", "color": Color(0xFF4CAF50)},
{"level": 2, "name": "良好", "color": Color(0xFF8BC34A)},
{"level": 3, "name": "合格", "color": Color(0xFFFFC107)},
{"level": 4, "name": "注意", "color": Color(0xFFF44336)},
{"level": 5, "name": "无报告", "color": Color(0xFF9E9E9E)},
];
return Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.rpx),
topRight: Radius.circular(20.rpx),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildHeader(),
_buildCalendarBody(showLabel),
],
),
);
}
Widget _buildHeader() {
return Container(
width: double.infinity,
constraints: BoxConstraints(minHeight: 90.rpx),
decoration: BoxDecoration(
color: const Color(0xFF313541),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.rpx),
topRight: Radius.circular(20.rpx),
),
),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 65.rpx),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.grey,
padding: EdgeInsets.all(8.rpx),
onTap: () => calendarController.previousMonth(),
child: Icon(
Icons.arrow_back_ios_new,
color: const Color(0xFF6D6F73),
size: 24.rpx,
),
),
Obx(() => Text(
'${calendarController.displayedMonth.value.year}${calendarController.displayedMonth.value.month}',
style: TextStyle(
color: Colors.white,
fontSize: 30.rpx,
),
)),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.grey,
padding: EdgeInsets.all(8.rpx),
onTap: () => calendarController.nextMonth(),
child: Icon(
Icons.arrow_forward_ios,
color: const Color(0xFF6D6F73),
size: 24.rpx,
),
),
],
),
),
);
}
Widget _buildCalendarBody(List<Map<String, dynamic>> showLabel) {
return Container(
width: double.infinity,
constraints: BoxConstraints(minHeight: 720.rpx),
decoration: const BoxDecoration(color: Color(0xFF242835)),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(65.rpx, 13.rpx, 65.rpx, 38.rpx),
child: Obx(() {
final daysInMonth = calendarController.getDaysInMonth();
final calendarRows = calendarController.getCalendarRows(daysInMonth);
final selectedDate = calendarController.selectedDate.value;
return Column(
mainAxisSize: MainAxisSize.max,
children: [
// 仅当为日历模式显示周标题
_buildWeekdayHeader(),
// 日历日期格子,支持日和周的高亮逻辑
_buildCalendarGrid(calendarRows, selectedDate),
// TODO: 你可以扩展 month 类型的展示
SizedBox(height: 55.rpx),
_buildLegend(showLabel),
],
);
}),
),
);
}
Widget _buildWeekdayHeader() {
return Container(
constraints: BoxConstraints(minHeight: 90.rpx),
child: Row(
children: ["", "", "", "", "", "", ""].map((day) {
return Expanded(
child: Center(
child: Text(
day,
style: TextStyle(
color: stringToColor("#FFFFFF"),
fontSize: AppConstants().normal_text_fontSize,
),
),
),
);
}).toList(),
),
);
}
Widget _buildCalendarGrid(
List<List<DateTime>> calendarRows, DateTime? selectedDate) {
final isMonthSelected = widget.type == 3;
Widget content = Column(
children: calendarRows.map((week) {
final isWeekSelected = widget.type == 2 &&
selectedDate != null &&
week.any((d) =>
d.year == selectedDate.year &&
d.month == selectedDate.month &&
d.day == selectedDate.day);
final row = Row(
children: week.map((date) {
if (date.year == 0) {
return const Expanded(child: SizedBox.shrink());
}
final isSelected = widget.type == 1 &&
selectedDate != null &&
date.year == selectedDate.year &&
date.month == selectedDate.month &&
date.day == selectedDate.day;
return Expanded(
child: SleepdateWidget(
highlightColor: widget.highlightColor, // ✅ 传入高亮颜色
date: date,
isSelected: isSelected,
onTap: () {
calendarController.selectDate(date);
widget.onDateSelected?.call(date);
Get.back();
},
),
);
}).toList(),
);
if (isWeekSelected) {
return Container(
decoration: BoxDecoration(
color: widget.highlightColor,
borderRadius:
BorderRadius.circular(AppConstants().button_container_radius),
),
padding: EdgeInsets.symmetric(vertical: 6.rpx),
margin: EdgeInsets.symmetric(vertical: 6.rpx),
child: row,
);
} else {
return row;
}
}).toList(),
);
// 如果是月份模式,包一层黑色背景容器
if (isMonthSelected && selectedDate != null) {
final displayedMonth = calendarController.displayedMonth.value;
final isSameMonth = displayedMonth.year == selectedDate.year &&
displayedMonth.month == selectedDate.month;
if (isSameMonth) {
// ✅ 当前显示的月 == 当前选中的月 → 加高亮外框
return Container(
decoration: BoxDecoration(
color: widget.highlightColor, // 背景淡色
borderRadius:
BorderRadius.circular(AppConstants().normal_container_radius),
// border: Border.all(
// color: widget.highlightColor,
// width: 2.rpx,
// ),
),
// padding: EdgeInsets.symmetric(vertical: 0.rpx, horizontal: 0.rpx),
// margin: EdgeInsets.symmetric(vertical: 0.rpx),
child: content,
);
} else {
return content;
}
} else {
return content;
}
}
Widget _buildLegend(List<Map<String, dynamic>> showLabel) {
return Wrap(
spacing: 20.rpx,
runSpacing: 20.rpx,
children: showLabel.map((item) {
return Container(
padding: EdgeInsets.all(5.rpx),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 20.rpx,
height: 20.rpx,
decoration: BoxDecoration(
color: item["color"],
borderRadius: BorderRadius.circular(10.rpx),
),
),
SizedBox(width: 8.rpx),
Text(
item["name"],
style: TextStyle(
color: Colors.white,
fontSize: 24.rpx,
),
),
],
),
);
}).toList(),
);
}
}