|
|
|
import 'package:calendar_date_picker2/calendar_date_picker2.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
|
|
|
|
|
|
|
final today = DateUtils.dateOnly(DateTime.now());
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
runApp(const MyApp());
|
|
|
|
}
|
|
|
|
|
|
|
|
class MyApp extends StatelessWidget {
|
|
|
|
const MyApp({Key? key}) : super(key: key);
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return MaterialApp(
|
|
|
|
title: 'CalendarDatePicker2 Demo',
|
|
|
|
theme: ThemeData(
|
|
|
|
primarySwatch: Colors.blue,
|
|
|
|
),
|
|
|
|
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
|
|
|
supportedLocales: const [
|
|
|
|
Locale('en', ''),
|
|
|
|
Locale('zh', ''),
|
|
|
|
Locale('he', ''),
|
|
|
|
Locale('es', ''),
|
|
|
|
Locale('ru', ''),
|
|
|
|
Locale('ko', ''),
|
|
|
|
Locale('hi', ''),
|
|
|
|
],
|
|
|
|
home: const MyHomePage(title: 'CalendarDatePicker2 Demo'),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class MyHomePage extends StatefulWidget {
|
|
|
|
const MyHomePage({Key? key, required this.title}) : super(key: key);
|
|
|
|
|
|
|
|
final String title;
|
|
|
|
|
|
|
|
@override
|
|
|
|
State<MyHomePage> createState() => _MyHomePageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _MyHomePageState extends State<MyHomePage> {
|
|
|
|
final _scrollController = ScrollController();
|
|
|
|
List<DateTime?> _dialogCalendarPickerValue = [
|
|
|
|
DateTime(2021, 8, 10),
|
|
|
|
DateTime(2021, 8, 13),
|
|
|
|
];
|
|
|
|
List<DateTime?> _singleDatePickerValueWithDefaultValue = [
|
|
|
|
DateTime.now().add(const Duration(days: 1)),
|
|
|
|
];
|
|
|
|
List<DateTime?> _multiDatePickerValueWithDefaultValue = [
|
|
|
|
DateTime(today.year, today.month, 1),
|
|
|
|
DateTime(today.year, today.month, 5),
|
|
|
|
DateTime(today.year, today.month, 14),
|
|
|
|
DateTime(today.year, today.month, 17),
|
|
|
|
DateTime(today.year, today.month, 25),
|
|
|
|
];
|
|
|
|
List<DateTime?> _rangeDatePickerValueWithDefaultValue = [
|
|
|
|
DateTime(1999, 5, 6),
|
|
|
|
DateTime(1999, 5, 21),
|
|
|
|
];
|
|
|
|
|
|
|
|
List<DateTime?> _rangeDatePickerWithActionButtonsWithValue = [
|
|
|
|
DateTime.now(),
|
|
|
|
DateTime.now().add(const Duration(days: 5)),
|
|
|
|
];
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
_scrollController.addListener(() {
|
|
|
|
if (_scrollController.offset > 1000) {
|
|
|
|
// ignore: avoid_print
|
|
|
|
print('scrolling distance: ${_scrollController.offset}');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Scaffold(
|
|
|
|
appBar: AppBar(
|
|
|
|
title: Text(widget.title),
|
|
|
|
),
|
|
|
|
body: SingleChildScrollView(
|
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
|
|
children: [
|
|
|
|
Wrap(
|
|
|
|
alignment: WrapAlignment.center,
|
|
|
|
children: <Widget>[
|
|
|
|
_buildCalendarDialogButton(),
|
|
|
|
_buildSingleDatePickerWithValue(),
|
|
|
|
_buildMultiDatePickerWithValue(),
|
|
|
|
_buildRangeDatePickerWithValue(),
|
|
|
|
_buildCalendarWithActionButtons(),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
Wrap(
|
|
|
|
alignment: WrapAlignment.center,
|
|
|
|
children: <Widget>[
|
|
|
|
_buildScrollCalendarDialogButton(),
|
|
|
|
_buildScrollSingleDatePickerWithValue(),
|
|
|
|
_buildScrollMultiDatePickerWithValue(),
|
|
|
|
_buildScrollRangeDatePickerWithValue(),
|
|
|
|
_buildScrollCalendarWithActionButtons(),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
String _getValueText(
|
|
|
|
CalendarDatePicker2Type datePickerType,
|
|
|
|
List<DateTime?> values,
|
|
|
|
) {
|
|
|
|
values =
|
|
|
|
values.map((e) => e != null ? DateUtils.dateOnly(e) : null).toList();
|
|
|
|
var valueText = (values.isNotEmpty ? values[0] : null)
|
|
|
|
.toString()
|
|
|
|
.replaceAll('00:00:00.000', '');
|
|
|
|
|
|
|
|
if (datePickerType == CalendarDatePicker2Type.multi) {
|
|
|
|
valueText = values.isNotEmpty
|
|
|
|
? values
|
|
|
|
.map((v) => v.toString().replaceAll('00:00:00.000', ''))
|
|
|
|
.join(', ')
|
|
|
|
: 'null';
|
|
|
|
} else if (datePickerType == CalendarDatePicker2Type.range) {
|
|
|
|
if (values.isNotEmpty) {
|
|
|
|
final startDate = values[0].toString().replaceAll('00:00:00.000', '');
|
|
|
|
final endDate = values.length > 1
|
|
|
|
? values[1].toString().replaceAll('00:00:00.000', '')
|
|
|
|
: 'null';
|
|
|
|
valueText = '$startDate to $endDate';
|
|
|
|
} else {
|
|
|
|
return 'null';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return valueText;
|
|
|
|
}
|
|
|
|
|
|
|
|
_buildCalendarDialogButton() {
|
|
|
|
const dayTextStyle =
|
|
|
|
TextStyle(color: Colors.black, fontWeight: FontWeight.w700);
|
|
|
|
final weekendTextStyle =
|
|
|
|
TextStyle(color: Colors.grey[500], fontWeight: FontWeight.w600);
|
|
|
|
final anniversaryTextStyle = TextStyle(
|
|
|
|
color: Colors.red[400],
|
|
|
|
fontWeight: FontWeight.w700,
|
|
|
|
decoration: TextDecoration.underline,
|
|
|
|
);
|
|
|
|
final config = CalendarDatePicker2WithActionButtonsConfig(
|
|
|
|
calendarViewScrollPhysics: const NeverScrollableScrollPhysics(),
|
|
|
|
dayTextStyle: dayTextStyle,
|
|
|
|
calendarType: CalendarDatePicker2Type.range,
|
|
|
|
selectedDayHighlightColor: Colors.purple[800],
|
|
|
|
closeDialogOnCancelTapped: true,
|
|
|
|
firstDayOfWeek: 1,
|
|
|
|
weekdayLabelTextStyle: const TextStyle(
|
|
|
|
color: Colors.black87,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
controlsTextStyle: const TextStyle(
|
|
|
|
color: Colors.black,
|
|
|
|
fontSize: 15,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
centerAlignModePicker: true,
|
|
|
|
customModePickerIcon: const SizedBox(),
|
|
|
|
selectedDayTextStyle: dayTextStyle.copyWith(color: Colors.white),
|
|
|
|
dayTextStylePredicate: ({required date}) {
|
|
|
|
TextStyle? textStyle;
|
|
|
|
if (date.weekday == DateTime.saturday ||
|
|
|
|
date.weekday == DateTime.sunday) {
|
|
|
|
textStyle = weekendTextStyle;
|
|
|
|
}
|
|
|
|
if (DateUtils.isSameDay(date, DateTime(2021, 1, 25))) {
|
|
|
|
textStyle = anniversaryTextStyle;
|
|
|
|
}
|
|
|
|
return textStyle;
|
|
|
|
},
|
|
|
|
dayBuilder: ({
|
|
|
|
required date,
|
|
|
|
textStyle,
|
|
|
|
decoration,
|
|
|
|
isSelected,
|
|
|
|
isDisabled,
|
|
|
|
isToday,
|
|
|
|
}) {
|
|
|
|
Widget? dayWidget;
|
|
|
|
if (date.day % 3 == 0 && date.day % 9 != 0) {
|
|
|
|
dayWidget = Container(
|
|
|
|
decoration: decoration,
|
|
|
|
child: Center(
|
|
|
|
child: Stack(
|
|
|
|
alignment: AlignmentDirectional.center,
|
|
|
|
children: [
|
|
|
|
Text(
|
|
|
|
MaterialLocalizations.of(context).formatDecimal(date.day),
|
|
|
|
style: textStyle,
|
|
|
|
),
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.only(top: 27.5),
|
|
|
|
child: Container(
|
|
|
|
height: 4,
|
|
|
|
width: 4,
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
borderRadius: BorderRadius.circular(5),
|
|
|
|
color: isSelected == true
|
|
|
|
? Colors.white
|
|
|
|
: Colors.grey[500],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return dayWidget;
|
|
|
|
},
|
|
|
|
yearBuilder: ({
|
|
|
|
required year,
|
|
|
|
decoration,
|
|
|
|
isCurrentYear,
|
|
|
|
isDisabled,
|
|
|
|
isSelected,
|
|
|
|
textStyle,
|
|
|
|
}) {
|
|
|
|
return Center(
|
|
|
|
child: Container(
|
|
|
|
decoration: decoration,
|
|
|
|
height: 36,
|
|
|
|
width: 72,
|
|
|
|
child: Center(
|
|
|
|
child: Semantics(
|
|
|
|
selected: isSelected,
|
|
|
|
button: true,
|
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
Text(
|
|
|
|
year.toString(),
|
|
|
|
style: textStyle,
|
|
|
|
),
|
|
|
|
if (isCurrentYear == true)
|
|
|
|
Container(
|
|
|
|
padding: const EdgeInsets.all(5),
|
|
|
|
margin: const EdgeInsets.only(left: 5),
|
|
|
|
decoration: const BoxDecoration(
|
|
|
|
shape: BoxShape.circle,
|
|
|
|
color: Colors.redAccent,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.all(15),
|
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
ElevatedButton(
|
|
|
|
onPressed: () async {
|
|
|
|
final values = await showCalendarDatePicker2Dialog(
|
|
|
|
context: context,
|
|
|
|
config: config,
|
|
|
|
dialogSize: const Size(325, 370),
|
|
|
|
borderRadius: BorderRadius.circular(15),
|
|
|
|
value: _dialogCalendarPickerValue,
|
|
|
|
dialogBackgroundColor: Colors.white,
|
|
|
|
);
|
|
|
|
if (values != null) {
|
|
|
|
// ignore: avoid_print
|
|
|
|
print(_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
values,
|
|
|
|
));
|
|
|
|
setState(() {
|
|
|
|
_dialogCalendarPickerValue = values;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
child: const Text('Open Calendar Dialog'),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_buildScrollCalendarDialogButton() {
|
|
|
|
const dayTextStyle =
|
|
|
|
TextStyle(color: Colors.black, fontWeight: FontWeight.w700);
|
|
|
|
final weekendTextStyle =
|
|
|
|
TextStyle(color: Colors.grey[500], fontWeight: FontWeight.w600);
|
|
|
|
final anniversaryTextStyle = TextStyle(
|
|
|
|
color: Colors.red[400],
|
|
|
|
fontWeight: FontWeight.w700,
|
|
|
|
decoration: TextDecoration.underline,
|
|
|
|
);
|
|
|
|
final config = CalendarDatePicker2WithActionButtonsConfig(
|
|
|
|
calendarViewScrollPhysics: const NeverScrollableScrollPhysics(),
|
|
|
|
dayTextStyle: dayTextStyle,
|
|
|
|
calendarType: CalendarDatePicker2Type.range,
|
|
|
|
calendarViewMode: CalendarDatePicker2Mode.scroll,
|
|
|
|
hideScrollViewMonthWeekHeader: true,
|
|
|
|
selectedDayHighlightColor: Colors.purple[800],
|
|
|
|
closeDialogOnCancelTapped: true,
|
|
|
|
firstDayOfWeek: 1,
|
|
|
|
weekdayLabelTextStyle: const TextStyle(
|
|
|
|
color: Colors.black87,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
controlsTextStyle: const TextStyle(
|
|
|
|
color: Colors.black,
|
|
|
|
fontSize: 15,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
centerAlignModePicker: true,
|
|
|
|
customModePickerIcon: const SizedBox(),
|
|
|
|
selectedDayTextStyle: dayTextStyle.copyWith(color: Colors.white),
|
|
|
|
dayTextStylePredicate: ({required date}) {
|
|
|
|
TextStyle? textStyle;
|
|
|
|
if (date.weekday == DateTime.saturday ||
|
|
|
|
date.weekday == DateTime.sunday) {
|
|
|
|
textStyle = weekendTextStyle;
|
|
|
|
}
|
|
|
|
if (DateUtils.isSameDay(date, DateTime(2021, 1, 25))) {
|
|
|
|
textStyle = anniversaryTextStyle;
|
|
|
|
}
|
|
|
|
return textStyle;
|
|
|
|
},
|
|
|
|
dayBuilder: ({
|
|
|
|
required date,
|
|
|
|
textStyle,
|
|
|
|
decoration,
|
|
|
|
isSelected,
|
|
|
|
isDisabled,
|
|
|
|
isToday,
|
|
|
|
}) {
|
|
|
|
Widget? dayWidget;
|
|
|
|
if (date.day % 3 == 0 && date.day % 9 != 0) {
|
|
|
|
dayWidget = Container(
|
|
|
|
decoration: decoration,
|
|
|
|
child: Center(
|
|
|
|
child: Stack(
|
|
|
|
alignment: AlignmentDirectional.center,
|
|
|
|
children: [
|
|
|
|
Text(
|
|
|
|
MaterialLocalizations.of(context).formatDecimal(date.day),
|
|
|
|
style: textStyle,
|
|
|
|
),
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.only(top: 27.5),
|
|
|
|
child: Container(
|
|
|
|
height: 4,
|
|
|
|
width: 4,
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
borderRadius: BorderRadius.circular(5),
|
|
|
|
color: isSelected == true
|
|
|
|
? Colors.white
|
|
|
|
: Colors.grey[500],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return dayWidget;
|
|
|
|
},
|
|
|
|
yearBuilder: ({
|
|
|
|
required year,
|
|
|
|
decoration,
|
|
|
|
isCurrentYear,
|
|
|
|
isDisabled,
|
|
|
|
isSelected,
|
|
|
|
textStyle,
|
|
|
|
}) {
|
|
|
|
return Center(
|
|
|
|
child: Container(
|
|
|
|
decoration: decoration,
|
|
|
|
height: 36,
|
|
|
|
width: 72,
|
|
|
|
child: Center(
|
|
|
|
child: Semantics(
|
|
|
|
selected: isSelected,
|
|
|
|
button: true,
|
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
Text(
|
|
|
|
year.toString(),
|
|
|
|
style: textStyle,
|
|
|
|
),
|
|
|
|
if (isCurrentYear == true)
|
|
|
|
Container(
|
|
|
|
padding: const EdgeInsets.all(5),
|
|
|
|
margin: const EdgeInsets.only(left: 5),
|
|
|
|
decoration: const BoxDecoration(
|
|
|
|
shape: BoxShape.circle,
|
|
|
|
color: Colors.redAccent,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.all(15),
|
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
ElevatedButton(
|
|
|
|
onPressed: () async {
|
|
|
|
final values = await showCalendarDatePicker2Dialog(
|
|
|
|
context: context,
|
|
|
|
config: config,
|
|
|
|
dialogSize: const Size(325, 860),
|
|
|
|
borderRadius: BorderRadius.circular(15),
|
|
|
|
value: _dialogCalendarPickerValue,
|
|
|
|
dialogBackgroundColor: Colors.white,
|
|
|
|
);
|
|
|
|
if (values != null) {
|
|
|
|
// ignore: avoid_print
|
|
|
|
print(_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
values,
|
|
|
|
));
|
|
|
|
setState(() {
|
|
|
|
_dialogCalendarPickerValue = values;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
child: const Text('Open Scroll Calendar Dialog'),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildSingleDatePickerWithValue() {
|
|
|
|
final config = CalendarDatePicker2Config(
|
|
|
|
selectedDayHighlightColor: Colors.amber[900],
|
|
|
|
weekdayLabels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
|
|
weekdayLabelTextStyle: const TextStyle(
|
|
|
|
color: Colors.black87,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
firstDayOfWeek: 1,
|
|
|
|
controlsHeight: 50,
|
|
|
|
dayMaxWidth: 25,
|
|
|
|
animateToDisplayedMonthDate: true,
|
|
|
|
controlsTextStyle: const TextStyle(
|
|
|
|
color: Colors.black,
|
|
|
|
fontSize: 15,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
dayTextStyle: const TextStyle(
|
|
|
|
color: Colors.amber,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
disabledDayTextStyle: const TextStyle(
|
|
|
|
color: Colors.grey,
|
|
|
|
),
|
|
|
|
centerAlignModePicker: true,
|
|
|
|
useAbbrLabelForMonthModePicker: true,
|
|
|
|
modePickerTextHandler: ({required monthDate, isMonthPicker}) {
|
|
|
|
if (isMonthPicker ?? false) {
|
|
|
|
// Custom month picker text
|
|
|
|
return '${getLocaleShortMonthFormat(const Locale('en')).format(monthDate)} C';
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
firstDate: DateTime(DateTime.now().year - 2, DateTime.now().month - 1,
|
|
|
|
DateTime.now().day - 5),
|
|
|
|
lastDate: DateTime(DateTime.now().year + 3, DateTime.now().month + 2,
|
|
|
|
DateTime.now().day + 10),
|
|
|
|
selectableDayPredicate: (day) =>
|
|
|
|
!day
|
|
|
|
.difference(DateTime.now().add(const Duration(days: 3)))
|
|
|
|
.isNegative &&
|
|
|
|
day.isBefore(DateTime.now().add(const Duration(days: 30))),
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
const Text('Single Date Picker'),
|
|
|
|
SizedBox(
|
|
|
|
width: 270,
|
|
|
|
child: CalendarDatePicker2(
|
|
|
|
displayedMonthDate: _singleDatePickerValueWithDefaultValue.first,
|
|
|
|
config: config,
|
|
|
|
value: _singleDatePickerValueWithDefaultValue,
|
|
|
|
onValueChanged: (dates) => setState(
|
|
|
|
() => _singleDatePickerValueWithDefaultValue = dates),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
Row(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const Text('Selection(s): '),
|
|
|
|
const SizedBox(width: 10),
|
|
|
|
Text(
|
|
|
|
_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
_singleDatePickerValueWithDefaultValue,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const SizedBox(height: 25),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildScrollSingleDatePickerWithValue() {
|
|
|
|
final config = CalendarDatePicker2Config(
|
|
|
|
calendarViewMode: CalendarDatePicker2Mode.scroll,
|
|
|
|
selectedDayHighlightColor: Colors.amber[900],
|
|
|
|
weekdayLabels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
|
|
weekdayLabelTextStyle: const TextStyle(
|
|
|
|
color: Colors.black87,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
firstDayOfWeek: 1,
|
|
|
|
controlsHeight: 50,
|
|
|
|
controlsTextStyle: const TextStyle(
|
|
|
|
color: Colors.black,
|
|
|
|
fontSize: 15,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
dayTextStyle: const TextStyle(
|
|
|
|
color: Colors.amber,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
disabledDayTextStyle: const TextStyle(
|
|
|
|
color: Colors.grey,
|
|
|
|
),
|
|
|
|
centerAlignModePicker: true,
|
|
|
|
useAbbrLabelForMonthModePicker: true,
|
|
|
|
firstDate: DateTime(DateTime.now().year - 2, DateTime.now().month - 1,
|
|
|
|
DateTime.now().day - 5),
|
|
|
|
lastDate: DateTime(DateTime.now().year + 3, DateTime.now().month + 2,
|
|
|
|
DateTime.now().day + 10),
|
|
|
|
selectableDayPredicate: (day) => !day
|
|
|
|
.difference(DateTime.now().subtract(const Duration(days: 3)))
|
|
|
|
.isNegative,
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
const Text('Scroll Single Date Picker'),
|
|
|
|
SizedBox(
|
|
|
|
width: 270,
|
|
|
|
height: 800,
|
|
|
|
child: CalendarDatePicker2(
|
|
|
|
config: config.copyWith(
|
|
|
|
scrollViewController: _scrollController,
|
|
|
|
dayMaxWidth: 32,
|
|
|
|
controlsHeight: 40,
|
|
|
|
hideScrollViewTopHeader: true,
|
|
|
|
),
|
|
|
|
value: _singleDatePickerValueWithDefaultValue,
|
|
|
|
onValueChanged: (dates) => setState(
|
|
|
|
() => _singleDatePickerValueWithDefaultValue = dates),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
Row(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const Text('Selection(s): '),
|
|
|
|
const SizedBox(width: 10),
|
|
|
|
Text(
|
|
|
|
_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
_singleDatePickerValueWithDefaultValue,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const SizedBox(height: 25),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildMultiDatePickerWithValue() {
|
|
|
|
final config = CalendarDatePicker2Config(
|
|
|
|
disableMonthPicker: true,
|
|
|
|
calendarType: CalendarDatePicker2Type.multi,
|
|
|
|
selectedDayHighlightColor: Colors.indigo,
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
const Text('Multi Date Picker'),
|
|
|
|
CalendarDatePicker2(
|
|
|
|
config: config,
|
|
|
|
value: _multiDatePickerValueWithDefaultValue,
|
|
|
|
onValueChanged: (dates) =>
|
|
|
|
setState(() => _multiDatePickerValueWithDefaultValue = dates),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
Wrap(
|
|
|
|
children: [
|
|
|
|
const Text('Selection(s): '),
|
|
|
|
const SizedBox(width: 10),
|
|
|
|
Text(
|
|
|
|
_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
_multiDatePickerValueWithDefaultValue,
|
|
|
|
),
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
maxLines: 1,
|
|
|
|
softWrap: false,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const SizedBox(height: 25),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildScrollMultiDatePickerWithValue() {
|
|
|
|
final config = CalendarDatePicker2Config(
|
|
|
|
disableMonthPicker: true,
|
|
|
|
calendarType: CalendarDatePicker2Type.multi,
|
|
|
|
calendarViewMode: CalendarDatePicker2Mode.scroll,
|
|
|
|
selectedDayHighlightColor: Colors.indigo,
|
|
|
|
scrollViewTopHeaderTextStyle: const TextStyle(
|
|
|
|
color: Colors.black87,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
const Text('Scroll Multi Date Picker'),
|
|
|
|
SizedBox(
|
|
|
|
height: 800,
|
|
|
|
child: CalendarDatePicker2(
|
|
|
|
config: config,
|
|
|
|
value: _multiDatePickerValueWithDefaultValue,
|
|
|
|
onValueChanged: (dates) =>
|
|
|
|
setState(() => _multiDatePickerValueWithDefaultValue = dates),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
Wrap(
|
|
|
|
children: [
|
|
|
|
const Text('Selection(s): '),
|
|
|
|
const SizedBox(width: 10),
|
|
|
|
Text(
|
|
|
|
_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
_multiDatePickerValueWithDefaultValue,
|
|
|
|
),
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
maxLines: 1,
|
|
|
|
softWrap: false,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const SizedBox(height: 25),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildRangeDatePickerWithValue() {
|
|
|
|
final config = CalendarDatePicker2Config(
|
|
|
|
centerAlignModePicker: true,
|
|
|
|
calendarType: CalendarDatePicker2Type.range,
|
|
|
|
selectedDayHighlightColor: Colors.teal[800],
|
|
|
|
weekdayLabelTextStyle: const TextStyle(
|
|
|
|
color: Colors.black87,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
controlsTextStyle: const TextStyle(
|
|
|
|
color: Colors.black,
|
|
|
|
fontSize: 15,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
dynamicCalendarRows: true,
|
|
|
|
modePickerBuilder: ({required monthDate, isMonthPicker}) {
|
|
|
|
return Center(
|
|
|
|
child: Container(
|
|
|
|
padding: const EdgeInsets.all(5),
|
|
|
|
margin: const EdgeInsets.symmetric(horizontal: 5),
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
color: isMonthPicker == true ? Colors.red : Colors.teal[800],
|
|
|
|
borderRadius: BorderRadius.circular(5),
|
|
|
|
),
|
|
|
|
child: Text(
|
|
|
|
isMonthPicker == true
|
|
|
|
? getLocaleShortMonthFormat(const Locale('en'))
|
|
|
|
.format(monthDate)
|
|
|
|
: monthDate.year.toString(),
|
|
|
|
style: const TextStyle(
|
|
|
|
color: Colors.white,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
weekdayLabelBuilder: ({required weekday, isScrollViewTopHeader}) {
|
|
|
|
if (weekday == DateTime.wednesday) {
|
|
|
|
return const Center(
|
|
|
|
child: Text(
|
|
|
|
'W',
|
|
|
|
style: TextStyle(
|
|
|
|
color: Colors.red,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
disabledDayTextStyle:
|
|
|
|
const TextStyle(color: Colors.grey, fontWeight: FontWeight.w400),
|
|
|
|
selectableDayPredicate: (day) {
|
|
|
|
if (_rangeDatePickerValueWithDefaultValue.isEmpty ||
|
|
|
|
_rangeDatePickerValueWithDefaultValue.length == 2) {
|
|
|
|
// exclude Wednesday
|
|
|
|
return day.weekday != DateTime.wednesday;
|
|
|
|
} else {
|
|
|
|
// Make sure range does not contain any Wednesday
|
|
|
|
final firstDate = _rangeDatePickerValueWithDefaultValue.first;
|
|
|
|
final range = [firstDate!, day]..sort();
|
|
|
|
for (var date = range.first;
|
|
|
|
date.compareTo(range.last) <= 0;
|
|
|
|
date = date.add(const Duration(days: 1))) {
|
|
|
|
if (date.weekday == DateTime.wednesday) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
const Text('Range Date Picker'),
|
|
|
|
CalendarDatePicker2(
|
|
|
|
config: config,
|
|
|
|
value: _rangeDatePickerValueWithDefaultValue,
|
|
|
|
onValueChanged: (dates) =>
|
|
|
|
setState(() => _rangeDatePickerValueWithDefaultValue = dates),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
Row(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const Text('Selection(s): '),
|
|
|
|
const SizedBox(width: 10),
|
|
|
|
Text(
|
|
|
|
_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
_rangeDatePickerValueWithDefaultValue,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const SizedBox(height: 25),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildScrollRangeDatePickerWithValue() {
|
|
|
|
final config = CalendarDatePicker2Config(
|
|
|
|
centerAlignModePicker: true,
|
|
|
|
calendarType: CalendarDatePicker2Type.range,
|
|
|
|
calendarViewMode: CalendarDatePicker2Mode.scroll,
|
|
|
|
rangeBidirectional: true,
|
|
|
|
selectedDayHighlightColor: Colors.teal[800],
|
|
|
|
weekdayLabelTextStyle: const TextStyle(
|
|
|
|
color: Colors.black87,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
controlsTextStyle: const TextStyle(
|
|
|
|
color: Colors.black,
|
|
|
|
fontSize: 15,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
dynamicCalendarRows: true,
|
|
|
|
weekdayLabelBuilder: ({required weekday, isScrollViewTopHeader}) {
|
|
|
|
if (weekday == DateTime.wednesday && isScrollViewTopHeader != true) {
|
|
|
|
return const Center(
|
|
|
|
child: Text(
|
|
|
|
'W',
|
|
|
|
style: TextStyle(
|
|
|
|
color: Colors.red,
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
modePickerTextHandler: ({required monthDate, isMonthPicker}) {
|
|
|
|
if (isMonthPicker ?? false) {
|
|
|
|
return '${getLocaleShortMonthFormat(const Locale('en')).format(monthDate)} New';
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
disabledDayTextStyle:
|
|
|
|
const TextStyle(color: Colors.grey, fontWeight: FontWeight.w400),
|
|
|
|
selectableDayPredicate: (day) {
|
|
|
|
if (_rangeDatePickerValueWithDefaultValue.isEmpty ||
|
|
|
|
_rangeDatePickerValueWithDefaultValue.length == 2) {
|
|
|
|
// exclude Wednesday
|
|
|
|
return day.weekday != DateTime.wednesday;
|
|
|
|
} else {
|
|
|
|
// Make sure range does not contain any Wednesday
|
|
|
|
final firstDate = _rangeDatePickerValueWithDefaultValue.first;
|
|
|
|
final range = [firstDate!, day]..sort();
|
|
|
|
for (var date = range.first;
|
|
|
|
date.compareTo(range.last) <= 0;
|
|
|
|
date = date.add(const Duration(days: 1))) {
|
|
|
|
if (date.weekday == DateTime.wednesday) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
const Text('Scroll Range Date Picker'),
|
|
|
|
SizedBox(
|
|
|
|
height: 800,
|
|
|
|
child: CalendarDatePicker2(
|
|
|
|
config: config,
|
|
|
|
value: _rangeDatePickerValueWithDefaultValue,
|
|
|
|
onValueChanged: (dates) =>
|
|
|
|
setState(() => _rangeDatePickerValueWithDefaultValue = dates),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
Row(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const Text('Selection(s): '),
|
|
|
|
const SizedBox(width: 10),
|
|
|
|
Text(
|
|
|
|
_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
_rangeDatePickerValueWithDefaultValue,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const SizedBox(height: 25),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildCalendarWithActionButtons() {
|
|
|
|
final config = CalendarDatePicker2WithActionButtonsConfig(
|
|
|
|
calendarType: CalendarDatePicker2Type.range,
|
|
|
|
disableModePicker: true,
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
const Text('Date Picker With Action Buttons'),
|
|
|
|
CalendarDatePicker2WithActionButtons(
|
|
|
|
config: config,
|
|
|
|
value: _rangeDatePickerWithActionButtonsWithValue,
|
|
|
|
onValueChanged: (dates) => setState(
|
|
|
|
() => _rangeDatePickerWithActionButtonsWithValue = dates),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
Row(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const Text('Selection(s): '),
|
|
|
|
const SizedBox(width: 10),
|
|
|
|
Flexible(
|
|
|
|
child: Text(
|
|
|
|
_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
_rangeDatePickerWithActionButtonsWithValue,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const SizedBox(height: 25),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildScrollCalendarWithActionButtons() {
|
|
|
|
final config = CalendarDatePicker2WithActionButtonsConfig(
|
|
|
|
calendarType: CalendarDatePicker2Type.range,
|
|
|
|
calendarViewMode: CalendarDatePicker2Mode.scroll,
|
|
|
|
rangeBidirectional: true,
|
|
|
|
scrollViewConstraints: const BoxConstraints(maxHeight: 800),
|
|
|
|
scrollViewMonthYearBuilder: (monthDate) {
|
|
|
|
return Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
Container(
|
|
|
|
margin: const EdgeInsets.only(bottom: 5),
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
color: const Color.fromARGB(255, 11, 69, 117),
|
|
|
|
borderRadius: BorderRadius.circular(5),
|
|
|
|
),
|
|
|
|
child: Row(
|
|
|
|
children: [
|
|
|
|
Text(
|
|
|
|
getLocaleShortMonthFormat(const Locale('en'))
|
|
|
|
.format(monthDate),
|
|
|
|
style: const TextStyle(
|
|
|
|
color: Colors.white,
|
|
|
|
fontSize: 15,
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const SizedBox(width: 5),
|
|
|
|
Text(
|
|
|
|
monthDate.year.toString(),
|
|
|
|
style: const TextStyle(
|
|
|
|
color: Colors.white,
|
|
|
|
fontSize: 15,
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
},
|
|
|
|
hideScrollViewMonthWeekHeader: true,
|
|
|
|
disableModePicker: true,
|
|
|
|
);
|
|
|
|
return SizedBox(
|
|
|
|
width: 375,
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
const Text('Date Picker With Action Buttons'),
|
|
|
|
CalendarDatePicker2WithActionButtons(
|
|
|
|
config: config,
|
|
|
|
value: _rangeDatePickerWithActionButtonsWithValue,
|
|
|
|
onValueChanged: (dates) => setState(
|
|
|
|
() => _rangeDatePickerWithActionButtonsWithValue = dates),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
Row(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
const Text('Selection(s): '),
|
|
|
|
const SizedBox(width: 10),
|
|
|
|
Flexible(
|
|
|
|
child: Text(
|
|
|
|
_getValueText(
|
|
|
|
config.calendarType,
|
|
|
|
_rangeDatePickerWithActionButtonsWithValue,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const SizedBox(height: 25),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} |