import 'package:flisp_app/provider/todo_provider.dart'; import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:provider/provider.dart'; import 'package:flisp_app/models/todo.dart'; import 'package:flisp_app/utils/date_utils.dart'; class TodoForm extends StatefulWidget { final GlobalKey formKey; final bool isEditing; final Todo? initialTodo; const TodoForm({ super.key, required this.formKey, required this.isEditing, this.initialTodo, }); @override State createState() => _TodoFormState(); } class _TodoFormState extends State { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { final int maxTitleCount = 10; final int maxContentCount = 20; final store = Provider.of(context); Widget buildTitle() { return Row( children: [ Icon( widget.isEditing ? Icons.edit_note : Icons.add_task, color: Colors.orange, size: 24, ), SizedBox(width: 8), Text( widget.isEditing ? '编辑待办事项' : '添加待办事项', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.orange, ), ), ], ); } FormBuilderTextField buildTitleField() { return FormBuilderTextField( name: 'title', initialValue: store.formItem.title, onChanged: (value) { setState(() { store.formItem.title = value ?? ''; }); }, decoration: InputDecoration( labelText: '标题', hintText: '请输入待办事项标题...', counterText: '', suffixText: '${store.formItem.title.length}/$maxTitleCount', border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.orange), ), filled: true, fillColor: Colors.white, prefixIcon: Icon(Icons.title, color: Colors.blue), contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14), ), maxLength: maxTitleCount, validator: (value) { if (value == null || value.isEmpty) { return '请输入标题'; } if (value.length > maxTitleCount) { return '标题不能超过$maxTitleCount个字符'; } return null; }, ); } FormBuilderTextField buildDescriptionField() { return FormBuilderTextField( name: 'description', initialValue: store.formItem.content, onChanged: (value) { setState(() { store.formItem.content = value ?? ''; }); }, decoration: InputDecoration( labelText: '内容', hintText: '请输入待办事项内容...', counterText: '', suffixText: '${store.formItem.content.length}/$maxContentCount', border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.orange), ), filled: true, fillColor: Colors.white, prefixIcon: Icon(Icons.description, color: Colors.green), contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14), ), maxLines: 2, maxLength: maxContentCount, validator: (value) { if (value != null && value.length > maxContentCount) { return '内容不能超过$maxContentCount个字符'; } return null; }, ); } IconButton buildClearDateSuffixIcon() { return IconButton( icon: Icon(Icons.clear, size: 18), onPressed: () { setState(() { store.formItem.dueDate = null; }); widget.formKey.currentState?.fields['dueDate']?.didChange(null); }, ); } FormBuilderDateTimePicker buildDateField() { return FormBuilderDateTimePicker( name: 'dueDate', initialValue: store.formItem.dueDate, inputType: InputType.date, onChanged: (value) { setState(() { store.formItem.dueDate = value; }); }, decoration: InputDecoration( labelText: store.formItem.dueDate == null ? '选择截止日期' : '截止: ${formatDate(store.formItem.dueDate!)}', labelStyle: TextStyle( color: store.formItem.dueDate == null ? Colors.grey : Colors.black87, ), prefixIcon: Icon(Icons.calendar_today, color: Colors.purple), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.orange), ), filled: true, fillColor: Colors.white, contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14), suffixIcon: store.formItem.dueDate != null ? buildClearDateSuffixIcon() : null, ), validator: (value) { if (value != null && value.isBefore(DateTime.now().subtract(Duration(days: 1)))) { return '不能选择过去的日期'; } return null; }, ); } FormBuilderRadioGroup builderRadioGroup() { return FormBuilderRadioGroup( name: 'priority', initialValue: store.formItem.priority, decoration: InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.zero, ), orientation: OptionsOrientation.horizontal, wrapSpacing: 6, options: TodoPriority.values.map((priority) { return FormBuilderFieldOption( value: priority, child: Row( mainAxisSize: MainAxisSize.min, children: [Text(priority.label)], ), ); }).toList(), onChanged: (value) { if (value != null) { setState(() { store.formItem.priority = value; }); } }, ); } Container buildPriorityField() { return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade300, width: 1), ), padding: EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.flag, color: Colors.orange), SizedBox(width: 6), Text('优先级'), ], ), builderRadioGroup(), ], ), ); } FormBuilder buildForm() { return FormBuilder( key: widget.formKey, child: Column( mainAxisSize: MainAxisSize.min, children: [ buildTitleField(), SizedBox(height: 12), buildDescriptionField(), SizedBox(height: 12), buildDateField(), SizedBox(height: 12), buildPriorityField(), ], ), ); } return Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [buildTitle(), SizedBox(height: 20), buildForm()], ), ); } }