Skip to content

Commit 71d5853

Browse files
committed
reactive_date_time_picker 4.5.0
1 parent af56fba commit 71d5853

File tree

5 files changed

+250
-70
lines changed

5 files changed

+250
-70
lines changed

packages/reactive_date_time_picker/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## [4.5.0]
2+
3+
* more props pass through
4+
* custom picker integration
5+
16
## [4.4.0]
27

38
* valueBuilder method

packages/reactive_date_time_picker/example/lib/main.dart

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:calendar_date_picker2/calendar_date_picker2.dart';
12
import 'package:flutter/material.dart';
23
import 'package:reactive_date_time_picker/reactive_date_time_picker.dart';
34
import 'package:reactive_forms/reactive_forms.dart';
@@ -116,6 +117,21 @@ class MyApp extends StatelessWidget {
116117
suffixIcon: Icon(Icons.calendar_today),
117118
),
118119
),
120+
const SizedBox(height: 8),
121+
ReactiveDateTimePicker(
122+
formControlName: 'dateTimeNullable',
123+
type: ReactiveDatePickerFieldType.date,
124+
decoration: const InputDecoration(
125+
labelText: 'Date & Time',
126+
hintText: 'hintText',
127+
border: OutlineInputBorder(),
128+
helperText: 'helperText',
129+
suffixIcon: Icon(Icons.calendar_today),
130+
),
131+
onTap: (context, value) async {
132+
return await showDatePicker(context);
133+
},
134+
),
119135
const SizedBox(height: 16),
120136
ElevatedButton(
121137
child: const Text('Sign Up'),
@@ -142,3 +158,106 @@ class MyApp extends StatelessWidget {
142158
);
143159
}
144160
}
161+
162+
Future<DateTime?> showDatePicker(
163+
BuildContext context, {
164+
DateTime? value,
165+
DateTime? firstDate,
166+
DateTime? lastDate,
167+
DateTime? currentDate,
168+
}) async {
169+
final result = await _showCalendarDatePicker2Dialog(
170+
context,
171+
firstDate: firstDate,
172+
lastDate: lastDate,
173+
currentDate: currentDate,
174+
value: [value],
175+
calendarType: CalendarDatePicker2Type.single,
176+
);
177+
178+
return result?.firstOrNull;
179+
}
180+
181+
Future<List<DateTime?>?> _showCalendarDatePicker2Dialog(
182+
BuildContext context, {
183+
required CalendarDatePicker2Type calendarType,
184+
List<DateTime?> value = const [],
185+
DateTime? firstDate,
186+
DateTime? lastDate,
187+
DateTime? currentDate,
188+
}) async {
189+
return showCalendarDatePicker2Dialog(
190+
value: value,
191+
context: context,
192+
config: calendarConfig(
193+
context,
194+
calendarType: calendarType,
195+
firstDate: firstDate,
196+
lastDate: lastDate,
197+
currentDate: currentDate,
198+
),
199+
dialogSize: const Size(360, 400),
200+
borderRadius: BorderRadius.circular(16),
201+
dialogBackgroundColor: Colors.white,
202+
);
203+
}
204+
205+
CalendarDatePicker2WithActionButtonsConfig calendarConfig(
206+
BuildContext context, {
207+
CalendarDatePicker2Type calendarType = CalendarDatePicker2Type.single,
208+
DateTime? firstDate,
209+
DateTime? lastDate,
210+
DateTime? currentDate,
211+
}) {
212+
final primaryColor = Theme.of(context).primaryColor;
213+
214+
const dayTextStyle = TextStyle(
215+
fontWeight: FontWeight.w700,
216+
);
217+
218+
final firstDay = firstDate?.startOfDay();
219+
final lastDay = lastDate?.startOfDay();
220+
221+
return CalendarDatePicker2WithActionButtonsConfig(
222+
firstDate: firstDate,
223+
lastDate: lastDate,
224+
dayTextStyle: dayTextStyle,
225+
calendarType: calendarType,
226+
selectedDayHighlightColor: primaryColor,
227+
closeDialogOnCancelTapped: true,
228+
firstDayOfWeek: 1,
229+
selectableDayPredicate: (day) =>
230+
(firstDay == null || !day.isBefore(firstDay)) &&
231+
(lastDay == null || !day.isAfter(lastDay)),
232+
currentDate: currentDate,
233+
weekdayLabelTextStyle: TextStyle(
234+
color: primaryColor,
235+
fontWeight: FontWeight.w500,
236+
),
237+
controlsTextStyle: TextStyle(
238+
color: primaryColor,
239+
fontSize: 15,
240+
fontWeight: FontWeight.w500,
241+
),
242+
centerAlignModePicker: true,
243+
customModePickerIcon: const SizedBox(),
244+
selectedDayTextStyle: dayTextStyle.copyWith(color: Colors.white),
245+
nextMonthIcon: Icon(
246+
Icons.arrow_circle_right,
247+
size: 20,
248+
color: primaryColor,
249+
),
250+
lastMonthIcon: Icon(
251+
Icons.arrow_circle_left,
252+
size: 20,
253+
color: primaryColor,
254+
),
255+
todayTextStyle: dayTextStyle.merge(TextStyle(color: primaryColor)),
256+
);
257+
}
258+
259+
extension on DateTime {
260+
DateTime startOfDay() {
261+
return DateTime(year, month, day);
262+
}
263+
}

