diff --git a/lib/components/date_time_picker.dart b/lib/components/date_time_picker.dart index 25054c06..fc3fc095 100644 --- a/lib/components/date_time_picker.dart +++ b/lib/components/date_time_picker.dart @@ -1,6 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +/// First shows a DatePicker for the day then shows a TimePicker for the time of day. +/// +/// As per the decision of the material design team a TimePicker isn't able to limit the range +/// (https://github.com/flutter/flutter/issues/23717#issuecomment-966601311), therefore a manual check for the time of +/// day will be needed. Please refer to the validator on the AddMeasurementPage for an example Future showDateTimePicker({ required BuildContext context, DateTime? initialDate, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9dab8001..5860081a 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -336,5 +336,6 @@ "last30Days": "30 days", "@last30Days": {}, "allowMissingValues": "Allow missing values", - "@allowMissingValues": {} + "@allowMissingValues": {}, + "errTimeAfterNow": "The selected time of day is after this moment. We have automatically reset it to the current time. You can disable this validation in the settings!" } diff --git a/lib/screens/add_measurement.dart b/lib/screens/add_measurement.dart index c3f21d1d..6d1a7e1f 100644 --- a/lib/screens/add_measurement.dart +++ b/lib/screens/add_measurement.dart @@ -69,14 +69,23 @@ class _AddMeasurementPageState extends State { if (settings.allowManualTimeInput) { return GestureDetector( onTap: () async { + final now = DateTime.now(); + final selectionEnd = now.copyWith(minute: now.minute+5); + final messenger = ScaffoldMessenger.of(context); + final errTimeAfterNow = AppLocalizations.of(context)!.errTimeAfterNow; var selectedTime = await showDateTimePicker( context: context, firstDate: DateTime.fromMillisecondsSinceEpoch(0), - lastDate: DateTime.now().copyWith(second: DateTime.now().second + 1), + lastDate: selectionEnd, initialDate: _time); if (selectedTime != null) { + if (settings.validateInputs && selectedTime.isAfter(selectionEnd)) { + messenger.showSnackBar(SnackBar(content: Text(errTimeAfterNow))); + if (selectedTime.hour > now.hour) selectedTime = selectedTime.copyWith(hour: now.hour); + if (selectedTime.minute > now.minute) selectedTime = selectedTime.copyWith(minute: now.minute); + } // validation for first date is not needed here as intervall starts at 00:00 setState(() { - _time = selectedTime; + _time = selectedTime!; }); } }, @@ -100,7 +109,7 @@ class _AddMeasurementPageState extends State { initialValue: (_systolic ?? '').toString(), hintText: AppLocalizations.of(context)!.sysLong, basicValidation: !settings.allowMissingValues, - preValidion: (v) => _systolic = int.tryParse(v ?? ''), + preValidation: (v) => _systolic = int.tryParse(v ?? ''), focusNode: _sysFocusNode, additionalValidator: (String? value) { _systolic = int.tryParse(value ?? ''); @@ -112,7 +121,7 @@ class _AddMeasurementPageState extends State { initialValue: (_diastolic ?? '').toString(), hintText: AppLocalizations.of(context)!.diaLong, basicValidation: !settings.allowMissingValues, - preValidion: (v) => _diastolic = int.tryParse(v ?? ''), + preValidation: (v) => _diastolic = int.tryParse(v ?? ''), additionalValidator: (String? value) { if (settings.validateInputs && (int.tryParse(value ?? '') ?? 0) >= (_systolic ?? 1)) { return AppLocalizations.of(context)?.errDiaGtSys; @@ -126,7 +135,7 @@ class _AddMeasurementPageState extends State { initialValue: (_pulse ?? '').toString(), hintText: AppLocalizations.of(context)!.pulLong, basicValidation: !settings.allowMissingValues, - preValidion: (v) => _pulse = int.tryParse(v ?? ''), + preValidation: (v) => _pulse = int.tryParse(v ?? ''), additionalValidator: (String? value) { if (settings.validateInputs && (int.tryParse(value ?? '') ?? 0) >= 600) { // https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3273956/ return AppLocalizations.of(context)?.errUnrealistic; @@ -202,11 +211,11 @@ class ValueInput extends StatelessWidget { final String hintText; final FocusNode? focusNode; final bool basicValidation; - final void Function(String?)? preValidion; + final void Function(String?)? preValidation; final FormFieldValidator additionalValidator; const ValueInput({super.key, required this.initialValue, required this.hintText, this.focusNode, this.basicValidation = true, - this.preValidion, required this.additionalValidator}); + this.preValidation, required this.additionalValidator}); @override Widget build(BuildContext context) { @@ -223,7 +232,7 @@ class ValueInput extends StatelessWidget { } }, validator: (String? value) { - if (preValidion != null) preValidion!(value); + if (preValidation != null) preValidation!(value); if (basicValidation) { if (value == null || value.isEmpty || (int.tryParse(value) == null)) { return AppLocalizations.of(context)?.errNaN;