1
0
mirror of https://github.com/nisrulz/flutter-examples.git synced 2025-11-09 04:58:58 +00:00

New Example - Calendar (#91)

This commit is contained in:
Ishaan Kesarwani
2022-10-22 23:59:43 +05:30
committed by GitHub
parent d9cc97a7ea
commit 91d4d1b868
100 changed files with 7300 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
import 'package:flutter/material.dart';
import 'package:flutter_material_color_picker/flutter_material_color_picker.dart';
/// Dialog with some Material colors ([materialColors]) to pick one of them.
class ColorPickerDialog extends StatefulWidget {
/// Initially selected color.
///
/// If pre-selected color is not from [materialColors] [Colors.blue] will be
/// used.
final Color selectedColor;
///
const ColorPickerDialog({
Key? key,
required this.selectedColor
}) : super(key: key);
@override
State<StatefulWidget> createState() => _ColorPickerDialogState();
}
class _ColorPickerDialogState extends State<ColorPickerDialog> {
Color _mainColor = Colors.blue;
@override
void initState() {
super.initState();
bool isSelectedMaterial = materialColors.contains(widget.selectedColor);
if (isSelectedMaterial) {
_mainColor = widget.selectedColor;
}
}
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: const EdgeInsets.all(6.0),
title: const Text("Color picker"),
content: MaterialColorPicker(
selectedColor: _mainColor,
allowShades: false,
onMainColorChange: _onMainColorChange,
),
actions: [
TextButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop(null);
},
),
TextButton(
child: const Text('SUBMIT'),
onPressed: () {
Navigator.of(context).pop(_mainColor);
},
),
],
);
}
void _onMainColorChange (Color? newColor) {
if (newColor == null) return;
setState(() {
_mainColor = newColor;
});
}
}

View File

@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
// default with and height for the button container
const double _kBtnSize = 24.0;
/// Round colored button with title to select some style color.
class ColorSelectorBtn extends StatelessWidget {
/// Title near color button.
final String title;
/// Color of the button.
final Color color;
/// onTap callback.
final VoidCallback showDialogFunction;
/// Size of the circle.
///
/// By default is [_kBtnSize].
final double colorBtnSize;
///
const ColorSelectorBtn(
{Key? key,
required this.title,
required this.color,
required this.showDialogFunction,
this.colorBtnSize = _kBtnSize})
: super(key: key);
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Expanded(
child: Row(
children: <Widget>[
GestureDetector(
onTap: showDialogFunction,
child: Container(
height: colorBtnSize,
width: colorBtnSize,
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
),
),
const SizedBox(
width: 8.0,
),
Expanded(
child: Text(
title,
overflow: TextOverflow.ellipsis,
)),
],
),
);
}
}

View File

