main
  1import 'package:blood_pressure_app/features/input/forms/form_base.dart';
  2import 'package:blood_pressure_app/l10n/app_localizations.dart';
  3import 'package:blood_pressure_app/model/storage/settings_store.dart';
  4import 'package:flutter/material.dart';
  5import 'package:intl/intl.dart';
  6import 'package:provider/provider.dart';
  7
  8/// Input to allow date and time input.
  9class DateTimeForm extends FormBase<DateTime> {
 10  /// Create input to allow date and time input.
 11  const DateTimeForm({super.key,
 12    super.initialValue,
 13  });
 14
 15  @override
 16  FormStateBase<DateTime, DateTimeForm> createState() => DateTimeFormState();
 17}
 18
 19/// State of a [DateTimeForm].
 20class DateTimeFormState extends FormStateBase<DateTime, DateTimeForm> {
 21  late DateTime _time;
 22
 23  String? _error;
 24
 25  @override
 26  void initState() {
 27    super.initState();
 28    _time = widget.initialValue ?? DateTime.now();
 29  }
 30
 31  @override
 32  DateTime? save() => validate() ? _time : null;
 33
 34  @override
 35  bool isEmptyInputFocused() => false;
 36
 37  @override
 38  bool validate() {
 39    if (context.read<Settings>().validateInputs && _time.isAfter(DateTime.now())) {
 40      setState(() {
 41        _error = AppLocalizations.of(context)!.errTimeAfterNow;
 42      });
 43      return false;
 44    } else if (_error != null) {
 45      setState(() {
 46        _error = null;
 47      });
 48    }
 49    return true;
 50  }
 51
 52  @override
 53  void fillForm(DateTime? value) => setState(() {
 54    _time = value ?? DateTime.now();
 55  });
 56
 57  Future<void> _openDatePicker() async {
 58    final now = DateTime.now();
 59    final date = await showDatePicker(
 60      context: context,
 61      initialDate: _time,
 62      firstDate: DateTime.fromMillisecondsSinceEpoch(1),
 63      lastDate: _time.isAfter(now) ? _time : now,
 64    );
 65    if (date == null) return;
 66    setState(() => _time = date.copyWith(
 67      hour: _time.hour,
 68      minute: _time.minute,
 69    ));
 70
 71  }
 72
 73  Future<void> _openTimePicker() async {
 74    final timeOfDay = await showTimePicker(
 75      context: context,
 76      initialTime: TimeOfDay.fromDateTime(_time),
 77    );
 78    if (timeOfDay == null) return;
 79    setState(() => _time = _time.copyWith(
 80      hour: timeOfDay.hour,
 81      minute: timeOfDay.minute,
 82    ));
 83  }
 84
 85  Widget _buildInput(String content, void Function() onTap, String label, [String? error]) => Expanded(
 86    child: InputDecorator(
 87      decoration: InputDecoration(
 88        labelText: label,
 89        error: error == null ? null : Text(error),
 90      ),
 91      child: GestureDetector(
 92        onTap: onTap,
 93        child: Text(content, style: Theme.of(context).textTheme.bodyLarge)
 94      ),
 95    ),
 96  );
 97
 98  @override
 99  Widget build(BuildContext context) {
100    final date = DateFormat('yyyy-MM-dd').format(_time);
101    final timeOfDay = DateFormat('HH:mm').format(_time);
102    return Row(
103      children: [
104        _buildInput(date, _openDatePicker, AppLocalizations.of(context)!.date),
105        SizedBox(width: 8,),
106        _buildInput(timeOfDay, _openTimePicker, AppLocalizations.of(context)!.time, _error),
107      ],
108    );
109  }
110}