added date constraints to overlay date time picker

This commit is contained in:
Brighton van den End 2022-11-18 15:57:03 +01:00
parent 3edcbe4b5a
commit 66e0090597
15 changed files with 538 additions and 118 deletions

View file

@ -1,22 +1,35 @@
<!-- <!--
This README describes the package. If you publish this package to pub.dev, This README describes the package. If you publish this package to pub.dev,
this README's contents appear on the landing page for your package. this README's contents appear on the landing page for your package.
For information about how to write a good package README, see the guide for For information about how to write a good package README, see the guide for
[writing package pages](https://dart.dev/guides/libraries/writing-package-pages). [writing package pages](https://dart.dev/guides/libraries/writing-package-pages).
For general information about developing packages, see the Dart guide for For general information about developing packages, see the Dart guide for
[creating packages](https://dart.dev/guides/libraries/create-library-packages) [creating packages](https://dart.dev/guides/libraries/create-library-packages)
and the Flutter guide for and the Flutter guide for
[developing packages and plugins](https://flutter.dev/developing-packages). [developing packages and plugins](https://flutter.dev/developing-packages).
--> -->
TODO: Put a short description of the package here that helps potential users # Date Time Picker
know whether this package might be useful for them.
The date time picker to be able to input a date.
## Features ## Features
TODO: List what your package can do. Maybe include images, gifs, or videos. ### Drag down date time picker
A picker that is placed in the top of the screen.
You are able to select a day at this point.
When it is dragged down you are able to select a day for a given month.
### Overlay date time picker
A picker, that when opened using a button, is placed over the screen.
Then you are able to swipe through the month to select a day.
It is possible to add a constraint to de picker to limit the choice of day.
![Overlay date time picker GIF](overlay_date_time_picker.gif)
## Getting started ## Getting started
@ -25,15 +38,24 @@ start using the package.
## Usage ## Usage
TODO: Include short and useful examples for package users. Add longer examples
to `/example` folder.
```dart ```dart
const like = 'sample'; OverlayDateTimePicker(
alignment: Alignment.bottomCenter,
child: const Text("Select Day"),
onTapDay: (date) {},
),
``` ```
## Additional information See the [Example Code](example/lib/main.dart) for more example's on how to use this package.
TODO: Tell users more about the package: where to find more information, how to ## Issues
contribute to the package, how to file issues, what response they can expect
from the package authors, and more. Please file any issues, bugs or feature request as an issue on our [GitHub](https://github.com/Iconica-Development/flutter_date_time_picker/pulls) page. Commercial support is available if you need help with integration with your app or services. You can contact us at [support@iconica.nl](mailto:support@iconica.nl).
## Want to contribute
If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our [contribution guide](../CONTRIBUTING.md) and send us your [pull request](https://github.com/Iconica-Development/flutter_date_time_picker/pulls).
## Author
This `flutter-date-time-picker` for Flutter is developed by [Iconica](https://iconica.nl). You can contact us at <support@iconica.nl>

View file

@ -1,16 +1,3 @@
# example # example
A new Flutter project. The example Flutter app for the date time picker
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

View file

@ -80,6 +80,9 @@ class DatePickerDemo extends StatelessWidget {
onPressed: onPressed, onPressed: onPressed,
child: const Text("Select Day"), child: const Text("Select Day"),
), ),
dateTimeConstraint: DateTimeConstraint(
min: DateConstraint(date: DateTime.now()),
),
), ),
OverlayDateTimePicker( OverlayDateTimePicker(
theme: dateTimePickerTheme, theme: dateTimePickerTheme,
@ -91,6 +94,18 @@ class DatePickerDemo extends StatelessWidget {
Icons.schedule, Icons.schedule,
), ),
), ),
dateTimeConstraint: DateTimeConstraint(
min: DateConstraint(date: DateTime.now()),
max: DateConstraint(
date: DateTime(
DateTime.now().year,
DateTime.now().month + 4,
DateTime.now().day,
),
),
),
onNextPageButtonChild: const Icon(Icons.add),
onPreviousPageButtonChild: const Icon(Icons.minimize),
) )
], ],
), ),