@@ -0,0 +1,188 @@
import 'package:flutter/material.dart';
import 'package:flutter_date_pickers/flutter_date_pickers.dart' as dp;
import 'package:flutter_date_pickers/flutter_date_pickers.dart';
import '../color_picker_dialog.dart';
import '../color_selector_btn.dart';
import '../event.dart';
/// Page with [dp.DayPicker].
class DayPickerPage extends StatefulWidget {
/// Custom events.
final List<Event> events;
///
const DayPickerPage({
Key? key,
this.events = const []
}) : super(key: key);
@override
State<StatefulWidget> createState() => _DayPickerPageState();
}
class _DayPickerPageState extends State<DayPickerPage> {
DateTime _selectedDate = DateTime.now();
DateTime _firstDate = DateTime.now().subtract(Duration(days: 45));
DateTime _lastDate = DateTime.now().add(Duration(days: 45));
Color selectedDateStyleColor = Colors.blue;
Color selectedSingleDateDecorationColor = Colors.red;
@override
void didChangeDependencies() {
super.didChangeDependencies();
Color? bodyTextColor = Theme.of(context).accentTextTheme.bodyText1?.color;
if (bodyTextColor != null) selectedDateStyleColor = bodyTextColor;
selectedSingleDateDecorationColor = Theme.of(context).accentColor;
}
@override
Widget build(BuildContext context) {
// add selected colors to default settings
dp.DatePickerRangeStyles styles = dp.DatePickerRangeStyles(
selectedDateStyle: Theme.of(context)
.accentTextTheme
.bodyText1
?.copyWith(color: selectedDateStyleColor),
selectedSingleDateDecoration: BoxDecoration(
color: selectedSingleDateDecorationColor,
shape: BoxShape.circle
),
dayHeaderStyle: DayHeaderStyle(
textStyle: TextStyle(
color: Colors.red
)
)
);
return Flex(
direction: MediaQuery.of(context).orientation == Orientation.portrait
? Axis.vertical
: Axis.horizontal,
children: <Widget>[
Expanded(
child: dp.DayPicker.single(
selectedDate: _selectedDate,
onChanged: _onSelectedDateChanged,
firstDate: _firstDate,
lastDate: _lastDate,
datePickerStyles: styles,
datePickerLayoutSettings: dp.DatePickerLayoutSettings(
maxDayPickerRowCount: 2,
showPrevMonthEnd: true,
showNextMonthStart: true
),
selectableDayPredicate: _isSelectableCustom,
eventDecorationBuilder: _eventDecorationBuilder,
),
),
Container(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Selected date styles",
style: Theme.of(context).textTheme.subtitle1,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ColorSelectorBtn(
title: "Text",
color: selectedDateStyleColor,
showDialogFunction: _showSelectedDateDialog,
colorBtnSize: 42.0,
),
SizedBox(
width: 12.0,
),
ColorSelectorBtn(
title: "Background",
color: selectedSingleDateDecorationColor,
showDialogFunction: _showSelectedBackgroundColorDialog,
colorBtnSize: 42.0,
),
],
),
),
Text("Selected: $_selectedDate")
],
),
),
),
],
);
}
// select text color of the selected date
void _showSelectedDateDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedDateStyleColor,
));
if (newSelectedColor != null) {
setState(() {
selectedDateStyleColor = newSelectedColor;
});
}
}
// select background color of the selected date
void _showSelectedBackgroundColorDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedSingleDateDecorationColor,
));
if (newSelectedColor != null) {
setState(() {
selectedSingleDateDecorationColor = newSelectedColor;
});
}
}
void _onSelectedDateChanged(DateTime newDate) {
setState(() {
_selectedDate = newDate;
});
}
// ignore: prefer_expression_function_bodies
bool _isSelectableCustom (DateTime day) {
return day.weekday < 6;
}
dp.EventDecoration? _eventDecorationBuilder(DateTime date) {
List<DateTime> eventsDates = widget.events
.map<DateTime>((Event e) => e.date)
.toList();
bool isEventDate = eventsDates.any((DateTime d) =>
date.year == d.year
&& date.month == d.month
&& d.day == date.day);
BoxDecoration roundedBorder = BoxDecoration(
border: Border.all(
color: Colors.deepOrange,
),
borderRadius: BorderRadius.all(Radius.circular(3.0))
);
return isEventDate
? dp.EventDecoration(boxDecoration: roundedBorder)
: null;
}
}

View File

