Line data Source code
1 : import 'package:flutter/material.dart';
2 : import '../range_picker.dart';
3 : import '../week_picker.dart';
4 :
5 : /// 0 points to Sunday, and 6 points to Saturday.
6 : typedef DayHeaderStyleBuilder = DayHeaderStyle? Function(int dayOfTheWeek);
7 :
8 : /// 0 points to Sunday, and 6 points to Saturday.
9 : typedef DayHeaderTitleBuilder = String Function(
10 : int dayOfTheWeek, List<String> localizedWeekdayHeaders);
11 :
12 : /// Common styles for date pickers.
13 : ///
14 : /// To define more styles for date pickers which allow select some range
15 : /// (e.g. [RangePicker], [WeekPicker]) use [DatePickerRangeStyles].
16 : @immutable
17 : class DatePickerStyles {
18 : /// Styles for title of displayed period
19 : /// (e.g. month for day picker and year for month picker).
20 : final TextStyle? displayedPeriodTitle;
21 :
22 : /// Style for the number of current date.
23 : final TextStyle? currentDateStyle;
24 :
25 : /// Style for the numbers of disabled dates.
26 : final TextStyle? disabledDateStyle;
27 :
28 : /// Style for the number of selected date.
29 : final TextStyle? selectedDateStyle;
30 :
31 : /// Used for date which is neither current nor disabled nor selected.
32 : final TextStyle? defaultDateTextStyle;
33 :
34 : /// Day cell decoration for selected date in case only one date is selected.
35 : final BoxDecoration? selectedSingleDateDecoration;
36 :
37 : /// Style for the day header.
38 : ///
39 : /// If you need to customize day header's style depends on day of the week
40 : /// use [dayHeaderStyleBuilder] instead.
41 : final DayHeaderStyle? dayHeaderStyle;
42 :
43 : /// Builder to customize styles for day headers depends on day of the week.
44 : /// Where 0 points to Sunday and 6 points to Saturday.
45 : ///
46 : /// Builder must return not null value for every weekday from 0 to 6.
47 : ///
48 : /// If styles should be the same for any day of the week
49 : /// use [dayHeaderStyle] instead.
50 : final DayHeaderStyleBuilder? dayHeaderStyleBuilder;
51 :
52 : /// Builder to customize titles for day headers depends on day of the week.
53 : /// Where 0 points to Sunday and 6 points to Saturday.
54 : final DayHeaderTitleBuilder? dayHeaderTitleBuilder;
55 :
56 : /// Widget which will be shown left side of the shown page title.
57 : /// User goes to previous data period by click on it.
58 : final Widget prevIcon;
59 :
60 : /// Widget which will be shown right side of the shown page title.
61 : /// User goes to next data period by click on it.
62 : final Widget nextIcon;
63 :
64 : /// Index of the first day of week, where 0 points to Sunday, and 6 points to
65 : /// Saturday. Must not be less 0 or more then 6.
66 : ///
67 : /// Can be null. In this case value from current locale will be used.
68 : final int? firstDayOfeWeekIndex;
69 :
70 : /// Styles for date picker.
71 0 : DatePickerStyles(
72 : {this.displayedPeriodTitle,
73 : this.currentDateStyle,
74 : this.disabledDateStyle,
75 : this.selectedDateStyle,
76 : this.selectedSingleDateDecoration,
77 : this.defaultDateTextStyle,
78 : this.dayHeaderStyle,
79 : this.dayHeaderStyleBuilder,
80 : this.dayHeaderTitleBuilder,
81 : this.firstDayOfeWeekIndex,
82 : this.prevIcon = const Icon(Icons.chevron_left),
83 : this.nextIcon = const Icon(Icons.chevron_right)})
84 0 : : assert(!(dayHeaderStyle != null && dayHeaderStyleBuilder != null),
85 : "Should be only one from: dayHeaderStyleBuilder, dayHeaderStyle."),
86 : assert(
87 0 : dayHeaderStyleBuilder == null ||
88 0 : _validateDayHeaderStyleBuilder(dayHeaderStyleBuilder),
89 : "dayHeaderStyleBuilder must return not null value from every weekday "
90 : "(from 0 to 6)."),
91 0 : assert(_validateFirstDayOfWeek(firstDayOfeWeekIndex),
92 : "firstDayOfeWeekIndex must be null or in correct range (from 0 to 6).");
93 :
94 : /// Return new [DatePickerStyles] object where fields
95 : /// with null values set with defaults from theme.
96 0 : DatePickerStyles fulfillWithTheme(ThemeData theme) {
97 0 : Color accentColor = theme.colorScheme.secondary;
98 :
99 : TextStyle? _displayedPeriodTitle =
100 0 : displayedPeriodTitle ?? theme.textTheme.subtitle1;
101 0 : TextStyle? _currentDateStyle = currentDateStyle ??
102 0 : theme.textTheme.bodyText1?.copyWith(color: theme.colorScheme.secondary);
103 0 : TextStyle? _disabledDateStyle = disabledDateStyle ??
104 0 : theme.textTheme.bodyText2?.copyWith(color: theme.disabledColor);
105 : TextStyle? _selectedDateStyle =
106 0 : selectedDateStyle ?? theme.textTheme.bodyText1?.copyWith(
107 0 : color: theme.colorScheme.onSecondary,
108 : );
109 :
110 : TextStyle? _defaultDateTextStyle =
111 0 : defaultDateTextStyle ?? theme.textTheme.bodyText2;
112 : BoxDecoration _selectedSingleDateDecoration =
113 0 : selectedSingleDateDecoration ??
114 0 : BoxDecoration(
115 : color: accentColor,
116 : borderRadius: const BorderRadius.all(Radius.circular(10.0)));
117 :
118 0 : DayHeaderStyle? _dayHeaderStyle = dayHeaderStyle;
119 0 : if (dayHeaderStyleBuilder == null && _dayHeaderStyle == null) {
120 0 : _dayHeaderStyle = DayHeaderStyle(textStyle: theme.textTheme.caption);
121 : }
122 :
123 0 : return DatePickerStyles(
124 : disabledDateStyle: _disabledDateStyle,
125 : currentDateStyle: _currentDateStyle,
126 : displayedPeriodTitle: _displayedPeriodTitle,
127 : selectedDateStyle: _selectedDateStyle,
128 : selectedSingleDateDecoration: _selectedSingleDateDecoration,
129 : defaultDateTextStyle: _defaultDateTextStyle,
130 : dayHeaderStyle: _dayHeaderStyle,
131 0 : dayHeaderStyleBuilder: dayHeaderStyleBuilder,
132 0 : dayHeaderTitleBuilder: dayHeaderTitleBuilder,
133 0 : nextIcon: nextIcon,
134 0 : prevIcon: prevIcon);
135 : }
136 :
137 0 : @override
138 : bool operator ==(Object other) {
139 : if (identical(this, other)) return true;
140 0 : if (other.runtimeType != runtimeType) return false;
141 :
142 0 : return other is DatePickerStyles &&
143 0 : other.displayedPeriodTitle == displayedPeriodTitle &&
144 0 : other.currentDateStyle == currentDateStyle &&
145 0 : other.disabledDateStyle == disabledDateStyle &&
146 0 : other.selectedDateStyle == selectedDateStyle &&
147 0 : other.defaultDateTextStyle == defaultDateTextStyle &&
148 0 : other.selectedSingleDateDecoration == selectedSingleDateDecoration &&
149 0 : other.dayHeaderStyle == dayHeaderStyle &&
150 0 : other.dayHeaderStyleBuilder == dayHeaderStyleBuilder &&
151 0 : other.dayHeaderTitleBuilder == dayHeaderTitleBuilder &&
152 0 : other.prevIcon == prevIcon &&
153 0 : other.nextIcon == nextIcon &&
154 0 : other.firstDayOfeWeekIndex == firstDayOfeWeekIndex;
155 : }
156 :
157 0 : @override
158 0 : int get hashCode => hashValues(
159 0 : displayedPeriodTitle,
160 0 : currentDateStyle,
161 0 : disabledDateStyle,
162 0 : selectedDateStyle,
163 0 : defaultDateTextStyle,
164 0 : selectedSingleDateDecoration,
165 0 : dayHeaderStyle,
166 0 : dayHeaderStyleBuilder,
167 0 : dayHeaderTitleBuilder,
168 0 : prevIcon,
169 0 : nextIcon,
170 0 : firstDayOfeWeekIndex);
171 :
172 0 : static bool _validateDayHeaderStyleBuilder(DayHeaderStyleBuilder builder) {
173 : List<int> weekdays = const [0, 1, 2, 3, 4, 5, 6];
174 :
175 : // ignore: avoid_types_on_closure_parameters
176 0 : bool valid = weekdays.every((int weekday) => builder(weekday) != null);
177 :
178 : return valid;
179 : }
180 :
181 0 : static bool _validateFirstDayOfWeek(int? index) {
182 : if (index == null) return true;
183 :
184 0 : bool valid = index >= 0 && index <= 6;
185 :
186 : return valid;
187 : }
188 : }
189 :
190 : /// Styles for date pickers which allow select some range
191 : /// (e.g. RangePicker, WeekPicker).
192 : @immutable
193 : class DatePickerRangeStyles extends DatePickerStyles {
194 : /// Decoration for the first date of the selected range.
195 : final BoxDecoration? selectedPeriodStartDecoration;
196 :
197 : /// Text style for the first date of the selected range.
198 : ///
199 : /// If null - default [DatePickerStyles.selectedDateStyle] will be used.
200 : final TextStyle? selectedPeriodStartTextStyle;
201 :
202 : /// Decoration for the last date of the selected range.
203 : final BoxDecoration? selectedPeriodLastDecoration;
204 :
205 : /// Text style for the last date of the selected range.
206 : ///
207 : /// If null - default [DatePickerStyles.selectedDateStyle] will be used.
208 : final TextStyle? selectedPeriodEndTextStyle;
209 :
210 : /// Decoration for the date of the selected range
211 : /// which is not first date and not end date of this range.
212 : ///
213 : /// If there is only one date selected
214 : /// [DatePickerStyles.selectedSingleDateDecoration] will be used.
215 : final BoxDecoration? selectedPeriodMiddleDecoration;
216 :
217 : /// Text style for the middle date of the selected range.
218 : ///
219 : /// If null - default [DatePickerStyles.selectedDateStyle] will be used.
220 : final TextStyle? selectedPeriodMiddleTextStyle;
221 :
222 : /// Return new [DatePickerRangeStyles] object
223 : /// where fields with null values set with defaults from given theme.
224 0 : @override
225 : DatePickerRangeStyles fulfillWithTheme(ThemeData theme) {
226 0 : Color accentColor = theme.colorScheme.secondary;
227 :
228 0 : DatePickerStyles commonStyles = super.fulfillWithTheme(theme);
229 :
230 : final BoxDecoration _selectedPeriodStartDecoration =
231 0 : selectedPeriodStartDecoration ??
232 0 : BoxDecoration(
233 : color: accentColor,
234 : borderRadius: const BorderRadiusDirectional.only(
235 : topStart: Radius.circular(10.0),
236 : bottomStart: Radius.circular(10.0)),
237 : );
238 :
239 : final BoxDecoration _selectedPeriodLastDecoration =
240 0 : selectedPeriodLastDecoration ??
241 0 : BoxDecoration(
242 : color: accentColor,
243 : borderRadius: const BorderRadiusDirectional.only(
244 : topEnd: Radius.circular(10.0),
245 : bottomEnd: Radius.circular(10.0)),
246 : );
247 :
248 : final BoxDecoration _selectedPeriodMiddleDecoration =
249 0 : selectedPeriodMiddleDecoration ??
250 0 : BoxDecoration(
251 : color: accentColor,
252 : shape: BoxShape.rectangle,
253 : );
254 :
255 : final TextStyle? _selectedPeriodStartTextStyle =
256 0 : selectedPeriodStartTextStyle ?? commonStyles.selectedDateStyle;
257 :
258 : final TextStyle? _selectedPeriodMiddleTextStyle =
259 0 : selectedPeriodMiddleTextStyle ?? commonStyles.selectedDateStyle;
260 :
261 : final TextStyle? _selectedPeriodEndTextStyle =
262 0 : selectedPeriodEndTextStyle ?? commonStyles.selectedDateStyle;
263 :
264 0 : return DatePickerRangeStyles(
265 0 : disabledDateStyle: commonStyles.disabledDateStyle,
266 0 : currentDateStyle: commonStyles.currentDateStyle,
267 0 : displayedPeriodTitle: commonStyles.displayedPeriodTitle,
268 0 : selectedDateStyle: commonStyles.selectedDateStyle,
269 0 : selectedSingleDateDecoration: commonStyles.selectedSingleDateDecoration,
270 0 : defaultDateTextStyle: commonStyles.defaultDateTextStyle,
271 0 : dayHeaderStyle: commonStyles.dayHeaderStyle,
272 0 : dayHeaderStyleBuilder: commonStyles.dayHeaderStyleBuilder,
273 0 : dayHeaderTitleBuilder: commonStyles.dayHeaderTitleBuilder,
274 0 : firstDayOfWeekIndex: firstDayOfeWeekIndex,
275 : selectedPeriodStartDecoration: _selectedPeriodStartDecoration,
276 : selectedPeriodMiddleDecoration: _selectedPeriodMiddleDecoration,
277 : selectedPeriodLastDecoration: _selectedPeriodLastDecoration,
278 : selectedPeriodStartTextStyle: _selectedPeriodStartTextStyle,
279 : selectedPeriodMiddleTextStyle: _selectedPeriodMiddleTextStyle,
280 : selectedPeriodEndTextStyle: _selectedPeriodEndTextStyle,
281 : );
282 : }
283 :
284 : /// Styles for the pickers that allows to select range ([RangePicker],
285 : /// [WeekPicker]).
286 0 : DatePickerRangeStyles({
287 : TextStyle? displayedPeriodTitle,
288 : TextStyle? currentDateStyle,
289 : TextStyle? disabledDateStyle,
290 : TextStyle? selectedDateStyle,
291 : BoxDecoration? selectedSingleDateDecoration,
292 : TextStyle? defaultDateTextStyle,
293 : DayHeaderStyle? dayHeaderStyle,
294 : DayHeaderStyleBuilder? dayHeaderStyleBuilder,
295 : DayHeaderTitleBuilder? dayHeaderTitleBuilder,
296 : Widget nextIcon = const Icon(Icons.chevron_right),
297 : Widget prevIcon = const Icon(Icons.chevron_left),
298 : int? firstDayOfWeekIndex,
299 : this.selectedPeriodLastDecoration,
300 : this.selectedPeriodMiddleDecoration,
301 : this.selectedPeriodStartDecoration,
302 : this.selectedPeriodStartTextStyle,
303 : this.selectedPeriodMiddleTextStyle,
304 : this.selectedPeriodEndTextStyle,
305 0 : }) : super(
306 : displayedPeriodTitle: displayedPeriodTitle,
307 : currentDateStyle: currentDateStyle,
308 : disabledDateStyle: disabledDateStyle,
309 : selectedDateStyle: selectedDateStyle,
310 : selectedSingleDateDecoration: selectedSingleDateDecoration,
311 : defaultDateTextStyle: defaultDateTextStyle,
312 : dayHeaderStyle: dayHeaderStyle,
313 : dayHeaderStyleBuilder: dayHeaderStyleBuilder,
314 : dayHeaderTitleBuilder: dayHeaderTitleBuilder,
315 : nextIcon: nextIcon,
316 : prevIcon: prevIcon,
317 : firstDayOfeWeekIndex: firstDayOfWeekIndex);
318 :
319 0 : @override
320 : bool operator ==(Object other) {
321 : if (identical(this, other)) return true;
322 0 : if (other.runtimeType != runtimeType) return false;
323 :
324 0 : return other is DatePickerRangeStyles &&
325 0 : other.selectedPeriodStartDecoration == selectedPeriodStartDecoration &&
326 0 : other.selectedPeriodStartTextStyle == selectedPeriodStartTextStyle &&
327 0 : other.selectedPeriodLastDecoration == selectedPeriodLastDecoration &&
328 0 : other.selectedPeriodEndTextStyle == selectedPeriodEndTextStyle &&
329 0 : other.selectedPeriodMiddleDecoration ==
330 0 : selectedPeriodMiddleDecoration &&
331 0 : other.selectedPeriodMiddleTextStyle == selectedPeriodMiddleTextStyle &&
332 0 : other.displayedPeriodTitle == displayedPeriodTitle &&
333 0 : other.currentDateStyle == currentDateStyle &&
334 0 : other.disabledDateStyle == disabledDateStyle &&
335 0 : other.selectedDateStyle == selectedDateStyle &&
336 0 : other.defaultDateTextStyle == defaultDateTextStyle &&
337 0 : other.selectedSingleDateDecoration == selectedSingleDateDecoration &&
338 0 : other.dayHeaderStyle == dayHeaderStyle &&
339 0 : other.dayHeaderStyleBuilder == dayHeaderStyleBuilder &&
340 0 : other.dayHeaderTitleBuilder == dayHeaderTitleBuilder &&
341 0 : other.prevIcon == prevIcon &&
342 0 : other.nextIcon == nextIcon &&
343 0 : other.firstDayOfeWeekIndex == firstDayOfeWeekIndex;
344 : }
345 :
346 0 : @override
347 0 : int get hashCode => hashValues(
348 0 : selectedPeriodStartDecoration,
349 0 : selectedPeriodStartTextStyle,
350 0 : selectedPeriodLastDecoration,
351 0 : selectedPeriodEndTextStyle,
352 0 : selectedPeriodMiddleDecoration,
353 0 : selectedPeriodMiddleTextStyle,
354 0 : displayedPeriodTitle,
355 0 : currentDateStyle,
356 0 : disabledDateStyle,
357 0 : selectedDateStyle,
358 0 : defaultDateTextStyle,
359 0 : selectedSingleDateDecoration,
360 0 : dayHeaderStyle,
361 0 : dayHeaderStyleBuilder,
362 0 : dayHeaderTitleBuilder,
363 0 : prevIcon,
364 0 : nextIcon,
365 0 : firstDayOfeWeekIndex);
366 : }
367 :
368 : /// User styles for the day header in date picker.
369 : @immutable
370 : class DayHeaderStyle {
371 : /// If null - textTheme.caption from the Theme will be used.
372 : final TextStyle? textStyle;
373 :
374 : /// If null - no decoration will be applied for the day header;
375 : final BoxDecoration? decoration;
376 :
377 : /// Creates styles for the day headers in date pickers.
378 : ///
379 : /// See also:
380 : /// * [DatePickerStyles.dayHeaderStyleBuilder]
381 0 : const DayHeaderStyle({this.textStyle, this.decoration});
382 :
383 0 : @override
384 : bool operator ==(Object other) {
385 : if (identical(this, other)) return true;
386 0 : if (other.runtimeType != runtimeType) return false;
387 :
388 0 : return other is DayHeaderStyle &&
389 0 : other.textStyle == textStyle &&
390 0 : other.decoration == decoration;
391 : }
392 :
393 0 : @override
394 0 : int get hashCode => hashValues(textStyle, decoration);
395 : }
|