packages/reactive_date_time_picker/example/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ dependencies:
3030
# The following adds the Cupertino Icons font to your application.
3131
# Use with the CupertinoIcons class for iOS style icons.
3232
cupertino_icons: ^1.0.5
33+
calendar_date_picker2: ^1.1.9
3334

3435
dev_dependencies:
3536
flutter_test:

packages/reactive_date_time_picker/lib/reactive_date_time_picker.dart

Lines changed: 124 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,28 @@ class ReactiveDateTimePicker
9898
RouteSettings? datePickerRouteSettings,
9999
TextInputType? keyboardType,
100100
Offset? anchorPoint,
101+
DateTime? currentDate,
102+
bool barrierDismissible = true,
103+
Color? barrierColor,
104+
String? barrierLabel,
105+
ValueChanged<DatePickerEntryMode>? onDatePickerModeChange,
101106

102107
// time picker params
103108
TimePickerEntryMode timePickerEntryMode = TimePickerEntryMode.dial,
104109
RouteSettings? timePickerRouteSettings,
110+
bool timePickerBarrierDismissible = true,
111+
Color? timePickerBarrierColor,
112+
String? timePickerBarrierLabel,
113+
String? hourLabelText,
114+
String? minuteLabelText,
115+
String? timePickerErrorInvalidText,
116+
EntryModeChangeCallback? onEntryModeChanged,
117+
Offset? timePickerAnchorPoint,
118+
Orientation? timePickerOrientation,
119+
Future<DateTime?> Function(
120+
BuildContext context,
121+
DateTime? value,
122+
)? onTap,
105123
Widget Function(BuildContext context, String error)? errorBuilder,
106124

