import 'package:flutter/material.dart'; import '../service/tools.dart' show getIsoDateString; import '../service/validators.dart'; class TimeSelector extends StatefulWidget { const TimeSelector({ super.key, this.initialDueDateTime, this.nextFocusNode, required this.dueDateController, required this.dueTimeController, this.formKey, }); final DateTime? initialDueDateTime; final GlobalKey? formKey; final FocusNode? nextFocusNode; final TextEditingController dueDateController; final TextEditingController dueTimeController; @override State createState() => _TimeSelectorState(); } class _TimeSelectorState extends State { final dueDateFocusNode = FocusNode(); final dueTimeFocusNode = FocusNode(); bool isDueTimeEnabled = false; @override void initState() { isDueTimeEnabled = widget.initialDueDateTime != null; super.initState(); } @override Widget build(BuildContext context) { return Flex( direction: Axis.horizontal, children: [ Flexible( flex: 3, child: TextFormField( focusNode: dueDateFocusNode, controller: widget.dueDateController, onChanged: maybeEnableDueTime, onFieldSubmitted: (_) { isDueTimeEnabled ? dueDateFocusNode.nextFocus() : widget.nextFocusNode?.requestFocus(); }, decoration: InputDecoration( label: Text('Due Date'), suffixIcon: IconButton( onPressed: () async { final result = await onOpenCalendarPickerPressed(); if (result != null) { final dateString = getIsoDateString(result); widget.dueDateController.text = dateString; maybeEnableDueTime(dateString); widget.formKey?.currentState?.validate(); dueTimeFocusNode.requestFocus(); } }, icon: Icon(Icons.calendar_month), ), ), validator: dateTimeValidator, keyboardType: TextInputType.datetime, textInputAction: TextInputAction.next, ), ), Padding(padding: EdgeInsetsGeometry.only(left: 10)), Flexible( flex: 2, child: TextFormField( focusNode: dueTimeFocusNode, onFieldSubmitted: (_) => dueTimeFocusNode.nextFocus(), controller: widget.dueTimeController, enabled: isDueTimeEnabled, decoration: InputDecoration( label: Text('Due Time'), suffixIcon: IconButton( onPressed: () async { final result = await onOpenTimePickerPressed(); if (result != null && context.mounted) { widget.dueTimeController.text = result.format(context); widget.nextFocusNode?.requestFocus(); } }, icon: Icon(Icons.schedule), ), ), validator: timeValidator, keyboardType: TextInputType.text, textInputAction: TextInputAction.next, ), ), ], ); } Future onOpenCalendarPickerPressed() { return showDialog( context: context, builder: (context) => DatePickerDialog( firstDate: DateTime(DateTime.now().year - 100), lastDate: DateTime(DateTime.now().year + 100), initialDate: DateTime.tryParse(widget.dueDateController.text) ?? DateTime.now(), ), ); } Future onOpenTimePickerPressed() { return showDialog( context: context, builder: (context) => TimePickerDialog( initialTime: TimeOfDay.fromDateTime( widget.initialDueDateTime ?? DateTime.now(), ), ), ); } void maybeEnableDueTime(String value) { if (value.isNotEmpty && dateTimeValidator(value) == null) { setState(() { isDueTimeEnabled = true; }); } else if (isDueTimeEnabled) { setState(() { isDueTimeEnabled = false; }); } } }