View file

@ -61,7 +61,7 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "0.0.1" version: "2.0.0"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:

View file

@ -6,6 +6,7 @@ library flutter_date_time_picker;
export 'src/drag_down_date_time_picker.dart' show DragDownDateTimePicker; export 'src/drag_down_date_time_picker.dart' show DragDownDateTimePicker;
export 'src/overlay_date_time_picker.dart' show OverlayDateTimePicker; export 'src/overlay_date_time_picker.dart' show OverlayDateTimePicker;
export 'src/models/date_constraint.dart';
export 'src/enums/date_box_shape.dart'; export 'src/enums/date_box_shape.dart';
export 'src/models/date_box_base_theme.dart'; export 'src/models/date_box_base_theme.dart';
export 'src/models/date_box_disabled_theme.dart'; export 'src/models/date_box_disabled_theme.dart';

View file

@ -0,0 +1,107 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
class DateTimeConstraint {
final DateConstraint min;
final DateConstraint max;
const DateTimeConstraint({
this.min = DateConstraint.infinity,
this.max = DateConstraint.infinity,
});
bool inRange(DateTime date) {
return _checkDate(
min,
() => !date.isBefore(min.date!),
) &&
_checkDate(
max,
() => !date.isAfter(max.date!),
);
}
bool inDateRange(DateTime date) {
return _checkDate(
min,
() => !_stripToDateOnly(date).isBefore(_stripToDateOnly(min.date!)),
) &&
_checkDate(
max,
() => !_stripToDateOnly(date).isAfter(_stripToDateOnly(max.date!)),
);
}
bool inMonthRange(DateTime date) {
return _checkDate(
min,
() =>
!_stripToMonthsOnly(date).isBefore(_stripToMonthsOnly(min.date!)),
) &&
_checkDate(
max,
() =>
!_stripToMonthsOnly(date).isAfter(_stripToMonthsOnly(max.date!)),
);
}
bool inYearRange(DateTime date) {
return _checkDate(
min,
() => !_stripToYearsOnly(date).isBefore(_stripToYearsOnly(min.date!)),
) &&
_checkDate(
max,
() => !_stripToYearsOnly(date).isAfter(_stripToYearsOnly(max.date!)),
);
}
DateTime _stripToDateOnly(DateTime date) {
return DateTime(
date.year,
date.month,
date.day,
);
}
DateTime _stripToMonthsOnly(DateTime date) {
return DateTime(
date.year,
date.month,
1,
);
}
DateTime _stripToYearsOnly(DateTime date) {
return DateTime(
date.year,
1,
1,
);
}
bool _checkDate(DateConstraint constraint, bool Function() checker) {
if (!constraint.isInfinite) {
return checker();
}
return constraint.isInfinite;
}
}
class DateConstraint {
static const DateConstraint infinity =
DateConstraint(date: null, isInfinite: true);
final DateTime? date;
final bool isInfinite;
const DateConstraint({this.date, this.isInfinite = false})
: assert(
!(date != null && isInfinite),
'Can NOT have a limit set and be infinite.',
),
assert(
date != null || isInfinite,
'Must set some form of a limit.',
);
}

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class DateTimePickerBarTheme { class DateTimePickerBarTheme {

View file

@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_date_time_picker/src/extensions/date_time.dart'; import 'package:flutter_date_time_picker/src/extensions/date_time.dart';
import 'package:flutter_date_time_picker/src/models/date_time_picker_theme.dart'; import 'package:flutter_date_time_picker/src/models/date_time_picker_theme.dart';
import 'package:flutter_date_time_picker/src/utils/date_time_picker_controller.dart'; import 'package:flutter_date_time_picker/src/utils/date_time_picker_controller.dart';
import 'package:flutter_date_time_picker/src/models/date_constraint.dart';
import 'package:flutter_date_time_picker/src/widgets/overlay_date_time_picker/overlay.dart'; import 'package:flutter_date_time_picker/src/widgets/overlay_date_time_picker/overlay.dart';
class OverlayDateTimePicker extends StatefulWidget { class OverlayDateTimePicker extends StatefulWidget {
@ -14,8 +15,7 @@ class OverlayDateTimePicker extends StatefulWidget {
this.textStyle = const TextStyle(), this.textStyle = const TextStyle(),
this.alignment = Alignment.bottomRight, this.alignment = Alignment.bottomRight,
this.initialDate, this.initialDate,
this.size = const Size(325, 350), this.size = const Size(325, 375),
this.wrongTimeDialog,
this.onTapDay, this.onTapDay,
this.highlightToday = true, this.highlightToday = true,
this.alwaysUse24HourFormat = true, this.alwaysUse24HourFormat = true,
@ -28,14 +28,14 @@ class OverlayDateTimePicker extends StatefulWidget {
this.buttonBuilder, this.buttonBuilder,
this.closeOnSelectDate = true, this.closeOnSelectDate = true,
this.showWeekDays = true, this.showWeekDays = true,
this.dateTimeConstraint = const DateTimeConstraint(),
this.onNextPageButtonChild,
this.onPreviousPageButtonChild,
}) : assert(child != null || buttonBuilder != null); }) : assert(child != null || buttonBuilder != null);
/// The child contained by the DatePicker. /// The child contained by the DatePicker.
final Widget? child; final Widget? child;
/// A [Widget] to display when the user picks a disabled time in the [TimePickerDialog]
final Widget? wrongTimeDialog;
/// Visual properties for the [OverlayDateTimePicker] /// Visual properties for the [OverlayDateTimePicker]
final DateTimePickerTheme theme; final DateTimePickerTheme theme;
@ -51,13 +51,13 @@ class OverlayDateTimePicker extends StatefulWidget {
/// a [bool] to set de clock on [TimePickerDialog] to a fixed 24 or 12-hour format. /// a [bool] to set de clock on [TimePickerDialog] to a fixed 24 or 12-hour format.
final bool alwaysUse24HourFormat; final bool alwaysUse24HourFormat;
/// [pickTime] is a [bool] that determines if the user is able to pick a time after picking a date using the [TimePickerDialog]. /// is a [bool] that determines if the user is able to pick a time after picking a date using the [TimePickerDialog].
final bool pickTime; final bool pickTime;
/// indicates the starting date. Default is [DateTime.now()] /// indicates the starting date. Default is [DateTime.now()]
final DateTime? initialDate; final DateTime? initialDate;
/// [markedDates] contain the dates [DateTime] that will be marked in the [OverlayDateTimePicker] by a small dot. /// contain the dates [DateTime] that will be marked in the [OverlayDateTimePicker] by a small dot.
final List<DateTime>? markedDates; final List<DateTime>? markedDates;
/// a [List] of [DateTime] objects that will be disabled and cannot be interacted with whatsoever. /// a [List] of [DateTime] objects that will be disabled and cannot be interacted with whatsoever.
@ -75,12 +75,21 @@ class OverlayDateTimePicker extends StatefulWidget {
/// [buttonBuilder] is a method for building the button that can trigger the overlay to appear /// [buttonBuilder] is a method for building the button that can trigger the overlay to appear
final Widget Function(Key key, void Function() onPressed)? buttonBuilder; final Widget Function(Key key, void Function() onPressed)? buttonBuilder;
/// [closeOnSelectDate] is a bool that indicates if the overlay should be closed if a date has been picked. /// is a [bool] that indicates if the overlay should be closed if a date has been picked.
final bool closeOnSelectDate; final bool closeOnSelectDate;
/// [showWeekDays] is a [bool] that determines if day in the week indicators should be shown /// [showWeekDays] is a [bool] that determines if day in the week indicators should be shown
final bool showWeekDays; final bool showWeekDays;
/// a [DateTimeConstraint] that dictates the constraints of the dates that can be picked.
final DateTimeConstraint dateTimeConstraint;
/// a [Widget] that determents the icon of the button for going to the next page
final Widget? onNextPageButtonChild;
/// a [Widget] that determents the icon of the button for going to the previous page
final Widget? onPreviousPageButtonChild;
@override @override
State<OverlayDateTimePicker> createState() => _OverlayDateTimePickerState(); State<OverlayDateTimePicker> createState() => _OverlayDateTimePickerState();
} }
@ -222,6 +231,9 @@ class _OverlayDateTimePickerState extends State<OverlayDateTimePicker> {
showWeekDays: true, showWeekDays: true,
onNextDate: nextDate, onNextDate: nextDate,
onPreviousDate: previousDate, onPreviousDate: previousDate,
dateTimeConstraint: widget.dateTimeConstraint,
onNextPageButtonChild: widget.onNextPageButtonChild,
onPreviousPageButtonChild: widget.onPreviousPageButtonChild,
), ),
), ),
), ),