@@ -0,0 +1,191 @@
import 'package:flutter/material.dart';
import 'package:flutter_date_pickers/flutter_date_pickers.dart' as dp;
import '../color_picker_dialog.dart';
import '../color_selector_btn.dart';
import '../event.dart';
/// Page with [dp.DayPicker] where many single days can be selected.
class DaysPickerPage extends StatefulWidget {
/// Custom events.
final List<Event> events;
///
const DaysPickerPage({
Key? key,
this.events = const []
}) : super(key: key);
@override
State<StatefulWidget> createState() => _DaysPickerPageState();
}
class _DaysPickerPageState extends State<DaysPickerPage> {
List<DateTime> _selectedDates = [];
DateTime _firstDate = DateTime.now().subtract(Duration(days: 45));
DateTime _lastDate = DateTime.now().add(Duration(days: 45));
Color selectedDateStyleColor = Colors.blue;
Color selectedSingleDateDecorationColor = Colors.red;
@override
void initState() {
super.initState();
final now = DateTime.now();
_selectedDates = [
now,
now.subtract(Duration(days: 10)),
now.add(Duration(days: 7))
];
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
Color? bodyTextColor = Theme.of(context).accentTextTheme.bodyText1?.color;
if (bodyTextColor != null) selectedDateStyleColor = bodyTextColor;
selectedSingleDateDecorationColor = Theme.of(context).accentColor;
}
@override
Widget build(BuildContext context) {
// add selected colors to default settings
dp.DatePickerRangeStyles styles = dp.DatePickerRangeStyles(
selectedDateStyle: Theme.of(context)
.accentTextTheme
.bodyText1
?.copyWith(color: selectedDateStyleColor),
selectedSingleDateDecoration: BoxDecoration(
color: selectedSingleDateDecorationColor, shape: BoxShape.circle));
return Flex(
direction: MediaQuery.of(context).orientation == Orientation.portrait
? Axis.vertical
: Axis.horizontal,
children: <Widget>[
Expanded(
child: dp.DayPicker.multi(
selectedDates: _selectedDates,
onChanged: _onSelectedDateChanged,
firstDate: _firstDate,
lastDate: _lastDate,
datePickerStyles: styles,
datePickerLayoutSettings: dp.DatePickerLayoutSettings(
maxDayPickerRowCount: 2,
showPrevMonthEnd: true,
showNextMonthStart: true
),
selectableDayPredicate: _isSelectableCustom,
eventDecorationBuilder: _eventDecorationBuilder,
),
),
Container(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Selected date styles",
style: Theme.of(context).textTheme.subtitle1,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ColorSelectorBtn(
title: "Text",
color: selectedDateStyleColor,
showDialogFunction: _showSelectedDateDialog,
colorBtnSize: 42.0,
),
SizedBox(
width: 12.0,
),
ColorSelectorBtn(
title: "Background",
color: selectedSingleDateDecorationColor,
showDialogFunction: _showSelectedBackgroundColorDialog,
colorBtnSize: 42.0,
),
],
),
),
Text("Selected: $_selectedDates")
],
),
),
),
],
);
}
// select text color of the selected date
void _showSelectedDateDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedDateStyleColor,
));
if (newSelectedColor != null) {
setState(() {
selectedDateStyleColor = newSelectedColor;
});
}
}
// select background color of the selected date
void _showSelectedBackgroundColorDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedSingleDateDecorationColor,
));
if (newSelectedColor != null) {
setState(() {
selectedSingleDateDecorationColor = newSelectedColor;
});
}
}
void _onSelectedDateChanged(List<DateTime> newDates) {
setState(() {
_selectedDates = newDates;
});
}
// ignore: prefer_expression_function_bodies
bool _isSelectableCustom (DateTime day) {
return day.weekday < 6;
}
dp.EventDecoration? _eventDecorationBuilder(DateTime date) {
List<DateTime> eventsDates = widget.events
.map<DateTime>((Event e) => e.date)
.toList();
bool isEventDate = eventsDates.any((DateTime d) =>
date.year == d.year
&& date.month == d.month
&& d.day == date.day);
BoxDecoration roundedBorder = BoxDecoration(
border: Border.all(
color: Colors.deepOrange,
),
borderRadius: BorderRadius.all(Radius.circular(3.0))
);
return isEventDate
? dp.EventDecoration(boxDecoration: roundedBorder)
: null;
}
}

View File

@@ -0,0 +1,134 @@
import 'package:flutter/material.dart';
import 'package:flutter_date_pickers/flutter_date_pickers.dart' as dp;
import '../color_picker_dialog.dart';
import '../color_selector_btn.dart';
/// Page with the [dp.MonthPicker].
class MonthPickerPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _MonthPickerPageState();
}
class _MonthPickerPageState extends State<MonthPickerPage> {
DateTime _firstDate = DateTime.now().subtract(Duration(days: 350));
DateTime _lastDate = DateTime.now().add(Duration(days: 350));
DateTime _selectedDate = DateTime.now();
Color selectedDateStyleColor = Colors.blue;
Color selectedSingleDateDecorationColor = Colors.red;
@override
void didChangeDependencies() {
super.didChangeDependencies();
Color? bodyTextColor = Theme.of(context).accentTextTheme.bodyText1?.color;
if (bodyTextColor != null) selectedDateStyleColor = bodyTextColor;
selectedSingleDateDecorationColor = Theme.of(context).accentColor;
}
@override
Widget build(BuildContext context) {
// add selected colors to default settings
dp.DatePickerStyles styles = dp.DatePickerStyles(
selectedDateStyle: Theme.of(context)
.accentTextTheme
.bodyText1
?.copyWith(color: selectedDateStyleColor),
selectedSingleDateDecoration: BoxDecoration(
color: selectedSingleDateDecorationColor, shape: BoxShape.circle));
return Flex(
direction: MediaQuery.of(context).orientation == Orientation.portrait
? Axis.vertical
: Axis.horizontal,
children: <Widget>[
Expanded(
child: dp.MonthPicker(
selectedDate: _selectedDate,
onChanged: _onSelectedDateChanged,
firstDate: _firstDate,
lastDate: _lastDate,
datePickerStyles: styles,
),
),
Container(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Selected date styles",
style: Theme.of(context).textTheme.subtitle1,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ColorSelectorBtn(
title: "Text",
color: selectedDateStyleColor,
showDialogFunction: _showSelectedDateDialog,
colorBtnSize: 42.0,
),
SizedBox(
width: 12.0,
),
ColorSelectorBtn(
title: "Background",
color: selectedSingleDateDecorationColor,
showDialogFunction: _showSelectedBackgroundColorDialog,
colorBtnSize: 42.0,
),
],
),
),
Text("Selected: $_selectedDate")
],
),
),
),
],
);
}
// select text color of the selected date
void _showSelectedDateDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedDateStyleColor,
));
if (newSelectedColor != null) {
setState(() {
selectedDateStyleColor = newSelectedColor;
});
}
}
// select background color of the selected date
void _showSelectedBackgroundColorDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedSingleDateDecorationColor,
));
if (newSelectedColor != null) {
setState(() {
selectedSingleDateDecorationColor = newSelectedColor;
});
}
}
void _onSelectedDateChanged(DateTime newDate) {
setState(() {
_selectedDate = newDate;
});
}
}

