Skip to content

Commit 509f606

Browse files
committed
reactive_date_range_picker 2.3.0
1 parent 71d5853 commit 509f606

File tree

6 files changed

+203
-44
lines changed

6 files changed

+203
-44
lines changed

packages/reactive_date_range_picker/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## [2.3.0]
2+
3+
* onTap for custom calendars support
4+
* valueBuilder
5+
16
## [2.2.0]
27

38
* mouse cursor

packages/reactive_date_range_picker/example/lib/main.dart

Lines changed: 125 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_range_picker/reactive_date_range_picker.dart';
34
import 'package:reactive_forms/reactive_forms.dart';
@@ -60,6 +61,22 @@ class MyApp extends StatelessWidget {
6061
suffixIcon: Icon(Icons.calendar_today),
6162
),
6263
),
64+
ReactiveDateRangePicker(
65+
formControlName: 'dateRange',
66+
decoration: const InputDecoration(
67+
labelText: 'Date Range',
68+
hintText: 'hintText',
69+
border: OutlineInputBorder(),
70+
helperText: 'helperText',
71+
suffixIcon: Icon(Icons.calendar_today),
72+
),
73+
onTap: (context, value) async {
74+
return await showDateRangePicker(
75+
context,
76+
value: value,
77+
);
78+
},
79+
),
6380
ElevatedButton(
6481
child: const Text('Sign Up'),
6582
onPressed: () {
@@ -81,3 +98,111 @@ class MyApp extends StatelessWidget {
8198
);
8299
}
83100
}
101+
102+
Future<DateTimeRange?> showDateRangePicker(
103+
BuildContext context, {
104+
DateTime? firstDate,
105+
DateTime? lastDate,
106+
DateTime? currentDate,
107+
DateTimeRange? value,
108+
}) async {
109+
final selectedDates = await _showCalendarDatePicker2Dialog(
110+
context,
111+
calendarType: CalendarDatePicker2Type.range,
112+
currentDate: currentDate,
113+
firstDate: firstDate,
114+
lastDate: lastDate,
115+
value: [value?.start, value?.end],
116+
);
117+
118+
if (selectedDates == null || selectedDates.isEmpty) return value;
119+
120+
return DateTimeRange(
121+
start: selectedDates[0] ?? DateTime.now(),
122+
end: selectedDates[selectedDates.length == 1 ? 0 : 1] ?? DateTime.now(),
123+
);
124+
}
125+
126+
Future<List<DateTime?>?> _showCalendarDatePicker2Dialog(
127+
BuildContext context, {
128+
required CalendarDatePicker2Type calendarType,
129+
List<DateTime?> value = const [],
130+
DateTime? firstDate,
131+
DateTime? lastDate,
132+
DateTime? currentDate,
133+
}) async {
134+
return showCalendarDatePicker2Dialog(
135+
value: value,
136+
context: context,
137+
config: getCalendarConfig(
138+
context,
139+
calendarType: calendarType,
140+
firstDate: firstDate,
141+
lastDate: lastDate,
142+
currentDate: currentDate,
143+
),
144+
dialogSize: const Size(360, 400),
145+
borderRadius: BorderRadius.circular(16),
146+
dialogBackgroundColor: Colors.white,
147+
);
148+
}
149+
150+
CalendarDatePicker2WithActionButtonsConfig getCalendarConfig(
151+
BuildContext context, {
152+
CalendarDatePicker2Type calendarType = CalendarDatePicker2Type.single,
153+
DateTime? firstDate,
154+
DateTime? lastDate,
155+
DateTime? currentDate,
156+
}) {
157+
final primaryColor = Theme.of(context).primaryColor;
158+
159+
const dayTextStyle = TextStyle(
160+
fontWeight: FontWeight.w700,
161+
);
162+
163+
final firstDay = firstDate?.startOfDay();
164+
final lastDay = lastDate?.startOfDay();
165+
166+
return CalendarDatePicker2WithActionButtonsConfig(
167+
firstDate: firstDate,
168+
lastDate: lastDate,
169+
dayTextStyle: dayTextStyle,
170+
calendarType: calendarType,
171+
selectedDayHighlightColor: primaryColor,
172+
closeDialogOnCancelTapped: true,
173+
firstDayOfWeek: 1,
174+
selectableDayPredicate: (day) =>
175+
(firstDay == null || !day.isBefore(firstDay)) &&
176+
(lastDay == null || !day.isAfter(lastDay)),
177+
currentDate: currentDate,
178+
weekdayLabelTextStyle: TextStyle(
179+
color: primaryColor,
180+
fontWeight: FontWeight.w500,
181+
),
182+
controlsTextStyle: TextStyle(
183+
color: primaryColor,
184+
fontSize: 15,
185+
fontWeight: FontWeight.w500,
186+
),
187+
centerAlignModePicker: true,
188+
customModePickerIcon: const SizedBox(),
189+
selectedDayTextStyle: dayTextStyle.copyWith(color: Colors.white),
190+
nextMonthIcon: Icon(
191+
Icons.arrow_right,
192+
size: 20,
193+
color: primaryColor,
194+
),
195+
lastMonthIcon: Icon(
196+
Icons.arrow_left,
197+
size: 20,
198+
color: primaryColor,
199+
),
200+
todayTextStyle: dayTextStyle.merge(TextStyle(color: primaryColor)),
201+
);
202+
}
203+
204+
extension on DateTime {
205+
DateTime startOfDay() {
206+
return DateTime(year, month, day);
207+
}
208+
}

