import 'package:flutter/material.dart'; import 'package:food_hub_app/apis/recipe.dart'; import 'package:food_hub_app/models/recipe.dart'; import 'package:food_hub_app/utils/date_util.dart'; import 'package:food_hub_app/utils/index.dart'; import 'package:food_hub_app/widgets/common/index.dart'; import 'package:table_calendar/table_calendar.dart'; class RecipeCalendar extends StatefulWidget { const RecipeCalendar({super.key}); @override State createState() => _RecipeCalendarState(); } class _RecipeCalendarState extends State { DateTime _selectedDay = DateTime.now(); DateTime _focusedDay = DateTime.now(); List recordList = []; List selectRecordList = []; @override void initState() { super.initState(); refreshRecord(); } Future refreshRecord() async { final result = await queryRecordApi( getFirstDayOfMonth(_focusedDay), getLastDayOfMonth(_focusedDay), ); setState(() { recordList = result; if (recordList.isNotEmpty) { _selectedDay = DateTime.parse(recordList.last.date); } else { _selectedDay = _focusedDay; } refreshSelectRecord(); }); } void refreshSelectRecord() { setState(() { selectRecordList = recordList .where((record) => record.date == formatDateTime(_selectedDay)) .toList(); }); } TableCalendar recipeCalendar() { return TableCalendar( locale: 'zh_CN', headerStyle: const HeaderStyle( formatButtonVisible: false, titleCentered: true, ), firstDay: DateTime.utc(2010, 1, 1), lastDay: DateTime.utc(2100, 12, 31), focusedDay: _focusedDay, selectedDayPredicate: (day) => isSameDay(_selectedDay, day), onDaySelected: (selectedDay, focusedDay) { if (!isSameDay(_selectedDay, selectedDay)) { setState(() { _selectedDay = selectedDay; _focusedDay = focusedDay; refreshSelectRecord(); }); } }, onPageChanged: (focusedDay) { _focusedDay = focusedDay; refreshRecord(); }, // 自定义日期单元格构建器 calendarBuilders: CalendarBuilders( defaultBuilder: (context, day, focusedDay) => _buildDateWidget(day, false, false), selectedBuilder: (context, day, focusedDay) => _buildDateWidget(day, true, false), todayBuilder: (context, day, focusedDay) => _buildDateWidget(day, false, true), ), ); } Widget dailyItem(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(formatDateTime(_selectedDay, 'MM月dd日 EEEE')), if (selectRecordList.isEmpty) buildEmptyData() else ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: selectRecordList.length, itemBuilder: (context, index) { return recipeRecordItem(context, selectRecordList[index]); }, ), ], ); } Widget recipeRecordItem(BuildContext context, Record record) { final colors = Theme.of(context).colorScheme; return Card( elevation: 0, color: colors.inversePrimary, child: Padding( padding: EdgeInsets.all(10), child: Row( children: [ CircleAvatar( radius: 24, backgroundColor: colors.primary, child: Text( record.category[0], style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold, ), ), ), SizedBox(width: 10), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( record.name, style: TextStyle(fontWeight: FontWeight.bold), ), SizedBox(height: 5), Text(record.category, style: TextStyle(color: Colors.grey)), ], ), ), circleIconButton( context: context, icon: Icons.chevron_right, onPressed: () => {}, ), ], ), ), ); } Widget _buildDateWidget(DateTime day, bool isSelected, bool isToday) { // 检查当前日期是否在需要显示红点的列表中 bool shouldShowRedDot = recordList.any( (item) => item.date == formatDateTime(day), ); return Container( width: 40, height: 40, margin: EdgeInsets.all(2), decoration: BoxDecoration( color: isSelected ? Theme.of(context).primaryColor : isToday ? Colors.grey[300] : Colors.transparent, shape: BoxShape.circle, ), child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ // 日期数字 Text( day.day.toString(), style: TextStyle(color: isSelected ? Colors.white : Colors.black), ), // 底部红点 - 只在指定日期显示 if (shouldShowRedDot) Container( margin: EdgeInsets.only(top: 2), width: 6, height: 6, decoration: BoxDecoration( color: Colors.red, shape: BoxShape.circle, ), ), ], ), ); } @override Widget build(BuildContext context) { return Column( children: [ buildCard(context: context, child: recipeCalendar()), Expanded(child: buildCard(context: context, child: dailyItem(context))), ], ); } }