From e281d245e4dbd80e08db9be72d6d89916a7a5b24 Mon Sep 17 00:00:00 2001 From: Badr Kouki Date: Sun, 29 Jun 2025 10:19:07 +0100 Subject: [PATCH] refactor: update custom weekdays parameter --- example/lib/main.dart | 85 +++++++------ lib/bottom_picker.dart | 36 +++--- lib/cupertino/cupertino_date_picker.dart | 149 ++++++++--------------- lib/widgets/date_picker.dart | 13 +- lib/widgets/range_picker.dart | 3 - 5 files changed, 121 insertions(+), 165 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 10378ff..f3adf46 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -172,19 +172,6 @@ class ExampleApp extends StatelessWidget { onPressed: () { _openDateTimePicker( context, - CupertinoDatePickerCalendarType.fullWeek, - ); - }, - child: Text('Date and Time Picker', textAlign: TextAlign.center), - ), - ), - SizedBox( - width: buttonWidth, - child: ElevatedButton( - onPressed: () { - _openDateTimePicker( - context, - CupertinoDatePickerCalendarType.workDays, ); }, child: Text('Workday Picker', textAlign: TextAlign.center), @@ -194,9 +181,8 @@ class ExampleApp extends StatelessWidget { width: buttonWidth, child: ElevatedButton( onPressed: () { - _openDateTimePicker( + _openDateTimePickerWeekend( context, - CupertinoDatePickerCalendarType.weekend, ); }, child: Text('Weekend Day Picker', textAlign: TextAlign.center), @@ -312,11 +298,6 @@ class ExampleApp extends StatelessWidget { initialDateTime: DateTime(1996, 10, 22), maxDateTime: DateTime(1998), minDateTime: DateTime(1980), - pickerTextStyle: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: 12, - ), onChange: (index) { print(index); }, @@ -376,11 +357,6 @@ class ExampleApp extends StatelessWidget { initialDateTime: DateTime(1996, 10, 22), maxDateTime: DateTime(1998), minDateTime: DateTime(1980), - pickerTextStyle: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: 12, - ), onChange: (index) { print(index); }, @@ -445,11 +421,6 @@ class ExampleApp extends StatelessWidget { dateOrder: DatePickerDateOrder.dmy, initialSecondDate: DateTime.now().add(Duration(days: 230)), itemExtent: 20, - pickerTextStyle: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: 12, - ), onRangeDateSubmitPressed: (firstDate, secondDate) { print(firstDate); print(secondDate); @@ -484,11 +455,6 @@ class ExampleApp extends StatelessWidget { ], ); }, - pickerTextStyle: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: 12, - ), showTimeSeparator: true, bottomPickerTheme: BottomPickerTheme.plumPlate, onRangeTimeSubmitPressed: (firstDate, secondDate) { @@ -588,7 +554,6 @@ class ExampleApp extends StatelessWidget { void _openDateTimePicker( BuildContext context, - CupertinoDatePickerCalendarType calendarType, ) { BottomPicker.dateTime( minuteInterval: 2, @@ -629,7 +594,53 @@ class ExampleApp extends StatelessWidget { Color(0xfffdcbf1), Color(0xffe6dee9), ], - calendarType: calendarType, + calendarDays: CupertinoDatePickerWidget.workDays, + ).show(context); + } + + void _openDateTimePickerWeekend( + BuildContext context, + ) { + BottomPicker.dateTime( + minuteInterval: 2, + headerBuilder: (context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Set the event exact time and date', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + color: Colors.black, + ), + ), + InkWell( + onTap: () { + print('Picker closed'); + Navigator.pop(context); + }, + child: Text( + 'close', + style: TextStyle( + decoration: TextDecoration.underline, + ), + ), + ), + ], + ); + }, + onSubmit: (date) { + print(date); + }, + minDateTime: DateTime(2021, 5, 1), + maxDateTime: DateTime(2021, 8, 2), + initialDateTime: DateTime(2021, 5, 1), + gradientColors: [ + Color(0xfffdcbf1), + Color(0xffe6dee9), + ], + calendarDays: CupertinoDatePickerWidget.weekend, ).show(context); } } diff --git a/lib/bottom_picker.dart b/lib/bottom_picker.dart index 512d812..6453f58 100644 --- a/lib/bottom_picker.dart +++ b/lib/bottom_picker.dart @@ -54,7 +54,7 @@ class BottomPicker extends StatefulWidget { this.buttonSingleColor, this.backgroundColor = Colors.white, this.pickerThemeData, - @Deprecated("should use pickerThemeData instead") + @Deprecated('should use pickerThemeData instead') this.pickerTextStyle = const TextStyle( fontSize: 14, color: Colors.black, @@ -75,7 +75,7 @@ class BottomPicker extends StatefulWidget { @Deprecated('should use headerBuilder instead') this.closeWidget, this.closeOnSubmit = true, this.headerBuilder, - this.calendarType = CupertinoDatePickerCalendarType.fullWeek, + this.calendarDays = CupertinoDatePickerWidget.fullWeek, }) { dateOrder = null; onRangeDateSubmitPressed = null; @@ -110,7 +110,7 @@ class BottomPicker extends StatefulWidget { this.backgroundColor = Colors.white, this.dateOrder = DatePickerDateOrder.ymd, this.pickerThemeData, - @Deprecated("should use pickerThemeData instead") + @Deprecated('should use pickerThemeData instead') this.pickerTextStyle = const TextStyle( fontSize: 14, color: Colors.black, @@ -130,7 +130,7 @@ class BottomPicker extends StatefulWidget { @Deprecated('should use headerBuilder instead') this.closeWidget, this.closeOnSubmit = true, this.headerBuilder, - this.calendarType = CupertinoDatePickerCalendarType.fullWeek, + this.calendarDays = CupertinoDatePickerWidget.fullWeek, }) { datePickerMode = CupertinoDatePickerMode.date; bottomPickerType = BottomPickerType.dateTime; @@ -161,7 +161,7 @@ class BottomPicker extends StatefulWidget { this.buttonSingleColor, this.backgroundColor = Colors.white, this.pickerThemeData, - @Deprecated("should use pickerThemeData instead") + @Deprecated('should use pickerThemeData instead') this.pickerTextStyle = const TextStyle( fontSize: 14, color: Colors.black, @@ -181,7 +181,7 @@ class BottomPicker extends StatefulWidget { @Deprecated('should use headerBuilder instead') this.closeWidget, this.closeOnSubmit = true, this.headerBuilder, - this.calendarType = CupertinoDatePickerCalendarType.fullWeek, + this.calendarDays = CupertinoDatePickerWidget.fullWeek, }) { datePickerMode = CupertinoDatePickerMode.monthYear; bottomPickerType = BottomPickerType.dateTime; @@ -216,7 +216,7 @@ class BottomPicker extends StatefulWidget { this.backgroundColor = Colors.white, this.dateOrder = DatePickerDateOrder.ymd, this.pickerThemeData, - @Deprecated("should use pickerThemeData instead") + @Deprecated('should use pickerThemeData instead') this.pickerTextStyle = const TextStyle( fontSize: 14, color: Colors.black, @@ -237,7 +237,7 @@ class BottomPicker extends StatefulWidget { @Deprecated('should use headerBuilder instead') this.closeWidget, this.closeOnSubmit = true, this.headerBuilder, - this.calendarType = CupertinoDatePickerCalendarType.fullWeek, + this.calendarDays = CupertinoDatePickerWidget.fullWeek, }) { datePickerMode = CupertinoDatePickerMode.dateAndTime; bottomPickerType = BottomPickerType.dateTime; @@ -269,7 +269,7 @@ class BottomPicker extends StatefulWidget { this.buttonSingleColor, this.backgroundColor = Colors.white, this.pickerThemeData, - @Deprecated("should use pickerThemeData instead") + @Deprecated('should use pickerThemeData instead') this.pickerTextStyle = const TextStyle( fontSize: 14, color: Colors.black, @@ -290,7 +290,7 @@ class BottomPicker extends StatefulWidget { @Deprecated('should use headerBuilder instead') this.closeWidget, this.closeOnSubmit = true, this.headerBuilder, - this.calendarType = CupertinoDatePickerCalendarType.fullWeek, + this.calendarDays = CupertinoDatePickerWidget.fullWeek, }) { datePickerMode = CupertinoDatePickerMode.time; bottomPickerType = BottomPickerType.time; @@ -324,7 +324,7 @@ class BottomPicker extends StatefulWidget { this.buttonSingleColor, this.backgroundColor = Colors.white, this.pickerThemeData, - @Deprecated("should use pickerThemeData instead") + @Deprecated('should use pickerThemeData instead') this.pickerTextStyle = const TextStyle( fontSize: 14, color: Colors.black, @@ -343,7 +343,7 @@ class BottomPicker extends StatefulWidget { @Deprecated('should use headerBuilder instead') this.closeWidget, this.closeOnSubmit = true, this.headerBuilder, - this.calendarType = CupertinoDatePickerCalendarType.fullWeek, + this.calendarDays = CupertinoDatePickerWidget.fullWeek, }) { dateOrder = null; onRangeDateSubmitPressed = null; @@ -371,7 +371,7 @@ class BottomPicker extends StatefulWidget { this.buttonSingleColor, this.backgroundColor = Colors.white, this.pickerThemeData, - @Deprecated("should use pickerThemeData instead") + @Deprecated('should use pickerThemeData instead') this.pickerTextStyle = const TextStyle( fontSize: 14, color: Colors.black, @@ -397,7 +397,7 @@ class BottomPicker extends StatefulWidget { @Deprecated('should use headerBuilder instead') this.closeWidget, this.closeOnSubmit = true, this.headerBuilder, - this.calendarType = CupertinoDatePickerCalendarType.fullWeek, + this.calendarDays = CupertinoDatePickerWidget.fullWeek, }) { datePickerMode = CupertinoDatePickerMode.date; bottomPickerType = BottomPickerType.rangeDate; @@ -440,7 +440,7 @@ class BottomPicker extends StatefulWidget { this.buttonSingleColor, this.backgroundColor = Colors.white, this.pickerThemeData, - @Deprecated("should use pickerThemeData instead") + @Deprecated('should use pickerThemeData instead') this.pickerTextStyle = const TextStyle( fontSize: 14, color: Colors.black, @@ -467,7 +467,7 @@ class BottomPicker extends StatefulWidget { @Deprecated('should use headerBuilder instead') this.closeWidget, this.closeOnSubmit = true, this.headerBuilder, - this.calendarType = CupertinoDatePickerCalendarType.fullWeek, + this.calendarDays = CupertinoDatePickerWidget.fullWeek, }) { datePickerMode = CupertinoDatePickerMode.time; bottomPickerType = BottomPickerType.rangeTime; @@ -763,7 +763,7 @@ class BottomPicker extends StatefulWidget { final bool closeOnSubmit; /// The datepicker calendar type - final CupertinoDatePickerCalendarType calendarType; + final List calendarDays; ///display the bottom picker popup ///[context] the app context to display the popup @@ -954,7 +954,6 @@ class BottomPickerState extends State { textStyle: widget.pickerTextStyle, itemExtent: widget.itemExtent, showTimeSeparator: widget.showTimeSeparator, - calendarType: widget.calendarType, pickerThemeData: widget.pickerThemeData, ) : widget.bottomPickerType == BottomPickerType.dateTime @@ -973,7 +972,6 @@ class BottomPickerState extends State { textStyle: widget.pickerTextStyle, itemExtent: widget.itemExtent, showTimeSeparator: widget.showTimeSeparator, - calendarType: widget.calendarType, pickerThemeData: widget.pickerThemeData, ) : widget.bottomPickerType == diff --git a/lib/cupertino/cupertino_date_picker.dart b/lib/cupertino/cupertino_date_picker.dart index f7fc7d5..4675383 100644 --- a/lib/cupertino/cupertino_date_picker.dart +++ b/lib/cupertino/cupertino_date_picker.dart @@ -187,12 +187,6 @@ enum _PickerColumnType { twoPoints, } -enum CupertinoDatePickerCalendarType { - fullWeek, - workDays, - weekend, -} - /// A date picker widget in iOS style. /// /// There are several modes of the date picker listed in [CupertinoDatePickerMode]. @@ -289,7 +283,7 @@ class CupertinoDatePickerWidget extends StatefulWidget { this.itemExtent = _kItemExtent, this.selectionOverlayBuilder, this.showTimeSeparator = false, - this.calendarType = CupertinoDatePickerCalendarType.fullWeek, + this.calendarDays = fullWeek, }) : initialDateTime = initialDateTime ?? DateTime.now(), assert( itemExtent > 0, @@ -430,7 +424,7 @@ class CupertinoDatePickerWidget extends StatefulWidget { /// Defaults to a value that matches the default iOS date picker wheel. final double itemExtent; - final CupertinoDatePickerCalendarType calendarType; + final List calendarDays; /// A function that returns a widget that is overlaid on the picker /// to highlight the currently selected entry. @@ -474,6 +468,29 @@ class CupertinoDatePickerWidget extends StatefulWidget { /// {@end-tool} final SelectionOverlayBuilder? selectionOverlayBuilder; + static const List fullWeek = [ + DateTime.monday, + DateTime.tuesday, + DateTime.wednesday, + DateTime.thursday, + DateTime.friday, + DateTime.saturday, + DateTime.sunday, + ]; + static const List weekend = [ + DateTime.saturday, + DateTime.sunday, + ]; + + static const List workDays = [ + DateTime.monday, + DateTime.tuesday, + DateTime.wednesday, + DateTime.thursday, + DateTime.friday, + ]; + + @override State createState() { // ignore: no_logic_in_create_state, https://github.com/flutter/flutter/issues/70499 @@ -715,17 +732,7 @@ class _CupertinoDatePickerDateTimeState void initState() { super.initState(); initialDateTime = widget.initialDateTime; - - switch (widget.calendarType) { - case CupertinoDatePickerCalendarType.workDays: - _handleWorkDaysInitialDateTime(); - break; - case CupertinoDatePickerCalendarType.weekend: - _handleWeekendInitialDateTime(); - break; - default: - } - + _handleWeekendInitialDateTime(); // Initially each of the "physical" regions is mapped to the meridiem region // with the same number, e.g., the first 12 items are mapped to the first 12 // hours of a day. Such mapping is flipped when the meridiem picker is scrolled @@ -744,29 +751,10 @@ class _CupertinoDatePickerDateTimeState PaintingBinding.instance.systemFonts.addListener(_handleSystemFontsChange); } - void _handleWorkDaysInitialDateTime() { - int daysToBeAdded = 0; - if (widget.calendarType == CupertinoDatePickerCalendarType.workDays && - initialDateTime.weekday == DateTime.saturday) { - daysToBeAdded = 2; - } else if (widget.calendarType == - CupertinoDatePickerCalendarType.workDays && - initialDateTime.weekday == DateTime.sunday) { - daysToBeAdded = 1; - } - initialDateTime = DateTime( - initialDateTime.year, - initialDateTime.month, - initialDateTime.day + daysToBeAdded, - ); - } - void _handleWeekendInitialDateTime() { int daysToBeAdded = 0; - if (widget.calendarType == CupertinoDatePickerCalendarType.weekend && - (initialDateTime.weekday != DateTime.saturday && - initialDateTime.weekday != DateTime.saturday)) { - daysToBeAdded = DateTime.saturday - initialDateTime.weekday; + if (!widget.calendarDays.contains(initialDateTime.weekday)) { + daysToBeAdded = widget.calendarDays.first - initialDateTime.weekday; } initialDateTime = DateTime( initialDateTime.year, @@ -903,20 +891,7 @@ class _CupertinoDatePickerDateTimeState initialDateTime.day + index, ); - bool isValidDate = true; - - if (widget.calendarType == CupertinoDatePickerCalendarType.workDays) { - if (tempDateTime.weekday == DateTime.saturday || - tempDateTime.weekday == DateTime.sunday) { - isValidDate = false; - } - } else if (widget.calendarType == - CupertinoDatePickerCalendarType.weekend) { - if (tempDateTime.weekday != DateTime.saturday && - tempDateTime.weekday != DateTime.sunday) { - isValidDate = false; - } - } + bool isValidDate = widget.calendarDays.contains(tempDateTime.weekday); final DateTime rangeStart = DateTime( initialDateTime.year, @@ -1181,6 +1156,24 @@ class _CupertinoDatePickerDateTimeState ); } + void _checkOnCustomDaysDisplay() { + final DateTime selectedDate = selectedDateTime; + final bool minCheck = widget.minimumDate?.isAfter(selectedDate) ?? false; + + if (!widget.calendarDays.contains(selectedDate.weekday)) { + const int daysThreshold = 1; + final DateTime targetDate = + selectedDate.add(const Duration(days: daysThreshold)); + + _scrollToDate( + targetDate, + selectedDate, + minCheck, + newItemIndex: dateController.selectedItem + daysThreshold, + ); + } + } + // One or more pickers have just stopped scrolling. void _pickerDidStopScrolling() { // Call setState to update the greyed out date/hour/minute/meridiem. @@ -1197,42 +1190,7 @@ class _CupertinoDatePickerDateTimeState final bool minCheck = widget.minimumDate?.isAfter(selectedDate) ?? false; final bool maxCheck = widget.maximumDate?.isBefore(selectedDate) ?? false; - if (widget.calendarType == CupertinoDatePickerCalendarType.workDays) { - int daysThreshold = 0; - if (selectedDate.weekday == DateTime.saturday) { - daysThreshold = -1; - } else if (selectedDate.weekday == DateTime.sunday) { - daysThreshold = -2; - } - - if ((selectedDate.weekday == DateTime.sunday || - selectedDate.weekday == DateTime.saturday) && - (_isDateBeforeMinDate(selectedDate))) { - daysThreshold = selectedDate.weekday == DateTime.sunday ? 1 : 2; - } - DateTime targetDate = selectedDate.add(Duration(days: daysThreshold)); - - _scrollToDate( - targetDate, - selectedDate, - minCheck, - newItemIndex: dateController.selectedItem + daysThreshold, - ); - } else if (widget.calendarType == CupertinoDatePickerCalendarType.weekend) { - if (selectedDate.weekday != DateTime.sunday && - selectedDate.weekday != DateTime.saturday) { - int daysThreshold = DateTime.saturday - selectedDate.weekday; - DateTime targetDate = selectedDate.add(Duration(days: daysThreshold)); - - _scrollToDate( - targetDate, - selectedDate, - minCheck, - newItemIndex: dateController.selectedItem + daysThreshold, - ); - } - } - + _checkOnCustomDaysDisplay(); if (minCheck || maxCheck) { // We have minCheck === !maxCheck. final DateTime targetDate = @@ -1241,13 +1199,6 @@ class _CupertinoDatePickerDateTimeState } } - bool _isDateBeforeMinDate(DateTime dateTime) { - if (widget.minimumDate == null) return false; - return widget.minimumDate!.day >= dateTime.day && - widget.minimumDate!.month >= dateTime.month && - widget.minimumDate!.year >= dateTime.year; - } - void _scrollToDate( DateTime newDate, DateTime fromDate, @@ -1261,9 +1212,7 @@ class _CupertinoDatePickerDateTimeState fromDate.day != newDate.day) { _animateColumnControllerToItem( dateController, - widget.calendarType != CupertinoDatePickerCalendarType.fullWeek - ? newItemIndex! - : selectedDayFromInitial, + newItemIndex ?? selectedDayFromInitial, ); } diff --git a/lib/widgets/date_picker.dart b/lib/widgets/date_picker.dart index 3274333..3e66ddd 100644 --- a/lib/widgets/date_picker.dart +++ b/lib/widgets/date_picker.dart @@ -13,7 +13,7 @@ class DatePicker extends StatelessWidget { final TextStyle textStyle; final double? itemExtent; final bool showTimeSeparator; - final CupertinoDatePickerCalendarType calendarType; + final List calendarDays; final CupertinoTextThemeData? pickerThemeData; const DatePicker({ @@ -29,7 +29,7 @@ class DatePicker extends StatelessWidget { this.dateOrder, this.itemExtent = 0, this.showTimeSeparator = false, - required this.calendarType, + this.calendarDays = CupertinoDatePickerWidget.fullWeek, this.pickerThemeData, }); @@ -37,9 +37,10 @@ class DatePicker extends StatelessWidget { Widget build(BuildContext context) { return CupertinoTheme( data: CupertinoThemeData( - textTheme: pickerThemeData ?? CupertinoTextThemeData( - dateTimePickerTextStyle: textStyle, - ), + textTheme: pickerThemeData ?? + CupertinoTextThemeData( + dateTimePickerTextStyle: textStyle, + ), ), child: CupertinoDatePickerWidget( itemExtent: itemExtent ?? 0, @@ -52,7 +53,7 @@ class DatePicker extends StatelessWidget { minimumDate: minDateTime, use24hFormat: use24hFormat, dateOrder: dateOrder, - calendarType: calendarType, + calendarDays: calendarDays, ), ); } diff --git a/lib/widgets/range_picker.dart b/lib/widgets/range_picker.dart index c594440..d5944fe 100644 --- a/lib/widgets/range_picker.dart +++ b/lib/widgets/range_picker.dart @@ -1,4 +1,3 @@ -import 'package:bottom_picker/cupertino/cupertino_date_picker.dart'; import 'package:bottom_picker/widgets/date_picker.dart'; import 'package:flutter/cupertino.dart'; @@ -107,7 +106,6 @@ class _RangePickerState extends State { }, dateOrder: widget.dateOrder, textStyle: widget.textStyle, - calendarType: CupertinoDatePickerCalendarType.fullWeek, pickerThemeData: widget.pickerThemeData, ), ), @@ -125,7 +123,6 @@ class _RangePickerState extends State { minuteInterval: widget.minuteInterval ?? 1, itemExtent: widget.itemExtent, showTimeSeparator: widget.showTimeSeperator, - calendarType: CupertinoDatePickerCalendarType.fullWeek, pickerThemeData: widget.pickerThemeData, ), ),