packages/reactive_date_range_picker/example/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ environment:
2323
dependencies:
2424
flutter:
2525
sdk: flutter
26+
calendar_date_picker2: ^1.1.9
2627
reactive_forms: ">=16.0.0 <18.0.0"
2728
reactive_date_range_picker:
2829
path: ../

packages/reactive_date_range_picker/lib/datetime_range_value_accessor.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ class DateTimeRangeValueAccessor
99
final DateFormat dateTimeFormat;
1010
final String delimiter;
1111

12-
DateTimeRangeValueAccessor(
13-
{DateFormat? dateTimeFormat, this.delimiter = ' - '})
14-
: dateTimeFormat = dateTimeFormat ?? DateFormat('yyyy/MM/dd');
12+
DateTimeRangeValueAccessor({
13+
DateFormat? dateTimeFormat,
14+
this.delimiter = ' - ',
15+
}) : dateTimeFormat = dateTimeFormat ?? DateFormat('yyyy/MM/dd');
1516

1617
@override
1718
String? modelToViewValue(DateTimeRange? modelValue) {
@@ -22,7 +23,9 @@ class DateTimeRangeValueAccessor
2223

2324
@override
2425
DateTimeRange? viewToModelValue(String? viewValue) {
25-
final dateRange = viewValue?.trim().split(delimiter);
26+
final dateRange = viewValue == null || viewValue.isEmpty
27+
? null
28+
: viewValue.trim().split(delimiter);
2629

2730
return dateRange == null || dateRange.isEmpty
2831
? null

packages/reactive_date_range_picker/lib/reactive_date_range_picker.dart

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ class ReactiveDateRangePicker extends ReactiveFormField<DateTimeRange, String> {
8989
TextAlignVertical? textAlignVertical,
9090
bool expands = false,
9191
MouseCursor cursor = SystemMouseCursors.click,
92+
Future<DateTimeRange?> Function(
93+
BuildContext context,
94+
DateTimeRange? value,
95+
)? onTap,
96+
Widget Function(BuildContext context, String? value)? valueBuilder,
9297
}) : super(
9398
valueAccessor: valueAccessor ?? DateTimeRangeValueAccessor(),
9499
builder: (field) {
@@ -126,49 +131,67 @@ class ReactiveDateRangePicker extends ReactiveFormField<DateTimeRange, String> {
126131
cursor: cursor,
127132
child: GestureDetector(
128133
onTap: () async {
129-
final dateRange = await showDateRangePicker(
130-
context: field.context,
131-
initialDateRange: field.control.value,
132-
firstDate: firstDate ?? DateTime(1900),
133-
lastDate: effectiveLastDate,
134-
currentDate: currentDate,
135-
initialEntryMode: initialEntryMode,
136-
helpText: helpText,
137-
cancelText: cancelText,
138-
confirmText: confirmText,
139-
saveText: saveText,
140-
errorFormatText: errorFormatText,
141-
errorInvalidText: errorInvalidText,
142-
errorInvalidRangeText: errorInvalidRangeText,
143-
fieldStartHintText: fieldStartHintText,
144-
fieldEndHintText: fieldEndHintText,
145-
fieldStartLabelText: fieldStartLabelText,
146-
fieldEndLabelText: fieldEndLabelText,
147-
locale: locale,
148-
useRootNavigator: useRootNavigator,
149-
routeSettings: routeSettings,
150-
textDirection: textDirection,
151-
builder: builder,
152-
barrierDismissible: barrierDismissible,
153-
barrierColor: barrierColor,
154-
anchorPoint: anchorPoint,
155-
keyboardType: keyboardType,
156-
switchToInputEntryModeIcon: switchToInputEntryModeIcon,
157-
switchToCalendarEntryModeIcon:
158-
switchToCalendarEntryModeIcon,
159-
);
160-
161-
if (dateRange == null) {
162-
return;
134+
field.control.focus();
135+
field.control.updateValueAndValidity();
136+
if (onTap != null) {
137+
field.didChange(
138+
effectiveValueAccessor.modelToViewValue(
139+
await onTap(
140+
field.context,
141+
field.control.value,
142+
),
143+
),
144+
);
145+
} else {
146+
final dateRange = await showDateRangePicker(
147+
context: field.context,
148+
initialDateRange: field.control.value,
149+
firstDate: firstDate ?? DateTime(1900),
150+
lastDate: effectiveLastDate,
151+
currentDate: currentDate,
152+
initialEntryMode: initialEntryMode,
153+
helpText: helpText,
154+
cancelText: cancelText,
155+
confirmText: confirmText,
156+
saveText: saveText,
157+
errorFormatText: errorFormatText,
158+
errorInvalidText: errorInvalidText,
159+
errorInvalidRangeText: errorInvalidRangeText,
160+
fieldStartHintText: fieldStartHintText,
161+
fieldEndHintText: fieldEndHintText,
162+
fieldStartLabelText: fieldStartLabelText,
163+
fieldEndLabelText: fieldEndLabelText,
164+
locale: locale,
165+
useRootNavigator: useRootNavigator,
166+
routeSettings: routeSettings,
167+
textDirection: textDirection,
168+
builder: builder,
169+
barrierDismissible: barrierDismissible,
170+
barrierColor: barrierColor,
171+
anchorPoint: anchorPoint,
172+
keyboardType: keyboardType,
173+
switchToInputEntryModeIcon:
174+
switchToInputEntryModeIcon,
175+
switchToCalendarEntryModeIcon:
176+
switchToCalendarEntryModeIcon,
177+
);
178+
179+
if (dateRange == null) {
180+
return;
181+
}
182+
field.didChange(
183+
effectiveValueAccessor.modelToViewValue(dateRange),
184+
);
163185
}
164186

187+
field.control.unfocus();
188+
field.control.updateValueAndValidity();
165189
field.control.markAsTouched();
166-
field.didChange(
167-
effectiveValueAccessor.modelToViewValue(dateRange));
168190
},
169191
child: InputDecorator(
170192
isFocused: field.control.hasFocus,
171193
isEmpty: isEmptyValue,
194+
isHovering: isHovered,
172195
baseStyle: baseStyle,
173196
textAlign: textAlign,
174197
textAlignVertical: textAlignVertical,
@@ -195,9 +218,7 @@ class ReactiveDateRangePicker extends ReactiveFormField<DateTimeRange, String> {
195218
)
196219
: null,
197220
),
198-
isHovering: isHovered,
199-
child: Text(
200-
field.value ?? '',
221+
child: DefaultTextStyle.merge(
201222
style: Theme.of(field.context)
202223
.textTheme
203224
.titleMedium
@@ -207,6 +228,10 @@ class ReactiveDateRangePicker extends ReactiveFormField<DateTimeRange, String> {
207228
? Theme.of(field.context).disabledColor
208229
: null,
209230
),
231+
child: valueBuilder?.call(field.context, field.value) ??
232+
Text(
233+
field.value ?? '',
234+
),
210235
),
211236
),
212237
),

packages/reactive_date_range_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_range_picker
22
description: Wrapper around flutter showDateRangePicker to use with reactive_forms
3-
version: 2.2.0
3+
version: 2.3.0
44
repository: https://github.com/artflutter/reactive_forms_widgets/tree/master/packages/reactive_date_range_picker
55
issue_tracker: https://github.com/artflutter/reactive_forms_widgets/issues
66

0 commit comments

Comments
 (0)