View file

@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
class LockingPageScrollPhysics extends ScrollPhysics {
final bool Function() allowedNextPage;
final bool Function() allowedPreviousPage;
const LockingPageScrollPhysics({
required this.allowedNextPage,
required this.allowedPreviousPage,
ScrollPhysics? parent,
}) : super(parent: parent);
@override
ScrollPhysics applyTo(ScrollPhysics? ancestor) {
return LockingPageScrollPhysics(
allowedNextPage: allowedNextPage,
allowedPreviousPage: allowedPreviousPage,
parent: buildParent(ancestor));
}
@override
double applyBoundaryConditions(ScrollMetrics position, double value) {
bool movingLeft = value > position.pixels;
if (movingLeft && allowedNextPage()) {
return super.applyBoundaryConditions(position, value);
}
if (!movingLeft && allowedPreviousPage()) {
return super.applyBoundaryConditions(position, value);
}
return value - position.pixels;
}
}

View file

@ -18,6 +18,7 @@ class DatePicker extends StatelessWidget {
required this.onSelectDate, required this.onSelectDate,
required this.date, required this.date,
required this.showWeekDays, required this.showWeekDays,
required this.dateTimeConstraint,
}); });
final DateTimePickerController controller; final DateTimePickerController controller;
@ -26,6 +27,7 @@ class DatePicker extends StatelessWidget {
final void Function(DateTime date) onSelectDate; final void Function(DateTime date) onSelectDate;
final DateTime date; final DateTime date;
final bool showWeekDays; final bool showWeekDays;
final DateTimeConstraint dateTimeConstraint;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -85,7 +87,8 @@ class DatePicker extends StatelessWidget {
padding: const EdgeInsets.all(2.0), padding: const EdgeInsets.all(2.0),
child: PickableDate( child: PickableDate(
isOffMonth: date.month != todayDate.month, isOffMonth: date.month != todayDate.month,
isDisabled: isDisabled(addedIndex + index, daysToSkip), isDisabled:
isDisabled(addedIndex + index, daysToSkip, todayDate),
isSelected: controller.selectedDate == todayDate, isSelected: controller.selectedDate == todayDate,
isToday: isToday(todayDate) && controller.highlightToday, isToday: isToday(todayDate) && controller.highlightToday,
theme: theme, theme: theme,
@ -108,13 +111,14 @@ class DatePicker extends StatelessWidget {
date.day == now.day; date.day == now.day;
} }
bool isDisabled(int index, int daysToSkip) { bool isDisabled(int index, int daysToSkip, DateTime date) {
return DateTime( return DateTime(
date.year, date.year,
date.month, date.month,
index + 1 - daysToSkip, index + 1 - daysToSkip,
).containsAny( ).containsAny(
controller.disabledDates ?? [], controller.disabledDates ?? [],
); ) ||
!dateTimeConstraint.inRange(date);
} }
} }

View file

@ -5,7 +5,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_date_time_picker/src/models/date_time_picker_theme.dart'; import 'package:flutter_date_time_picker/src/models/date_time_picker_theme.dart';
import 'package:flutter_date_time_picker/src/utils/date_time_picker_controller.dart'; import 'package:flutter_date_time_picker/src/utils/date_time_picker_controller.dart';
import 'package:flutter_date_time_picker/src/utils/locking_page_scroll_physics.dart';
import 'package:flutter_date_time_picker/src/widgets/overlay_date_time_picker/date_picker.dart'; import 'package:flutter_date_time_picker/src/widgets/overlay_date_time_picker/date_picker.dart';
import 'package:flutter_date_time_picker/src/models/date_constraint.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
class OverlayDateTimeContent extends StatefulWidget { class OverlayDateTimeContent extends StatefulWidget {
@ -18,6 +20,9 @@ class OverlayDateTimeContent extends StatefulWidget {
required this.showWeekDays, required this.showWeekDays,
required this.onNextDate, required this.onNextDate,
required this.onPreviousDate, required this.onPreviousDate,
required this.dateTimeConstraint,
required this.onPreviousPageButtonChild,
required this.onNextPageButtonChild,
}); });
final DateTimePickerTheme theme; final DateTimePickerTheme theme;
@ -25,6 +30,11 @@ class OverlayDateTimeContent extends StatefulWidget {
final Size size; final Size size;
final DateTimePickerController controller; final DateTimePickerController controller;
final bool showWeekDays; final bool showWeekDays;
final DateTimeConstraint dateTimeConstraint;
final Widget? onNextPageButtonChild;
final Widget? onPreviousPageButtonChild;
final void Function() onNextDate; final void Function() onNextDate;
final void Function() onPreviousDate; final void Function() onPreviousDate;
@ -34,10 +44,22 @@ class OverlayDateTimeContent extends StatefulWidget {
class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> { class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
bool usesButtons = false; bool usesButtons = false;
late DateTime nextDate;
late DateTime previousDate;
late final PageController _pageController; late final PageController _pageController;
@override @override
void initState() { void initState() {
_pageController = PageController(initialPage: 1); _pageController = PageController(initialPage: 1);
nextDate = DateTime(
widget.controller.browsingDate.year,
widget.controller.browsingDate.month + 1,
1,
);
previousDate = DateTime(
widget.controller.browsingDate.year,
widget.controller.browsingDate.month - 1,
1,
);
super.initState(); super.initState();
} }
@ -56,16 +78,25 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
IconButton( IconButton(
onPressed: goToPreviousPage, onPressed: (widget.dateTimeConstraint.inMonthRange(previousDate))
icon: const Icon(Icons.arrow_circle_left_outlined), ? _goToPreviousPage
: null,
icon: widget.onPreviousPageButtonChild ??
const Icon(Icons.arrow_circle_left_outlined),
color: widget.theme.barTheme.barColor, color: widget.theme.barTheme.barColor,
), ),
Text(DateFormat.yMMMM().format( Text(
widget.controller.browsingDate, DateFormat.yMMMM().format(
)), widget.controller.browsingDate,
),
style: widget.theme.baseTheme.textStyle,
),
IconButton( IconButton(
onPressed: goToNextPage, onPressed: (widget.dateTimeConstraint.inMonthRange(nextDate))
icon: const Icon(Icons.arrow_circle_right_outlined), ? _goToNextPage
: null,
icon: widget.onNextPageButtonChild ??
const Icon(Icons.arrow_circle_right_outlined),
color: widget.theme.barTheme.barColor, color: widget.theme.barTheme.barColor,
), ),
], ],
@ -78,9 +109,15 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
), ),
Expanded( Expanded(
child: PageView( child: PageView(
physics: LockingPageScrollPhysics(
allowedNextPage: () =>
widget.dateTimeConstraint.inMonthRange(nextDate),
allowedPreviousPage: () =>
widget.dateTimeConstraint.inMonthRange(previousDate),
),
controller: _pageController, controller: _pageController,
onPageChanged: (value) { onPageChanged: (value) {
if (!usesButtons) movePage(1 - value); if (!usesButtons) _movePage(1 - value);
}, },
pageSnapping: true, pageSnapping: true,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
@ -88,34 +125,29 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
children: [ children: [
DatePicker( DatePicker(
controller: widget.controller, controller: widget.controller,
onSelectDate: onSelectDate, onSelectDate: _onSelectDate,
theme: widget.theme, theme: widget.theme,
textStyle: widget.textStyle, textStyle: widget.textStyle,
date: DateTime( date: previousDate,
widget.controller.browsingDate.year, dateTimeConstraint: widget.dateTimeConstraint,
widget.controller.browsingDate.month - 1,
1,
),
showWeekDays: widget.showWeekDays, showWeekDays: widget.showWeekDays,
), ),
DatePicker( DatePicker(
controller: widget.controller, controller: widget.controller,
onSelectDate: onSelectDate, onSelectDate: _onSelectDate,
theme: widget.theme, theme: widget.theme,
textStyle: widget.textStyle, textStyle: widget.textStyle,
date: widget.controller.browsingDate, date: widget.controller.browsingDate,
showWeekDays: widget.showWeekDays, showWeekDays: widget.showWeekDays,
dateTimeConstraint: widget.dateTimeConstraint,
), ),
DatePicker( DatePicker(
controller: widget.controller, controller: widget.controller,
onSelectDate: onSelectDate, onSelectDate: _onSelectDate,
theme: widget.theme, theme: widget.theme,
textStyle: widget.textStyle, textStyle: widget.textStyle,
date: DateTime( date: nextDate,
widget.controller.browsingDate.year, dateTimeConstraint: widget.dateTimeConstraint,
widget.controller.browsingDate.month + 1,
1,
),
showWeekDays: widget.showWeekDays, showWeekDays: widget.showWeekDays,
), ),
], ],
@ -125,7 +157,7 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
); );
} }
void goToNextPage() async { void _goToNextPage() async {
setState(() { setState(() {
usesButtons = true; usesButtons = true;
}); });
@ -133,10 +165,10 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut, curve: Curves.easeInOut,
); );
nextPage(); _nextPage();
} }
void goToPreviousPage() async { void _goToPreviousPage() async {
setState(() { setState(() {
usesButtons = true; usesButtons = true;
}); });
@ -144,41 +176,59 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut, curve: Curves.easeInOut,
); );
previousPage(); _previousPage();
} }
void nextPage() { void _nextPage() {
widget.onNextDate.call(); widget.onNextDate.call();
if (!mounted) return; if (!mounted) return;
_pageController.jumpToPage(1);
setState(() { setState(() {
usesButtons = false; usesButtons = false;
}); });
_pageController.jumpToPage(1); _setDates();
} }
void previousPage() { void _previousPage() {
widget.onPreviousDate.call(); widget.onPreviousDate.call();
if (!mounted) return; if (!mounted) return;
_pageController.jumpToPage(1);
setState(() { setState(() {
usesButtons = false; usesButtons = false;
}); });
_pageController.jumpToPage(1); _setDates();
} }
void movePage(int direction) { void _movePage(int direction) {
if (direction < 0) { if (direction < 0) {
nextPage(); _nextPage();
} else if (direction > 0) { } else if (direction > 0) {
previousPage(); _previousPage();
} }
} }
void onSelectDate(DateTime date) { void _onSelectDate(DateTime date) {
if (!mounted) return; if (!mounted) return;
setState(() { setState(() {
widget.controller.selectedDate = date; widget.controller.selectedDate = date;
movePage(widget.controller.browsingDate.month - date.month); _movePage(widget.controller.browsingDate.month - date.month);
widget.controller.onTapDayCallBack?.call(date); widget.controller.onTapDayCallBack?.call(date);
}); });
} }
void _setDates() {
if (!mounted) return;
setState(() {
nextDate = DateTime(
widget.controller.browsingDate.year,
widget.controller.browsingDate.month + 1,
1,
);
previousDate = DateTime(
widget.controller.browsingDate.year,
widget.controller.browsingDate.month - 1,
1,
);
});
}
} }