View File

@@ -0,0 +1,273 @@
import 'package:flutter/material.dart';
import 'package:flutter_date_pickers/flutter_date_pickers.dart';
import '../color_picker_dialog.dart';
import '../color_selector_btn.dart';
import '../event.dart';
/// Page with the [RangePicker].
class RangePickerPage extends StatefulWidget {
/// Custom events.
final List<Event> events;
///
const RangePickerPage({
Key? key,
this.events = const []
}) : super(key: key);
@override
State<StatefulWidget> createState() => _RangePickerPageState();
}
class _RangePickerPageState extends State<RangePickerPage> {
DateTime _firstDate = DateTime.now().subtract(Duration(days: 345));
DateTime _lastDate = DateTime.now().add(Duration(days: 345));
DatePeriod _selectedPeriod = DatePeriod(
DateTime.now().subtract(Duration(days: 30)),
DateTime.now().subtract(Duration(days: 12))
);
Color selectedPeriodStartColor = Colors.blue;
Color selectedPeriodLastColor = Colors.blue;
Color selectedPeriodMiddleColor = Colors.blue;
@override
void didChangeDependencies() {
super.didChangeDependencies();
selectedPeriodLastColor = Theme.of(context).accentColor;
selectedPeriodMiddleColor = Theme.of(context).accentColor;
selectedPeriodStartColor = Theme.of(context).accentColor;
}
@override
Widget build(BuildContext context) {
// add selected colors to default settings
DatePickerRangeStyles styles = DatePickerRangeStyles(
selectedPeriodLastDecoration: BoxDecoration(
color: selectedPeriodLastColor,
borderRadius: const BorderRadius.only(
topRight: Radius.circular(24.0),
bottomRight: Radius.circular(24.0))),
selectedPeriodStartDecoration: BoxDecoration(
color: selectedPeriodStartColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(24.0),
bottomLeft: Radius.circular(24.0)
),
),
selectedPeriodMiddleDecoration: BoxDecoration(
color: selectedPeriodMiddleColor, shape: BoxShape.rectangle),
nextIcon: const Icon(Icons.arrow_right),
prevIcon: const Icon(Icons.arrow_left),
dayHeaderStyleBuilder: _dayHeaderStyleBuilder
);
return Flex(
direction: MediaQuery.of(context).orientation == Orientation.portrait
? Axis.vertical
: Axis.horizontal,
children: <Widget>[
Expanded(
child: RangePicker(
initiallyShowDate: DateTime.now(),
selectedPeriod: _selectedPeriod,
onChanged: _onSelectedDateChanged,
firstDate: _firstDate,
lastDate: _lastDate,
datePickerStyles: styles,
eventDecorationBuilder: _eventDecorationBuilder,
selectableDayPredicate: _isSelectableCustom,
onSelectionError: _onSelectionError,
),
),
Container(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Selected date styles",
style: Theme.of(context).textTheme.subtitle1,
),
_stylesBlock(),
_selectedBlock()
],
),
),
),
],
);
}
// Block with show information about selected date
// and boundaries of the selected period.
Widget _selectedBlock() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_selectedPeriod != null
? Column(children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 4.0),
child: Text("Selected period boundaries:"),
),
Text(_selectedPeriod.start.toString()),
Text(_selectedPeriod.end.toString()),
])
: Container()
],
);
// block with color buttons inside
Widget _stylesBlock() => Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ColorSelectorBtn(
title: "Start",
color: selectedPeriodStartColor,
showDialogFunction: _showSelectedStartColorDialog),
SizedBox(
width: 12.0,
),
ColorSelectorBtn(
title: "Middle",
color: selectedPeriodMiddleColor,
showDialogFunction: _showSelectedMiddleColorDialog),
SizedBox(
width: 12.0,
),
ColorSelectorBtn(
title: "End",
color: selectedPeriodLastColor,
showDialogFunction: _showSelectedEndColorDialog),
],
),
);
// select background color for the first date of the selected period
void _showSelectedStartColorDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedPeriodStartColor,
));
if (newSelectedColor != null) {
setState(() {
selectedPeriodStartColor = newSelectedColor;
});
}
}
// select background color for the last date of the selected period
void _showSelectedEndColorDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedPeriodLastColor,
));
if (newSelectedColor != null) {
setState(() {
selectedPeriodLastColor = newSelectedColor;
});
}
}
// select background color for the middle dates of the selected period
void _showSelectedMiddleColorDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedPeriodMiddleColor,
));
if (newSelectedColor != null) {
setState(() {
selectedPeriodMiddleColor = newSelectedColor;
});
}
}
void _onSelectedDateChanged(DatePeriod newPeriod) {
setState(() {
_selectedPeriod = newPeriod;
});
}
EventDecoration? _eventDecorationBuilder(DateTime date) {
List<DateTime> eventsDates = widget.events
.map<DateTime>((Event e) => e.date)
.toList();
bool isEventDate = eventsDates.any((DateTime d) =>
date.year == d.year
&& date.month == d.month
&& d.day == date.day);
BoxDecoration roundedBorder = BoxDecoration(
border: Border.all(
color: Colors.green,
),
borderRadius: BorderRadius.all(Radius.circular(3.0))
);
return isEventDate
? EventDecoration(boxDecoration: roundedBorder)
: null;
}
// ignore: prefer_expression_function_bodies
bool _isSelectableCustom (DateTime day) {
DateTime now = DateTime.now();
DateTime yesterday = now.subtract(Duration(days: 1));
DateTime tomorrow = now.add(Duration(days: 1));
bool isYesterday = sameDate(day, yesterday);
bool isTomorrow = sameDate(day, tomorrow);
return !isYesterday && !isTomorrow;
// return true;
// return day.weekday < 6;
// return day.day != DateTime.now().add(Duration(days: 7)).day ;
}
void _onSelectionError(UnselectablePeriodException exception) {
DatePeriod errorPeriod = exception.period;
// If user supposed to set another start of the period.
bool selectStart = _selectedPeriod.start != errorPeriod.start;
DateTime newSelection = selectStart
? errorPeriod.start
: errorPeriod.end;
DatePeriod newPeriod = DatePeriod(newSelection, newSelection);
setState(() {
_selectedPeriod = newPeriod;
});
}
// 0 is Sunday, 6 is Saturday
DayHeaderStyle _dayHeaderStyleBuilder(int weekday) {
bool isWeekend = weekday == 0 || weekday == 6;
return DayHeaderStyle(
textStyle: TextStyle(
color: isWeekend ? Colors.red : Colors.teal
)
);
}
}
bool sameDate(DateTime first, DateTime second) {
return first.year == second.year && first.month == second.month && first.day == second.day;
}