107125
// input decorator props
@@ -111,6 +129,8 @@ class ReactiveDateTimePicker
111129
bool expands = false,
112130
MouseCursor cursor = SystemMouseCursors.click,
113131
Widget Function(BuildContext context, String? value)? valueBuilder,
132+
Icon? switchToInputEntryModeIcon,
133+
Icon? switchToCalendarEntryModeIcon,
114134
}) : super(
115135
valueAccessor:
116136
valueAccessor ?? _effectiveValueAccessor(type, dateFormat),
@@ -156,78 +176,111 @@ class ReactiveDateTimePicker
156176
field.control.focus();
157177
field.control.updateValueAndValidity();
158178

159-
if (type == ReactiveDatePickerFieldType.date ||
160-
type == ReactiveDatePickerFieldType.dateTime) {
161-
date = await showDatePicker(
162-
context: field.context,
163-
initialDate: (getInitialDate ?? _getInitialDate)(
164-
field.control.value,
165-
effectiveLastDate,
179+
final initialDate = (getInitialDate ?? _getInitialDate)(
180+
field.control.value,
181+
effectiveLastDate,
182+
);
183+
184+
if (onTap != null) {
185+
field.didChange(
186+
effectiveValueAccessor.modelToViewValue(
187+
await onTap(
188+
field.context,
189+
initialDate,
190+
),
166191
),
167-
firstDate: firstDate ?? DateTime(1900),
168-
lastDate: effectiveLastDate,
169-
initialEntryMode: datePickerEntryMode,
170-
selectableDayPredicate: selectableDayPredicate,
171-
helpText: helpText,
172-
cancelText: cancelText,
173-
confirmText: confirmText,
174-
locale: locale,
175-
useRootNavigator: useRootNavigator,
176-
routeSettings: datePickerRouteSettings,
177-
textDirection: textDirection,
178-
builder: builder,
179-
initialDatePickerMode: initialDatePickerMode,
180-
errorFormatText: errorFormatText,
181-
errorInvalidText: errorInvalidText,
182-
fieldHintText: fieldHintText,
183-
fieldLabelText: fieldLabelText,
184-
keyboardType: keyboardType,
185-
anchorPoint: anchorPoint,
186-
);
187-
}
188-
189-
if (type == ReactiveDatePickerFieldType.time ||
190-
(type == ReactiveDatePickerFieldType.dateTime &&
191-
// there is no need to show timepicker if cancel was pressed on datepicker
192-
date != null)) {
193-
time = await showTimePicker(
194-
context: field.context,
195-
initialTime: (getInitialTime ??
196-
_getInitialTime)(field.control.value),
197-
builder: builder,
198-
useRootNavigator: useRootNavigator,
199-
initialEntryMode: timePickerEntryMode,
200-
cancelText: cancelText,
201-
confirmText: confirmText,
202-
helpText: helpText,
203-
routeSettings: timePickerRouteSettings,
204192
);
205-
}
193+
} else {
194+
if (type == ReactiveDatePickerFieldType.date ||
195+
type == ReactiveDatePickerFieldType.dateTime) {
196+
date = await showDatePicker(
197+
context: field.context,
198+
initialDate: initialDate,
199+
currentDate: currentDate,
200+
firstDate: firstDate ?? DateTime(1900),
201+
lastDate: effectiveLastDate,
202+
initialEntryMode: datePickerEntryMode,
203+
selectableDayPredicate: selectableDayPredicate,
204+
helpText: helpText,
205+
cancelText: cancelText,
206+
confirmText: confirmText,
207+
locale: locale,
208+
useRootNavigator: useRootNavigator,
209+
routeSettings: datePickerRouteSettings,
210+
textDirection: textDirection,
211+
builder: builder,
212+
initialDatePickerMode: initialDatePickerMode,
213+
errorFormatText: errorFormatText,
214+
errorInvalidText: errorInvalidText,
215+
fieldHintText: fieldHintText,
216+
fieldLabelText: fieldLabelText,
217+
keyboardType: keyboardType,
218+
anchorPoint: anchorPoint,
219+
barrierDismissible: barrierDismissible,
220+
barrierColor: barrierColor,
221+
barrierLabel: barrierLabel,
222+
onDatePickerModeChange: onDatePickerModeChange,
223+
switchToInputEntryModeIcon:
224+
switchToInputEntryModeIcon,
225+
switchToCalendarEntryModeIcon:
226+
switchToCalendarEntryModeIcon,
227+
);
228+
}
206229

207-
if (
208-
// if `date` and `time` in `dateTime` mode is not empty...
209-
(type == ReactiveDatePickerFieldType.dateTime &&
210-
(date != null && time != null)) ||
211-
// ... or if `date` in `date` mode is not empty ...
212-
(type == ReactiveDatePickerFieldType.date &&
213-
date != null) ||
214-
// ... or if `time` in `time` mode is not empty ...
215-
(type == ReactiveDatePickerFieldType.time &&
216-
time != null)) {
217-
final dateTime = _combine(date, time);
218-
219-
final value = field.control.value;
220-
// ... and new value is not the same as was before...
221-
if (value == null || dateTime.compareTo(value) != 0) {
222-
// ... this means that cancel was not pressed at any moment
223-
// so we can update the field
224-
field.didChange(
225-
effectiveValueAccessor.modelToViewValue(
226-
_combine(date, time),
227-
),
230+
if (type == ReactiveDatePickerFieldType.time ||
231+
(type == ReactiveDatePickerFieldType.dateTime &&
232+
// there is no need to show timepicker if cancel was pressed on datepicker
233+
date != null)) {
234+
time = await showTimePicker(
235+
context: field.context,
236+
initialTime: (getInitialTime ??
237+
_getInitialTime)(field.control.value),
238+
builder: builder,
239+
useRootNavigator: useRootNavigator,
240+
initialEntryMode: timePickerEntryMode,
241+
cancelText: cancelText,
242+
confirmText: confirmText,
243+
helpText: helpText,
244+
routeSettings: timePickerRouteSettings,
245+
barrierDismissible: timePickerBarrierDismissible,
246+
barrierColor: timePickerBarrierColor,
247+
barrierLabel: timePickerBarrierLabel,
248+
errorInvalidText: timePickerErrorInvalidText,
249+
hourLabelText: hourLabelText,
250+
minuteLabelText: minuteLabelText,
251+
onEntryModeChanged: onEntryModeChanged,
252+
anchorPoint: timePickerAnchorPoint,
253+
orientation: timePickerOrientation,
228254
);
229255
}
256+
257+
if (
258+
// if `date` and `time` in `dateTime` mode is not empty...
259+
(type == ReactiveDatePickerFieldType.dateTime &&
260+
(date != null && time != null)) ||
261+
// ... or if `date` in `date` mode is not empty ...
262+
(type == ReactiveDatePickerFieldType.date &&
263+
date != null) ||
264+
// ... or if `time` in `time` mode is not empty ...
265+
(type == ReactiveDatePickerFieldType.time &&
266+
time != null)) {
267+
final dateTime = _combine(date, time);
268+
269+
final value = field.control.value;
270+
// ... and new value is not the same as was before...
271+
if (value == null ||
272+
dateTime.compareTo(value) != 0) {
273+
// ... this means that cancel was not pressed at any moment
274+
// so we can update the field
275+
field.didChange(
276+
effectiveValueAccessor.modelToViewValue(
277+
_combine(date, time),
278+
),
279+
);
280+
}
281+
}
230282
}
283+
231284
field.control.unfocus();
232285
field.control.updateValueAndValidity();
233286
field.control.markAsTouched();
@@ -273,9 +326,11 @@ class ReactiveDateTimePicker
273326
? Theme.of(field.context).disabledColor
274327
: null,
275328
),
276-
child: valueBuilder?.call(field.context, field.value) ?? Text(
277-
field.value ?? '',
278-
),
329+
child:
330+
valueBuilder?.call(field.context, field.value) ??
331+
Text(
332+
field.value ?? '',
333+
),
279334
),
280335
),
281336
),

packages/reactive_date_time_picker/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: reactive_date_time_picker
22
description: Wrapper around showDatePicker and showTimePicker to work with reactive_forms
3-
version: 4.4.0
3+
version: 4.5.0
44
repository: https://github.com/artflutter/reactive_forms_widgets/tree/master/packages/reactive_date_time_picker
55
issue_tracker: https://github.com/artflutter/reactive_forms_widgets/issues
66

0 commit comments

Comments
 (0)