import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:lucide_icons/lucide_icons.dart'; import '../../../../core/theme/design_tokens.dart'; import '../../data/models/schedule_item_model.dart'; import '../../data/services/mock_calendar_service.dart'; class CreateEventSheet extends StatefulWidget { final DateTime? initialDate; final ScheduleItemModel? editingEvent; final VoidCallback? onSaved; const CreateEventSheet({ super.key, this.initialDate, this.editingEvent, this.onSaved, }); static Future show( BuildContext context, { DateTime? initialDate, VoidCallback? onSaved, }) { return showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => CreateEventSheet(initialDate: initialDate, onSaved: onSaved), ); } static Future edit( BuildContext context, ScheduleItemModel event, { VoidCallback? onSaved, }) { return showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => CreateEventSheet(editingEvent: event, onSaved: onSaved), ); } @override State createState() => _CreateEventSheetState(); } class _CreateEventSheetState extends State with SingleTickerProviderStateMixin { late TabController _tabController; final _titleController = TextEditingController(); final _descriptionController = TextEditingController(); final _locationController = TextEditingController(); final _notesController = TextEditingController(); late DateTime _startDate; late DateTime _startTime; DateTime? _endDate; DateTime? _endTime; String _selectedColor = '#3B82F6'; bool get _isEditing => widget.editingEvent != null; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); if (_isEditing) { final event = widget.editingEvent!; _titleController.text = event.title; _descriptionController.text = event.description ?? ''; _locationController.text = event.metadata?.location ?? ''; _notesController.text = event.metadata?.notes ?? ''; _startDate = event.startAt; _startTime = event.startAt; _endDate = event.endAt; _endTime = event.endAt; _selectedColor = event.metadata?.color ?? '#3B82F6'; } else { final now = widget.initialDate ?? DateTime.now(); _startDate = now; _startTime = now; _endDate = now; _endTime = now.add(const Duration(hours: 1)); } _titleController.addListener(() => setState(() {})); } @override void dispose() { _tabController.dispose(); _titleController.dispose(); _descriptionController.dispose(); _locationController.dispose(); _notesController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( height: MediaQuery.of(context).size.height * 0.85, decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), child: Column( children: [ _buildHeader(), _buildTabBar(), Expanded(child: _buildTabContent()), ], ), ); } Widget _buildHeader() { return Container( height: 56, padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( onTap: () => Navigator.pop(context), child: const Icon( LucideIcons.x, size: 24, color: AppColors.slate700, ), ), Text( _isEditing ? '编辑日程' : '新建日程', style: const TextStyle( fontSize: 17, fontWeight: FontWeight.w600, color: AppColors.slate900, ), ), GestureDetector( onTap: _saveEvent, child: Text( '保存', style: TextStyle( fontSize: 17, fontWeight: FontWeight.w600, color: _titleController.text.trim().isNotEmpty ? AppColors.blue600 : AppColors.slate400, ), ), ), ], ), ); } Widget _buildTabBar() { return Container( decoration: const BoxDecoration( border: Border(bottom: BorderSide(color: AppColors.border)), ), child: TabBar( controller: _tabController, labelColor: AppColors.blue600, unselectedLabelColor: AppColors.slate600, indicatorColor: AppColors.blue600, tabs: const [ Tab(text: '基础'), Tab(text: '进阶'), ], ), ); } Widget _buildTabContent() { return TabBarView( controller: _tabController, children: [_buildBasicTab(), _buildAdvancedTab()], ); } Widget _buildBasicTab() { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildTextField('标题', _titleController, '请输入日程标题'), const SizedBox(height: 20), _buildDateTimePicker('开始', _startDate, _startTime, (date, time) { setState(() { _startDate = date; _startTime = time; }); }), const SizedBox(height: 20), _buildDateTimePicker( '结束', _endDate ?? _startDate, _endTime ?? _startTime, (date, time) { setState(() { _endDate = date; _endTime = time; }); }, isOptional: true, ), ], ), ); } Widget _buildAdvancedTab() { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildTextField('描述', _descriptionController, '请输入描述'), const SizedBox(height: 20), _buildTextField('地点', _locationController, '请输入地点'), const SizedBox(height: 20), _buildColorPicker(), const SizedBox(height: 20), _buildTextField('备注', _notesController, '请输入备注', maxLines: 3), ], ), ); } Widget _buildTextField( String label, TextEditingController controller, String hint, { int maxLines = 1, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: AppColors.slate700, ), ), const SizedBox(height: 8), TextField( controller: controller, maxLines: maxLines, decoration: InputDecoration( hintText: hint, hintStyle: const TextStyle(color: AppColors.slate400), filled: true, fillColor: const Color(0xFFF1F5F9), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 12, ), ), ), ], ); } Widget _buildDateTimePicker( String label, DateTime date, DateTime time, Function(DateTime, DateTime) onChanged, { bool isOptional = false, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label + (isOptional ? '(可选)' : ''), style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: AppColors.slate700, ), ), const SizedBox(height: 8), Row( children: [ Expanded( child: GestureDetector( onTap: () => _showDatePicker(date, (newDate) { onChanged(newDate, time); }), child: Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 12, ), decoration: BoxDecoration( color: const Color(0xFFF1F5F9), borderRadius: BorderRadius.circular(10), ), child: Text( '${date.year}年${date.month}月${date.day}日', style: const TextStyle( fontSize: 15, color: AppColors.slate900, ), ), ), ), ), const SizedBox(width: 12), Expanded( child: GestureDetector( onTap: () => _showTimePicker(time, (newTime) { onChanged(date, newTime); }), child: Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 12, ), decoration: BoxDecoration( color: const Color(0xFFF1F5F9), borderRadius: BorderRadius.circular(10), ), child: Text( '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}', style: const TextStyle( fontSize: 15, color: AppColors.slate900, ), ), ), ), ), ], ), ], ); } Widget _buildColorPicker() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '颜色', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: AppColors.slate700, ), ), const SizedBox(height: 8), Row( children: defaultColors.map((color) { final colorHex = '#${color.value.toRadixString(16).substring(2).toUpperCase()}'; final isSelected = _selectedColor == colorHex; return GestureDetector( onTap: () => setState(() => _selectedColor = colorHex), child: Container( margin: const EdgeInsets.only(right: 12), width: 32, height: 32, decoration: BoxDecoration( color: color, shape: BoxShape.circle, border: isSelected ? Border.all(color: AppColors.slate900, width: 2) : null, ), child: isSelected ? const Icon(Icons.check, size: 16, color: Colors.white) : null, ), ); }).toList(), ), ], ); } void _showDatePicker(DateTime initial, Function(DateTime) onChanged) { showModalBottomSheet( context: context, builder: (context) => Container( height: 280, 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: CupertinoDatePicker( mode: CupertinoDatePickerMode.date, initialDateTime: initial, onDateTimeChanged: onChanged, ), ), ], ), ), ); } void _showTimePicker(DateTime initial, Function(DateTime) onChanged) { showModalBottomSheet( context: context, builder: (context) => Container( height: 280, 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: CupertinoDatePicker( mode: CupertinoDatePickerMode.time, initialDateTime: initial, onDateTimeChanged: onChanged, ), ), ], ), ), ); } void _saveEvent() { if (_titleController.text.trim().isEmpty) return; final startAt = DateTime( _startDate.year, _startDate.month, _startDate.day, _startTime.hour, _startTime.minute, ); DateTime? endAt; if (_endDate != null && _endTime != null) { endAt = DateTime( _endDate!.year, _endDate!.month, _endDate!.day, _endTime!.hour, _endTime!.minute, ); } final metadata = ScheduleMetadata( color: _selectedColor, location: _locationController.text.trim().isNotEmpty ? _locationController.text.trim() : null, notes: _notesController.text.trim().isNotEmpty ? _notesController.text.trim() : null, ); final event = ScheduleItemModel( id: _isEditing ? widget.editingEvent!.id : 'evt_${DateTime.now().millisecondsSinceEpoch}', title: _titleController.text.trim(), description: _descriptionController.text.trim().isNotEmpty ? _descriptionController.text.trim() : null, startAt: startAt, endAt: endAt, metadata: metadata, ); final service = CalendarService(); if (_isEditing) { service.updateEvent(event); } else { service.addEvent(event); } widget.onSaved?.call(); Navigator.pop(context); } }