View File

@@ -0,0 +1,228 @@
import 'package:flutter/material.dart';
import 'package:flutter_date_pickers/flutter_date_pickers.dart';
import '../event.dart';
/// Page with the [RangePicker] styled according to issue:
/// https://github.com/MariaMelnik/flutter_date_pickers/issues/49
class RangePickerPageStyled extends StatefulWidget {
/// Custom events.
final List<Event> events;
///
const RangePickerPageStyled({
Key? key,
this.events = const []
}) : super(key: key);
@override
State<StatefulWidget> createState() => _RangePickerPageStyledState();
}
class _RangePickerPageStyledState extends State<RangePickerPageStyled> {
DateTime _firstDate = DateTime.now().subtract(Duration(days: 345));
DateTime _lastDate = DateTime.now().add(Duration(days: 345));
DatePeriod _selectedPeriod = DatePeriod(
DateTime.now().subtract(Duration(days: 4)),
DateTime.now().add(Duration(days: 8))
);
Color selectedPeriodStartColor = Colors.blue;
Color selectedPeriodLastColor = Colors.blue;
Color selectedPeriodMiddleColor = Colors.blue;
@override
void initState() {
super.initState();
DateTime selectedPeriodStart = DateTime.now().subtract(Duration(days: 4));
DateTime selectedPeriodEnd = DateTime.now().add(Duration(days: 8));
_selectedPeriod = DatePeriod(selectedPeriodStart, selectedPeriodEnd);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// defaults for styles
selectedPeriodLastColor = Theme.of(context).accentColor;
selectedPeriodMiddleColor = Theme.of(context).accentColor;
selectedPeriodStartColor = Theme.of(context).accentColor;
}
@override
Widget build(BuildContext context) {
Color middleBgColor = Color.fromRGBO(237, 237, 250, 1);
DecorationImage circleImg = DecorationImage(
image: AssetImage('images/bg.png'),
fit: BoxFit.contain
);
// add selected colors to default settings
DatePickerRangeStyles styles = DatePickerRangeStyles(
selectedPeriodLastDecoration: BoxDecoration(
color: middleBgColor,
gradient: LinearGradient(
colors: [middleBgColor, Colors.transparent],
stops: [0.5, 0.5]
),
image: circleImg,
borderRadius: const BorderRadius.only(
topRight: Radius.circular(24.0),
bottomRight: Radius.circular(24.0))
),
selectedPeriodStartDecoration: BoxDecoration(
color: middleBgColor,
gradient: LinearGradient(
colors: [Colors.transparent, middleBgColor,],
stops: [0.5, 0.5]
),
image: circleImg,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(24.0),
bottomLeft: Radius.circular(24.0)
),
),
selectedPeriodMiddleDecoration: BoxDecoration(
color: middleBgColor,
shape: BoxShape.rectangle
),
);
return Flex(
direction: MediaQuery.of(context).orientation == Orientation.portrait
? Axis.vertical
: Axis.horizontal,
children: <Widget>[
Expanded(
child: RangePicker(
selectedPeriod: _selectedPeriod,
onChanged: _onSelectedDateChanged,
firstDate: _firstDate,
lastDate: _lastDate,
datePickerStyles: styles,
eventDecorationBuilder: _eventDecorationBuilder,
selectableDayPredicate: _isSelectableCustom,
onSelectionError: _onSelectionError,
datePickerLayoutSettings: DatePickerLayoutSettings(
showNextMonthStart: true,
showPrevMonthEnd: true
),
),
),
Container(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Selected date styles",
style: Theme.of(context).textTheme.subtitle1,
),
_selectedBlock()
],
),
),
),
],
);
}
// Block with show information about selected date
// and boundaries of the selected period.
Widget _selectedBlock() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_selectedPeriod != null
? Column(children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 4.0),
child: Text("Selected period boundaries:"),
),
Text(_selectedPeriod.start.toString()),
Text(_selectedPeriod.end.toString()),
])
: Container()
],
);
void _onSelectedDateChanged(DatePeriod newPeriod) {
setState(() {
_selectedPeriod = newPeriod;
});
}
EventDecoration? _eventDecorationBuilder(DateTime date) {
List<DateTime> eventsDates = widget.events
.map<DateTime>((Event e) => e.date)
.toList();
bool isEventDate = eventsDates.any((DateTime d) =>
date.year == d.year
&& date.month == d.month
&& d.day == date.day);
BoxDecoration roundedBorder = BoxDecoration(
border: Border.all(
color: Colors.green,
),
borderRadius: BorderRadius.all(Radius.circular(3.0))
);
return isEventDate
? EventDecoration(boxDecoration: roundedBorder)
: null;
}
// ignore: prefer_expression_function_bodies
bool _isSelectableCustom (DateTime day) {
DateTime now = DateTime.now();
DateTime yesterday = now.subtract(Duration(days: 1));
DateTime tomorrow = now.add(Duration(days: 1));
bool isYesterday = _sameDate(day, yesterday);
bool isTomorrow = _sameDate(day, tomorrow);
return !isYesterday && !isTomorrow;
// return true;
// return day.weekday < 6;
// return day.day != DateTime.now().add(Duration(days: 7)).day ;
}
void _onSelectionError(UnselectablePeriodException exception) {
DatePeriod errorPeriod = exception.period;
// If user supposed to set another start of the period.
bool selectStart = _selectedPeriod.start != errorPeriod.start;
DateTime newSelection = selectStart
? errorPeriod.start
: errorPeriod.end;
DatePeriod newPeriod = DatePeriod(newSelection, newSelection);
setState(() {
_selectedPeriod = newPeriod;
});
}
// 0 is Sunday, 6 is Saturday
DayHeaderStyle _dayHeaderStyleBuilder(int weekday) {
bool isWeekend = weekday == 0 || weekday == 6;
return DayHeaderStyle(
textStyle: TextStyle(
color: isWeekend ? Colors.red : Colors.teal
)
);
}
}
bool _sameDate(DateTime first, DateTime second) =>
first.year == second.year
&& first.month == second.month
&& first.day == second.day;