View file

@ -77,6 +77,6 @@ class PickableDate extends StatelessWidget {
TextStyle? getStyle(bool isToday, bool isSelected) { TextStyle? getStyle(bool isToday, bool isSelected) {
if (isToday) return theme.highlightTheme.textStyle; if (isToday) return theme.highlightTheme.textStyle;
if (isSelected) return theme.selectedTheme.textStyle; if (isSelected) return theme.selectedTheme.textStyle;
return null; return theme.baseTheme.textStyle;
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

View file

@ -1,6 +1,6 @@
name: flutter_date_time_picker name: flutter_date_time_picker
description: A new Flutter package project. description: A new Flutter package project.
version: 0.0.1 version: 2.0.0
homepage: https://iconica.nl/ homepage: https://iconica.nl/
environment: environment:
@ -16,40 +16,3 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages

View file

@ -0,0 +1,219 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter_date_time_picker/src/models/date_constraint.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('Date Range', () {
group('inRange()', () {
test(
'inRange() should return true when date is between min and max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 06, 01)),
max: DateConstraint(date: DateTime(2022, 07, 01)),
);
expect(range.inRange(DateTime(2022, 06, 20)), true);
expect(range.inRange(DateTime(2022, 07, 20)), false);
expect(range.inRange(DateTime(2022, 05, 20)), false);
});
test(
'inRange() should return true when date is between infinity and max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint.infinity,
max: DateConstraint(date: DateTime(2022, 07, 01)),
);
expect(range.inRange(DateTime(2022, 06, 20)), true);
expect(range.inRange(DateTime(2022, 07, 20)), false);
expect(range.inRange(DateTime(2022, 05, 20)), true);
});
test(
'inRange() should return true when date is between min and infinity otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 06, 01)),
max: DateConstraint.infinity,
);
expect(range.inRange(DateTime(2022, 06, 20)), true);
expect(range.inRange(DateTime(2022, 07, 20)), true);
expect(range.inRange(DateTime(2022, 05, 20)), false);
});
test('inRange() should return true when date is lower then max', () {
DateTimeConstraint range = DateTimeConstraint(
max: DateConstraint(date: DateTime(2022, 07, 01)),
);
expect(range.inRange(DateTime(2022, 06, 20)), true);
expect(range.inRange(DateTime(2022, 07, 20)), false);
expect(range.inRange(DateTime(2022, 05, 20)), true);
});
test('inRange() should return true when date is higher then min', () {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 06, 01)),
);
expect(range.inRange(DateTime(2022, 06, 20)), true);
expect(range.inRange(DateTime(2022, 07, 20)), true);
expect(range.inRange(DateTime(2022, 05, 20)), false);
});
test('inRange() should return true when date is equal to max', () {
DateTimeConstraint range = DateTimeConstraint(
max: DateConstraint(date: DateTime(2022, 06, 01)),
);
expect(range.inRange(DateTime(2022, 06, 01)), true);
expect(range.inRange(DateTime(2022, 05, 30)), true);
expect(range.inRange(DateTime(2022, 06, 02)), false);
});
test('inRange() should return true when date is equal to min', () {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 06, 01)),
);
expect(range.inRange(DateTime(2022, 06, 01)), true);
expect(range.inRange(DateTime(2022, 06, 02)), true);
expect(range.inRange(DateTime(2022, 05, 30)), false);
});
});
group('inYearRange()', () {
test(
'inYearRange() should return true when year is between min and max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 1, 1)),
max: DateConstraint(date: DateTime(2024, 1, 1)),
);
expect(range.inYearRange(DateTime(2023, 1, 1)), true);
expect(range.inYearRange(DateTime(2021, 1, 1)), false);
expect(range.inYearRange(DateTime(2025, 1, 1)), false);
});
test(
'inYearRange() should return true when year equals min or max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 1, 1)),
max: DateConstraint(date: DateTime(2023, 1, 1)),
);
expect(range.inYearRange(DateTime(2022, 1, 1)), true);
expect(range.inYearRange(DateTime(2023, 1, 1)), true);
expect(range.inYearRange(DateTime(2021, 1, 1)), false);
expect(range.inYearRange(DateTime(2024, 1, 1)), false);
});
test(
'inYearRange() should return true when year is between min and infinity otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 1, 1)),
);
expect(range.inYearRange(DateTime(2023, 1, 1)), true);
expect(range.inYearRange(DateTime(2025, 1, 1)), true);
expect(range.inYearRange(DateTime(2021, 1, 1)), false);
});
test(
'inYearRange() should return true when year is between infinity and max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
max: DateConstraint(date: DateTime(2024, 1, 1)),
);
expect(range.inYearRange(DateTime(2023, 1, 1)), true);
expect(range.inYearRange(DateTime(2021, 1, 1)), true);
expect(range.inYearRange(DateTime(2025, 1, 1)), false);
});
});
group('inMonthRange()', () {
test(
'inMonthRange() should return true when year is between min and max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 5, 1)),
max: DateConstraint(date: DateTime(2022, 7, 1)),
);
expect(range.inMonthRange(DateTime(2022, 6, 1)), true);
expect(range.inMonthRange(DateTime(2022, 3, 1)), false);
expect(range.inMonthRange(DateTime(2022, 8, 1)), false);
});
test(
'inMonthRange() should return true when year equals min or max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 5, 1)),
max: DateConstraint(date: DateTime(2022, 6, 1)),
);
expect(range.inMonthRange(DateTime(2022, 5, 1)), true);
expect(range.inMonthRange(DateTime(2022, 6, 1)), true);
expect(range.inMonthRange(DateTime(2022, 4, 1)), false);
expect(range.inMonthRange(DateTime(2022, 7, 1)), false);
});
test(
'inMonthRange() should return true when year is between min and infinity otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 5, 1)),
);
expect(range.inMonthRange(DateTime(2022, 6, 1)), true);
expect(range.inMonthRange(DateTime(2022, 8, 1)), true);
expect(range.inMonthRange(DateTime(2022, 3, 1)), false);
});
test(
'inMonthRange() should return true when year is between infinity and max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
max: DateConstraint(date: DateTime(2022, 7, 1)),
);
expect(range.inMonthRange(DateTime(2022, 6, 1)), true);
expect(range.inMonthRange(DateTime(2022, 3, 1)), true);
expect(range.inMonthRange(DateTime(2022, 8, 1)), false);
});
});
group('inDateRange()', () {
test(
'inDateRange() should return true when year is between min and max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 1, 4)),
max: DateConstraint(date: DateTime(2022, 1, 6)),
);
expect(range.inDateRange(DateTime(2022, 1, 5)), true);
expect(range.inDateRange(DateTime(2022, 1, 3)), false);
expect(range.inDateRange(DateTime(2022, 1, 7)), false);
});
test(
'inDateRange() should return true when year equals min or max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 1, 4)),
max: DateConstraint(date: DateTime(2022, 1, 5)),
);
expect(range.inDateRange(DateTime(2022, 1, 4)), true);
expect(range.inDateRange(DateTime(2022, 1, 5)), true);
expect(range.inDateRange(DateTime(2022, 1, 3)), false);
expect(range.inDateRange(DateTime(2022, 1, 6)), false);
});
test(
'inDateRange() should return true when year is between min and infinity otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
min: DateConstraint(date: DateTime(2022, 1, 4)),
);
expect(range.inDateRange(DateTime(2022, 1, 5)), true);
expect(range.inDateRange(DateTime(2022, 1, 7)), true);
expect(range.inDateRange(DateTime(2022, 1, 3)), false);
});
test(
'inDateRange() should return true when year is between infinity and max otherwise false',
() {
DateTimeConstraint range = DateTimeConstraint(
max: DateConstraint(date: DateTime(2022, 1, 6)),
);
expect(range.inDateRange(DateTime(2022, 1, 5)), true);
expect(range.inDateRange(DateTime(2022, 1, 3)), true);
expect(range.inDateRange(DateTime(2022, 1, 7)), false);
});
});
});
}