ReactiveDateTimePicker constructor

ReactiveDateTimePicker({
  1. Key? key,
  2. String? formControlName,
  3. FormControl<DateTime>? formControl,
  4. ControlValueAccessor<DateTime, String>? valueAccessor,
  5. Map<String, ValidationMessageFunction>? validationMessages,
  6. ShowErrorsFunction<DateTime>? showErrors,
  7. TextStyle? style,
  8. ReactiveDatePickerFieldType type = ReactiveDatePickerFieldType.date,
  9. InputDecoration? decoration,
  10. bool showClearIcon = true,
  11. Widget clearIcon = const Icon(Icons.clear),
  12. TransitionBuilder? builder,
  13. bool useRootNavigator = true,
  14. String? cancelText,
  15. String? confirmText,
  16. String? helpText,
  17. GetInitialDate? getInitialDate,
  18. GetInitialTime? getInitialTime,
  19. DateFormat? dateFormat,
  20. double disabledOpacity = 0.5,
  21. DateTime? firstDate,
  22. DateTime? lastDate,
  23. DatePickerEntryMode datePickerEntryMode = DatePickerEntryMode.calendar,
  24. SelectableDayPredicate? selectableDayPredicate,
  25. Locale? locale,
  26. TextDirection? textDirection,
  27. DatePickerMode initialDatePickerMode = DatePickerMode.day,
  28. String? errorFormatText,
  29. String? errorInvalidText,
  30. String? fieldHintText,
  31. String? fieldLabelText,
  32. RouteSettings? datePickerRouteSettings,
  33. TextInputType? keyboardType,
  34. Offset? anchorPoint,
  35. TimePickerEntryMode timePickerEntryMode = TimePickerEntryMode.dial,
  36. RouteSettings? timePickerRouteSettings,
})

Creates a ReactiveDatePickerField that wraps the function showDatePicker.

Can optionally provide a formControl to bind this widget to a control.

Can optionally provide a formControlName to bind this ReactiveFormField to a FormControl.

Must provide one of the arguments formControl or a formControlName, but not both at the same time.

The parameter transitionBuilder is the equivalent of builder parameter in the showTimePicker.

For documentation about the various parameters, see the showTimePicker function parameters.

Implementation

