Files
flisp_app/lib/widgets/calendar_form.dart
2025-11-21 14:58:11 +08:00

298 lines
8.9 KiB
Dart

import 'package:flisp_app/models/calendar.dart';
import 'package:flisp_app/provider/calendar_provider.dart';
import 'package:flisp_app/utils/date_utils.dart';
import 'package:flisp_app/widgets/common.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class CalendarForm extends StatefulWidget {
final GlobalKey<FormBuilderState> formKey;
final bool isEditing;
final Calendar? initialCalendar;
const CalendarForm({
super.key,
required this.formKey,
required this.isEditing,
this.initialCalendar,
});
@override
State<CalendarForm> createState() => _CalendarFormState();
}
class _CalendarFormState extends State<CalendarForm> {
final int maxTitleCount = 10;
@override
void initState() {
super.initState();
}
Widget buildTitle() {
final colors = Theme.of(context).colorScheme;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
widget.isEditing ? Icons.edit_note : Icons.add_task,
color: colors.primary,
size: 24,
),
SizedBox(width: 8),
Text(
widget.isEditing ? '编辑日程事项' : '添加日程事项',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: colors.primary,
),
),
],
);
}
String? titleFieldValidator(value) {
if (value == null || value.isEmpty) {
return '请输入标题';
}
if (value.length > maxTitleCount) {
return '标题不能超过$maxTitleCount个字符';
}
return null;
}
FormBuilderTextField buildTitleField(CalendarProvider provider) {
final colors = Theme.of(context).colorScheme;
return FormBuilderTextField(
name: 'title',
initialValue: provider.formItem.title,
onChanged: (value) {
setState(() {
provider.formItem.title = value ?? '';
});
},
decoration: InputDecoration(
label: RichText(
text: TextSpan(
text: '内容',
style: TextStyle(
color: Colors.grey,
fontSize: 16,
fontFamily: 'CustomFont',
),
children: const [
TextSpan(
text: '*',
style: TextStyle(
color: Colors.red,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
),
hintText: '请输入日程标题...',
hintStyle: TextStyle(color: Colors.grey),
counterText: '',
suffixText: '${provider.formItem.title.length}/$maxTitleCount',
border: buildFormBoard(),
enabledBorder: buildFormEnabledBoard(),
focusedBorder: buildFormFocusedBoard(colors),
filled: true,
fillColor: colors.surface,
prefixIcon: Icon(Icons.title, color: Colors.blue),
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14),
),
maxLength: maxTitleCount,
validator: (value) => titleFieldValidator(value),
);
}
String? startTimeFieldValidator(CalendarProvider provider, value) {
if (value == null) {
return '请选择开始时间';
}
if (value.isBefore(DateTime.now())) {
return '不能选择过去的日期';
}
final endTime = provider.formItem.endTime;
if (endTime != null && endTime.isBefore(value)) {
return '结束时间不能早于开始时间';
}
if (endTime != null && endTime.isAtSameMomentAs(value)) {
return '开始时间不能等于结束时间';
}
return null;
}
FormBuilderDateTimePicker buildStartTimeField(CalendarProvider provider) {
final colors = Theme.of(context).colorScheme;
var startTime = provider.formItem.startTime;
return FormBuilderDateTimePicker(
name: 'startTime',
format: DateFormat('yyyy-MM-dd HH:mm:ss'),
initialValue: startTime,
inputType: InputType.both,
onChanged: (value) {
setState(() {
provider.formItem.startTime = value!;
});
},
decoration: InputDecoration(
labelText:
startTime == null ? '选择开始时间' : '开始时间: ${formatTime(startTime)}',
labelStyle: TextStyle(color: Colors.grey),
prefixIcon: Icon(Icons.calendar_month, color: Colors.purple),
border: buildFormBoard(),
enabledBorder: buildFormEnabledBoard(),
focusedBorder: buildFormFocusedBoard(colors),
filled: true,
fillColor: colors.surface,
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14),
),
validator: (value) => startTimeFieldValidator(provider, value),
);
}
String? endTimeFieldValidator(CalendarProvider provider, value) {
if (value == null) {
return '请选择结束时间';
}
if (value.isBefore(DateTime.now())) {
return '不能选择过去的日期';
}
final startTime = provider.formItem.startTime;
if (startTime != null && value.isBefore(startTime)) {
return '结束时间不能早于开始时间';
}
if (startTime != null && startTime.isAtSameMomentAs(value)) {
return '开始时间不能等于结束时间';
}
return null;
}
FormBuilderDateTimePicker buildEndTimeField(CalendarProvider provider) {
final colors = Theme.of(context).colorScheme;
var endTime = provider.formItem.endTime;
return FormBuilderDateTimePicker(
name: 'endTime',
format: DateFormat('yyyy-MM-dd HH:mm:ss'),
initialValue: endTime,
inputType: InputType.both,
onChanged: (value) {
setState(() {
provider.formItem.endTime = value!;
});
},
decoration: InputDecoration(
labelText: endTime == null ? '选择结束时间' : '结束时间: ${formatTime(endTime)}',
labelStyle: TextStyle(color: Colors.grey),
prefixIcon: Icon(Icons.calendar_month, color: Colors.purple),
border: buildFormBoard(),
enabledBorder: buildFormEnabledBoard(),
focusedBorder: buildFormFocusedBoard(colors),
filled: true,
fillColor: colors.surface,
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14),
),
validator: (value) => endTimeFieldValidator(provider, value),
);
}
IconButton buildClearScheduled(CalendarProvider provider) {
return IconButton(
icon: Icon(Icons.clear, size: 18),
onPressed: () {
setState(() {
provider.formItem.scheduledTime = null;
});
widget.formKey.currentState?.fields['scheduledTime']?.didChange(null);
},
);
}
String? scheduledTimeFieldValidator(value) {
if (value != null && value.isBefore(DateTime.now())) {
return '不能选择过去的日期';
}
return null;
}
FormBuilderDateTimePicker buildScheduledTimeField(CalendarProvider provider) {
final colors = Theme.of(context).colorScheme;
var scheduledTime = provider.formItem.scheduledTime;
return FormBuilderDateTimePicker(
name: 'scheduledTime',
format: DateFormat('yyyy-MM-dd HH:mm:ss'),
initialValue: scheduledTime,
inputType: InputType.both,
onChanged: (value) {
setState(() {
provider.formItem.scheduledTime = value;
});
},
decoration: InputDecoration(
labelText:
scheduledTime == null
? '选择提醒时间'
: '提醒时间: ${formatTime(scheduledTime)}',
labelStyle: TextStyle(color: Colors.grey),
prefixIcon: Icon(Icons.calendar_month, color: Colors.purple),
border: buildFormBoard(),
enabledBorder: buildFormEnabledBoard(),
focusedBorder: buildFormFocusedBoard(colors),
filled: true,
fillColor: colors.surface,
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14),
suffixIcon:
scheduledTime != null ? buildClearScheduled(provider) : null,
),
validator: (value) => scheduledTimeFieldValidator(value),
);
}
FormBuilder buildForm(CalendarProvider provider) {
return FormBuilder(
key: widget.formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
buildTitleField(provider),
SizedBox(height: 12),
buildStartTimeField(provider),
SizedBox(height: 12),
buildEndTimeField(provider),
SizedBox(height: 12),
buildScheduledTimeField(provider),
],
),
);
}
@override
Widget build(BuildContext context) {
final provider = Provider.of<CalendarProvider>(context);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [buildTitle(), SizedBox(height: 20), buildForm(provider)],
),
);
}
}