View File

@@ -0,0 +1,239 @@
import 'package:flutter/material.dart';
import 'package:flutter_date_pickers/flutter_date_pickers.dart';
import '../color_picker_dialog.dart';
import '../color_selector_btn.dart';
import '../event.dart';
/// Page with the [WeekPicker].
class WeekPickerPage extends StatefulWidget {
/// Custom events.
final List<Event> events;
///
const WeekPickerPage({
Key? key,
this.events = const []
}) : super(key: key);
@override
State<StatefulWidget> createState() => _WeekPickerPageState();
}
class _WeekPickerPageState extends State<WeekPickerPage> {
DateTime _selectedDate = DateTime.now();
DateTime _firstDate = DateTime.now().subtract(Duration(days: 45));
DateTime _lastDate = DateTime.now().add(Duration(days: 45));
DatePeriod? _selectedPeriod;
Color selectedPeriodStartColor = Colors.blue;
Color selectedPeriodLastColor = Colors.blue;
Color selectedPeriodMiddleColor = Colors.blue;
@override
void didChangeDependencies() {
super.didChangeDependencies();
// defaults for styles
selectedPeriodLastColor = Theme.of(context).accentColor;
selectedPeriodMiddleColor = Theme.of(context).accentColor;
selectedPeriodStartColor = Theme.of(context).accentColor;
}
@override
Widget build(BuildContext context) {
// add selected colors to default settings
DatePickerRangeStyles styles = DatePickerRangeStyles(
selectedPeriodLastDecoration: BoxDecoration(
color: selectedPeriodLastColor,
borderRadius: BorderRadius.only(
topRight: Radius.circular(10.0),
bottomRight: Radius.circular(10.0))),
selectedPeriodStartDecoration: BoxDecoration(
color: selectedPeriodStartColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0), bottomLeft: Radius.circular(10.0)),
),
selectedPeriodMiddleDecoration: BoxDecoration(
color: selectedPeriodMiddleColor, shape: BoxShape.rectangle),
);
return Flex(
direction: MediaQuery.of(context).orientation == Orientation.portrait
? Axis.vertical
: Axis.horizontal,
children: <Widget>[
Expanded(
child: WeekPicker(
selectedDate: _selectedDate,
onChanged: _onSelectedDateChanged,
firstDate: _firstDate,
lastDate: _lastDate,
datePickerStyles: styles,
onSelectionError: _onSelectionError,
selectableDayPredicate: _isSelectableCustom,
eventDecorationBuilder: _eventDecorationBuilder,
),
),
Container(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Selected date styles",
style: Theme.of(context).textTheme.subtitle1,
),
_stylesBlock(),
_selectedBlock()
],
),
),
),
],
);
}
// block witt color buttons insede
Widget _stylesBlock() => Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ColorSelectorBtn(
title: "Start",
color: selectedPeriodStartColor,
showDialogFunction: _showSelectedStartColorDialog),
SizedBox(
width: 12.0,
),
ColorSelectorBtn(
title: "Middle",
color: selectedPeriodMiddleColor,
showDialogFunction: _showSelectedMiddleColorDialog),
SizedBox(
width: 12.0,
),
ColorSelectorBtn(
title: "End",
color: selectedPeriodLastColor,
showDialogFunction: _showSelectedEndColorDialog),
],
),
);
// Block with information about selected date
// and boundaries of the selected period.
Widget _selectedBlock() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text("Selected: $_selectedDate"),
),
_selectedPeriod != null
? Column(children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 4.0),
child: Text("Selected period boundaries:"),
),
Text(_selectedPeriod!.start.toString()),
Text(_selectedPeriod!.end.toString()),
])
: Container()
],
);
// select background color for the first date of the selected period
void _showSelectedStartColorDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedPeriodStartColor,
));
if (newSelectedColor != null) {
setState(() {
selectedPeriodStartColor = newSelectedColor;
});
}
}
// select background color for the last date of the selected period
void _showSelectedEndColorDialog() async {
Color? newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedPeriodLastColor,
));
if (newSelectedColor != null) {
setState(() {
selectedPeriodLastColor = newSelectedColor;
});
}
}
// select background color for the middle dates of the selected period
void _showSelectedMiddleColorDialog() async {
Color newSelectedColor = await showDialog(
context: context,
builder: (_) => ColorPickerDialog(
selectedColor: selectedPeriodMiddleColor,
));
if (newSelectedColor != null) {
setState(() {
selectedPeriodMiddleColor = newSelectedColor;
});
}
}
void _onSelectedDateChanged(DatePeriod newPeriod) {
setState(() {
_selectedDate = newPeriod.start;
_selectedPeriod = newPeriod;
});
}
void _onSelectionError(Object e){
if (e is UnselectablePeriodException) print("catch error: $e");
}
// ignore: prefer_expression_function_bodies
bool _isSelectableCustom (DateTime day) {
// return day.weekday < 6;
return day.day != DateTime.now().add(Duration(days: 7)).day ;
}
EventDecoration? _eventDecorationBuilder(DateTime date) {
List<DateTime> eventsDates = widget.events
.map<DateTime>((Event e) => e.date)
.toList();
bool isEventDate = eventsDates.any((DateTime d) => date.year == d.year
&& date.month == d.month
&& d.day == date.day);
if (!isEventDate) return null;
BoxDecoration roundedBorder = BoxDecoration(
color: Colors.blue,
border: Border.all(
color: Colors.blue,
),
borderRadius: BorderRadius.all(Radius.circular(3.0))
);
TextStyle? whiteText = Theme.of(context)
.textTheme
.bodyText2
?.copyWith(color: Colors.white);
return isEventDate
? EventDecoration(boxDecoration: roundedBorder, textStyle: whiteText)
: null;
}
}

