import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:lucide_icons/lucide_icons.dart'; import '../../../../core/theme/design_tokens.dart'; import '../widgets/bottom_dock.dart'; class CalendarMonthScreen extends StatefulWidget { const CalendarMonthScreen({super.key}); @override State createState() => _CalendarMonthScreenState(); } class _CalendarMonthScreenState extends State { DateTime _currentMonth = DateTime(2026, 2, 1); DateTime? _selectedDate; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF8FAFC), body: SafeArea( child: Column( children: [ _buildHeader(), Expanded( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.only(bottom: 84), child: _buildMonthContent(), ), ), ), _buildBottomDock(), ], ), ), ); } Widget _buildHeader() { return SizedBox( height: 76, child: Padding( padding: const EdgeInsets.only(left: 16, right: 16, top: 14, bottom: 6), child: Column( children: [ SizedBox( height: 56, child: Row( children: [ GestureDetector( onTap: () => _showMonthPicker(), child: Row( children: [ Text( '${_currentMonth.month}月', style: const TextStyle( fontSize: 22, fontWeight: FontWeight.w700, color: AppColors.slate900, ), ), const SizedBox(width: 6), const Icon( LucideIcons.chevronDown, size: 16, color: AppColors.slate900, ), ], ), ), ], ), ), ], ), ), ); } Widget _buildMonthContent() { return Column( children: [ _buildWeekdayHeader(), Container(height: 1, color: const Color(0xFFE5E7EB)), ..._buildWeeks(), ], ); } Widget _buildWeekdayHeader() { const weekdays = ['日', '一', '二', '三', '四', '五', '六']; return SizedBox( height: 40, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: weekdays .map( (day) => SizedBox( width: 36, child: Center( child: Text( day, style: const TextStyle( fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xFF9CA3AF), ), ), ), ), ) .toList(), ), ), ); } List _buildWeeks() { final firstDayOfMonth = DateTime( _currentMonth.year, _currentMonth.month, 1, ); final lastDayOfMonth = DateTime( _currentMonth.year, _currentMonth.month + 1, 0, ); final startWeekday = firstDayOfMonth.weekday % 7; final daysInMonth = lastDayOfMonth.day; final totalCells = ((daysInMonth + startWeekday) / 7).ceil() * 7; final weeks = []; for (var weekStart = 0; weekStart < totalCells; weekStart += 7) { weeks.add(_buildWeekRow(weekStart, startWeekday, daysInMonth)); if (weekStart + 7 < totalCells) { weeks.add(Container(height: 1, color: const Color(0xFFE5E7EB))); } } return weeks; } Widget _buildWeekRow(int weekStart, int startWeekday, int daysInMonth) { return Padding( padding: const EdgeInsets.only(left: 16, right: 16, top: 14, bottom: 0), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: List.generate(7, (index) { final dayIndex = weekStart + index - startWeekday + 1; if (dayIndex < 1 || dayIndex > daysInMonth) { return SizedBox(width: 36, height: 36); } final date = DateTime( _currentMonth.year, _currentMonth.month, dayIndex, ); final isSelected = _selectedDate != null && _selectedDate!.day == dayIndex && _selectedDate!.month == _currentMonth.month; return GestureDetector( onTap: () { setState(() { _selectedDate = date; }); }, child: Container( width: 36, height: 36, decoration: BoxDecoration( color: isSelected ? const Color(0xFFDBEAFE) : Colors.transparent, borderRadius: BorderRadius.circular(18), ), child: Center( child: Text( '$dayIndex', style: TextStyle( fontSize: 15, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, color: isSelected ? AppColors.blue600 : AppColors.slate900, ), ), ), ), ); }), ), const SizedBox(height: 10), _buildWeekEvents(weekStart, startWeekday, daysInMonth), ], ), ); } Widget _buildWeekEvents(int weekStart, int startWeekday, int daysInMonth) { return SizedBox( height: 70, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: List.generate(7, (index) { final dayIndex = weekStart + index - startWeekday + 1; if (dayIndex == 10) { return _buildEventDot(); } return const SizedBox(width: 38, height: 1); }), ), ); } Widget _buildEventDot() { return SizedBox( width: 76, height: 100, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: 20, padding: const EdgeInsets.symmetric(horizontal: 6), decoration: BoxDecoration( color: const Color(0xFFE5E7EB), borderRadius: BorderRadius.circular(6), ), child: const Center( child: Text( '购票提醒', style: TextStyle( fontSize: 9, fontWeight: FontWeight.w500, color: Color(0xFF6B7280), ), ), ), ), const SizedBox(height: 4), Container( height: 20, padding: const EdgeInsets.symmetric(horizontal: 6), decoration: BoxDecoration( color: const Color(0xFFE9D5FF), borderRadius: BorderRadius.circular(6), ), child: const Center( child: Text( '购票提醒', style: TextStyle( fontSize: 9, fontWeight: FontWeight.w500, color: Color(0xFF6B21A8), ), ), ), ), ], ), ); } void _showMonthPicker() { showModalBottomSheet( context: context, builder: (context) => Container( height: 300, color: Colors.white, child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), TextButton( onPressed: () => Navigator.pop(context), child: const Text('确定'), ), ], ), Expanded( child: Row( children: [ Expanded( child: CupertinoPicker( itemExtent: 40, scrollController: FixedExtentScrollController( initialItem: _currentMonth.year - 2020, ), onSelectedItemChanged: (index) { setState(() { _currentMonth = DateTime( 2020 + index, _currentMonth.month, 1, ); }); }, children: List.generate(20, (index) { return Center(child: Text('${2020 + index}年')); }), ), ), Expanded( child: CupertinoPicker( itemExtent: 40, scrollController: FixedExtentScrollController( initialItem: _currentMonth.month - 1, ), onSelectedItemChanged: (index) { setState(() { _currentMonth = DateTime( _currentMonth.year, index + 1, 1, ); }); }, children: List.generate(12, (index) { return Center(child: Text('${index + 1}月')); }), ), ), ], ), ), ], ), ), ); } Widget _buildBottomDock() { return BottomDock( activeTab: DockTab.calendar, onTodoTap: () {}, onCalendarTap: () {}, onHomeTap: () => Navigator.of(context).pop(), ); } }