ReactiveDateTimePicker({
  super.key,
  super.formControlName,
  super.formControl,
  ControlValueAccessor<DateTime, String>? valueAccessor,
  super.validationMessages,
  super.showErrors,

  ////////////////////////////////////////////////////////////////////////////
  TextStyle? style,
  ReactiveDatePickerFieldType type = ReactiveDatePickerFieldType.date,
  InputDecoration? decoration,
  bool showClearIcon = true,
  Widget clearIcon = const Icon(Icons.clear),

  // common params
  TransitionBuilder? builder,
  bool useRootNavigator = true,
  String? cancelText,
  String? confirmText,
  String? helpText,
  GetInitialDate? getInitialDate,
  GetInitialTime? getInitialTime,
  DateFormat? dateFormat,
  double disabledOpacity = 0.5,

  // date picker params
  DateTime? firstDate,
  DateTime? lastDate,
  DatePickerEntryMode datePickerEntryMode = DatePickerEntryMode.calendar,
  SelectableDayPredicate? selectableDayPredicate,
  Locale? locale,
  TextDirection? textDirection,
  DatePickerMode initialDatePickerMode = DatePickerMode.day,
  String? errorFormatText,
  String? errorInvalidText,
  String? fieldHintText,
  String? fieldLabelText,
  RouteSettings? datePickerRouteSettings,
  TextInputType? keyboardType,
  Offset? anchorPoint,

  // time picker params
  TimePickerEntryMode timePickerEntryMode = TimePickerEntryMode.dial,
  RouteSettings? timePickerRouteSettings,
}) : super(
        valueAccessor:
            valueAccessor ?? _effectiveValueAccessor(type, dateFormat),
        builder: (field) {
          Widget? suffixIcon = decoration?.suffixIcon;
          final isEmptyValue =
              field.value == null || field.value?.isEmpty == true;

          if (showClearIcon && !isEmptyValue) {
            suffixIcon = InkWell(
              borderRadius: BorderRadius.circular(25),
              child: clearIcon,
              onTap: () {
                field.control.markAsTouched();
                field.didChange(null);
              },
            );
          }

          final InputDecoration effectiveDecoration =
              (decoration ?? const InputDecoration())
                  .applyDefaults(Theme.of(field.context).inputDecorationTheme)
                  .copyWith(suffixIcon: suffixIcon);

          final effectiveValueAccessor =
              valueAccessor ?? _effectiveValueAccessor(type, dateFormat);

          final effectiveLastDate = lastDate ?? DateTime(2100);

          return IgnorePointer(
            ignoring: !field.control.enabled,
            child: Opacity(
              opacity: field.control.enabled ? 1 : disabledOpacity,
              child: GestureDetector(
                onTap: () async {
                  DateTime? date;
                  TimeOfDay? time;
                  field.control.focus();
                  field.control.updateValueAndValidity();

                  if (type == ReactiveDatePickerFieldType.date ||
                      type == ReactiveDatePickerFieldType.dateTime) {
                    date = await showDatePicker(
                      context: field.context,
                      initialDate: (getInitialDate ?? _getInitialDate)(
                        field.control.value,
                        effectiveLastDate,
                      ),
                      firstDate: firstDate ?? DateTime(1900),
                      lastDate: effectiveLastDate,
                      initialEntryMode: datePickerEntryMode,
                      selectableDayPredicate: selectableDayPredicate,
                      helpText: helpText,
                      cancelText: cancelText,
                      confirmText: confirmText,
                      locale: locale,
                      useRootNavigator: useRootNavigator,
                      routeSettings: datePickerRouteSettings,
                      textDirection: textDirection,
                      builder: builder,
                      initialDatePickerMode: initialDatePickerMode,
                      errorFormatText: errorFormatText,
                      errorInvalidText: errorInvalidText,
                      fieldHintText: fieldHintText,
                      fieldLabelText: fieldLabelText,
                      keyboardType: keyboardType,
                      anchorPoint: anchorPoint,
                    );
                  }

                  if (type == ReactiveDatePickerFieldType.time ||
                      (type == ReactiveDatePickerFieldType.dateTime &&
                          // there is no need to show timepicker if cancel was pressed on datepicker
                          date != null)) {
                    time = await showTimePicker(
                      context: field.context,
                      initialTime: (getInitialTime ??
                          _getInitialTime)(field.control.value),
                      builder: builder,
                      useRootNavigator: useRootNavigator,
                      initialEntryMode: timePickerEntryMode,
                      cancelText: cancelText,
                      confirmText: confirmText,
                      helpText: helpText,
                      routeSettings: timePickerRouteSettings,
                    );
                  }

                  if (
                      // if `date` and `time` in `dateTime` mode is not empty...
                      (type == ReactiveDatePickerFieldType.dateTime &&
                              (date != null && time != null)) ||
                          // ... or if `date` in `date` mode is not empty ...
                          (type == ReactiveDatePickerFieldType.date &&
                              date != null) ||
                          // ... or if `time` in `time` mode is not empty ...
                          (type == ReactiveDatePickerFieldType.time &&
                              time != null)) {
                    final dateTime = _combine(date, time);

                    final value = field.control.value;
                    // ... and new value is not the same as was before...
                    if (value == null || dateTime.compareTo(value) != 0) {
                      // ... this means that cancel was not pressed at any moment
                      // so we can update the field
                      field.didChange(
                        effectiveValueAccessor.modelToViewValue(
                          _combine(date, time),
                        ),
                      );
                    }
                  }
                  field.control.unfocus();
                  field.control.updateValueAndValidity();
                  field.control.markAsTouched();
                },
                child: InputDecorator(
                  decoration: effectiveDecoration.copyWith(
                    errorText: field.errorText,
                    enabled: field.control.enabled,
                  ),
                  isFocused: field.control.hasFocus,
                  isEmpty: isEmptyValue,
                  child: Text(
                    field.value ?? '',
                    style: Theme.of(field.context)
                        .textTheme
                        .titleMedium
                        ?.merge(style),
                  ),
                ),
              ),
            ),
          );
        },
      );