View File

@@ -0,0 +1,14 @@
/// Event for the date pickers.
class Event {
/// Event's date.
final DateTime date;
/// Event's title.
final String dis;
///
Event(this.date, this.dis)
: assert(date != null),
assert(dis != null);
}

View File

@@ -0,0 +1,121 @@
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'date_pickers_widgets/day_picker_page.dart';
import 'date_pickers_widgets/days_picker_page.dart';
import 'date_pickers_widgets/month_picker_page.dart';
import 'date_pickers_widgets/range_picker_page.dart';
import 'date_pickers_widgets/week_picker_page.dart';
import 'event.dart';
void main() {
runApp(MyApp());
}
///
class MyApp extends StatelessWidget {
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: GlobalMaterialLocalizations.delegates,
supportedLocales: [
const Locale('en', 'US'), // American English
const Locale('ru', 'RU'), // Russian
const Locale("pt") // Portuguese
],
debugShowCheckedModeBanner: false,
title: 'Date pickers demo',
theme: ThemeData(
primarySwatch: Colors.blueGrey,
),
home: MyHomePage(
title: 'flutter_date_pickers Demo',
),
);
}
}
/// Start page.
class MyHomePage extends StatefulWidget {
/// Page title.
final String title;
///
MyHomePage({
required this.title,
Key? key,
}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
DateTime startOfPeriod = DateTime.now().subtract(Duration(days: 10));
DateTime endOfPeriod = DateTime.now().add(Duration(days: 10));
int _selectedTab = 0;
final List<Widget> datePickers = <Widget>[
DayPickerPage(events: events,),
DaysPickerPage(),
WeekPickerPage(events: events,),
RangePickerPage(events: events,),
MonthPickerPage()
];
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(letterSpacing: 1.15),
),
),
body: datePickers[_selectedTab],
bottomNavigationBar: Theme(
data: Theme.of(context).copyWith(
canvasColor: Colors.blueGrey,
textTheme: Theme.of(context).textTheme.copyWith(
caption: TextStyle(color: Colors.white.withOpacity(0.5)))),
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.date_range), label: "Day"),
BottomNavigationBarItem(
icon: Icon(Icons.date_range), label: "Days"),
BottomNavigationBarItem(
icon: Icon(Icons.date_range), label: "Week"),
BottomNavigationBarItem(
icon: Icon(Icons.date_range), label: "Range"),
BottomNavigationBarItem(
icon: Icon(Icons.date_range), label: "Month"),
],
fixedColor: Colors.yellow,
currentIndex: _selectedTab,
onTap: (newIndex) {
setState(() {
_selectedTab = newIndex;
});
},
),
),
);
}
}
/// Mock events.
final List<Event> events = [
Event(DateTime.now(), "Today event"),
Event(DateTime.now().subtract(Duration(days: 3)), "Ev1"),
Event(DateTime.now().subtract(Duration(days: 13)), "Ev2"),
Event(DateTime.now().subtract(Duration(days: 30)), "Ev3"),
Event(DateTime.now().add(Duration(days: 3)), "Ev4"),
Event(DateTime.now().add(Duration(days: 13)), "Ev5"),
Event(DateTime.now().add(Duration(days: 30)), "Ev6"),
];