mirror of
https://github.com/Iconica-Development/flutter_date_time_picker.git
synced 2025-05-18 10:23:50 +02:00
added date constraints to overlay date time picker
This commit is contained in:
parent
3edcbe4b5a
commit
66e0090597
15 changed files with 538 additions and 118 deletions
50
README.md
50
README.md
|
@ -1,22 +1,35 @@
|
|||
<!--
|
||||
<!--
|
||||
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.
|
||||
|
||||
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
|
||||
[creating packages](https://dart.dev/guides/libraries/create-library-packages)
|
||||
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
|
||||
know whether this package might be useful for them.
|
||||
# Date Time Picker
|
||||
|
||||
The date time picker to be able to input a date.
|
||||
|
||||
## 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.
|
||||
|
||||

|
||||
|
||||
## Getting started
|
||||
|
||||
|
@ -25,15 +38,24 @@ start using the package.
|
|||
|
||||
## Usage
|
||||
|
||||
TODO: Include short and useful examples for package users. Add longer examples
|
||||
to `/example` folder.
|
||||
|
||||
```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
|
||||
contribute to the package, how to file issues, what response they can expect
|
||||
from the package authors, and more.
|
||||
## Issues
|
||||
|
||||
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>
|
||||
|
|
|
@ -1,16 +1,3 @@
|
|||
# example
|
||||
|
||||
A new Flutter project.
|
||||
|
||||
## 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.
|
||||
The example Flutter app for the date time picker
|
||||
|
|
|
@ -80,6 +80,9 @@ class DatePickerDemo extends StatelessWidget {
|
|||
onPressed: onPressed,
|
||||
child: const Text("Select Day"),
|
||||
),
|
||||
dateTimeConstraint: DateTimeConstraint(
|
||||
min: DateConstraint(date: DateTime.now()),
|
||||
),
|
||||
),
|
||||
OverlayDateTimePicker(
|
||||
theme: dateTimePickerTheme,
|
||||
|
@ -91,6 +94,18 @@ class DatePickerDemo extends StatelessWidget {
|
|||
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),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
@ -61,7 +61,7 @@ packages:
|
|||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
version: "2.0.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
|
|
@ -6,6 +6,7 @@ library flutter_date_time_picker;
|
|||
|
||||
export 'src/drag_down_date_time_picker.dart' show DragDownDateTimePicker;
|
||||
export 'src/overlay_date_time_picker.dart' show OverlayDateTimePicker;
|
||||
export 'src/models/date_constraint.dart';
|
||||
export 'src/enums/date_box_shape.dart';
|
||||
export 'src/models/date_box_base_theme.dart';
|
||||
export 'src/models/date_box_disabled_theme.dart';
|
||||
|
|
107
lib/src/models/date_constraint.dart
Normal file
107
lib/src/models/date_constraint.dart
Normal 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.',
|
||||
);
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
// SPDX-FileCopyrightText: 2022 Iconica
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DateTimePickerBarTheme {
|
||||
|
|
|
@ -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/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/models/date_constraint.dart';
|
||||
import 'package:flutter_date_time_picker/src/widgets/overlay_date_time_picker/overlay.dart';
|
||||
|
||||
class OverlayDateTimePicker extends StatefulWidget {
|
||||
|
@ -14,8 +15,7 @@ class OverlayDateTimePicker extends StatefulWidget {
|
|||
this.textStyle = const TextStyle(),
|
||||
this.alignment = Alignment.bottomRight,
|
||||
this.initialDate,
|
||||
this.size = const Size(325, 350),
|
||||
this.wrongTimeDialog,
|
||||
this.size = const Size(325, 375),
|
||||
this.onTapDay,
|
||||
this.highlightToday = true,
|
||||
this.alwaysUse24HourFormat = true,
|
||||
|
@ -28,14 +28,14 @@ class OverlayDateTimePicker extends StatefulWidget {
|
|||
this.buttonBuilder,
|
||||
this.closeOnSelectDate = true,
|
||||
this.showWeekDays = true,
|
||||
this.dateTimeConstraint = const DateTimeConstraint(),
|
||||
this.onNextPageButtonChild,
|
||||
this.onPreviousPageButtonChild,
|
||||
}) : assert(child != null || buttonBuilder != null);
|
||||
|
||||
/// The child contained by the DatePicker.
|
||||
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]
|
||||
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.
|
||||
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;
|
||||
|
||||
/// indicates the starting date. Default is [DateTime.now()]
|
||||
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;
|
||||
|
||||
/// 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
|
||||
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;
|
||||
|
||||
/// [showWeekDays] is a [bool] that determines if day in the week indicators should be shown
|
||||
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
|
||||
State<OverlayDateTimePicker> createState() => _OverlayDateTimePickerState();
|
||||
}
|
||||
|
@ -222,6 +231,9 @@ class _OverlayDateTimePickerState extends State<OverlayDateTimePicker> {
|
|||
showWeekDays: true,
|
||||
onNextDate: nextDate,
|
||||
onPreviousDate: previousDate,
|
||||
dateTimeConstraint: widget.dateTimeConstraint,
|
||||
onNextPageButtonChild: widget.onNextPageButtonChild,
|
||||
onPreviousPageButtonChild: widget.onPreviousPageButtonChild,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
36
lib/src/utils/locking_page_scroll_physics.dart
Normal file
36
lib/src/utils/locking_page_scroll_physics.dart
Normal 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;
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ class DatePicker extends StatelessWidget {
|
|||
required this.onSelectDate,
|
||||
required this.date,
|
||||
required this.showWeekDays,
|
||||
required this.dateTimeConstraint,
|
||||
});
|
||||
|
||||
final DateTimePickerController controller;
|
||||
|
@ -26,6 +27,7 @@ class DatePicker extends StatelessWidget {
|
|||
final void Function(DateTime date) onSelectDate;
|
||||
final DateTime date;
|
||||
final bool showWeekDays;
|
||||
final DateTimeConstraint dateTimeConstraint;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -85,7 +87,8 @@ class DatePicker extends StatelessWidget {
|
|||
padding: const EdgeInsets.all(2.0),
|
||||
child: PickableDate(
|
||||
isOffMonth: date.month != todayDate.month,
|
||||
isDisabled: isDisabled(addedIndex + index, daysToSkip),
|
||||
isDisabled:
|
||||
isDisabled(addedIndex + index, daysToSkip, todayDate),
|
||||
isSelected: controller.selectedDate == todayDate,
|
||||
isToday: isToday(todayDate) && controller.highlightToday,
|
||||
theme: theme,
|
||||
|
@ -108,13 +111,14 @@ class DatePicker extends StatelessWidget {
|
|||
date.day == now.day;
|
||||
}
|
||||
|
||||
bool isDisabled(int index, int daysToSkip) {
|
||||
bool isDisabled(int index, int daysToSkip, DateTime date) {
|
||||
return DateTime(
|
||||
date.year,
|
||||
date.month,
|
||||
index + 1 - daysToSkip,
|
||||
).containsAny(
|
||||
controller.disabledDates ?? [],
|
||||
);
|
||||
date.year,
|
||||
date.month,
|
||||
index + 1 - daysToSkip,
|
||||
).containsAny(
|
||||
controller.disabledDates ?? [],
|
||||
) ||
|
||||
!dateTimeConstraint.inRange(date);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
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/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/models/date_constraint.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class OverlayDateTimeContent extends StatefulWidget {
|
||||
|
@ -18,6 +20,9 @@ class OverlayDateTimeContent extends StatefulWidget {
|
|||
required this.showWeekDays,
|
||||
required this.onNextDate,
|
||||
required this.onPreviousDate,
|
||||
required this.dateTimeConstraint,
|
||||
required this.onPreviousPageButtonChild,
|
||||
required this.onNextPageButtonChild,
|
||||
});
|
||||
|
||||
final DateTimePickerTheme theme;
|
||||
|
@ -25,6 +30,11 @@ class OverlayDateTimeContent extends StatefulWidget {
|
|||
final Size size;
|
||||
final DateTimePickerController controller;
|
||||
final bool showWeekDays;
|
||||
final DateTimeConstraint dateTimeConstraint;
|
||||
|
||||
final Widget? onNextPageButtonChild;
|
||||
final Widget? onPreviousPageButtonChild;
|
||||
|
||||
final void Function() onNextDate;
|
||||
final void Function() onPreviousDate;
|
||||
|
||||
|
@ -34,10 +44,22 @@ class OverlayDateTimeContent extends StatefulWidget {
|
|||
|
||||
class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
|
||||
bool usesButtons = false;
|
||||
late DateTime nextDate;
|
||||
late DateTime previousDate;
|
||||
late final PageController _pageController;
|
||||
@override
|
||||
void initState() {
|
||||
_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();
|
||||
}
|
||||
|
||||
|
@ -56,16 +78,25 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: goToPreviousPage,
|
||||
icon: const Icon(Icons.arrow_circle_left_outlined),
|
||||
onPressed: (widget.dateTimeConstraint.inMonthRange(previousDate))
|
||||
? _goToPreviousPage
|
||||
: null,
|
||||
icon: widget.onPreviousPageButtonChild ??
|
||||
const Icon(Icons.arrow_circle_left_outlined),
|
||||
color: widget.theme.barTheme.barColor,
|
||||
),
|
||||
Text(DateFormat.yMMMM().format(
|
||||
widget.controller.browsingDate,
|
||||
)),
|
||||
Text(
|
||||
DateFormat.yMMMM().format(
|
||||
widget.controller.browsingDate,
|
||||
),
|
||||
style: widget.theme.baseTheme.textStyle,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: goToNextPage,
|
||||
icon: const Icon(Icons.arrow_circle_right_outlined),
|
||||
onPressed: (widget.dateTimeConstraint.inMonthRange(nextDate))
|
||||
? _goToNextPage
|
||||
: null,
|
||||
icon: widget.onNextPageButtonChild ??
|
||||
const Icon(Icons.arrow_circle_right_outlined),
|
||||
color: widget.theme.barTheme.barColor,
|
||||
),
|
||||
],
|
||||
|
@ -78,9 +109,15 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
|
|||
),
|
||||
Expanded(
|
||||
child: PageView(
|
||||
physics: LockingPageScrollPhysics(
|
||||
allowedNextPage: () =>
|
||||
widget.dateTimeConstraint.inMonthRange(nextDate),
|
||||
allowedPreviousPage: () =>
|
||||
widget.dateTimeConstraint.inMonthRange(previousDate),
|
||||
),
|
||||
controller: _pageController,
|
||||
onPageChanged: (value) {
|
||||
if (!usesButtons) movePage(1 - value);
|
||||
if (!usesButtons) _movePage(1 - value);
|
||||
},
|
||||
pageSnapping: true,
|
||||
scrollDirection: Axis.horizontal,
|
||||
|
@ -88,34 +125,29 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
|
|||
children: [
|
||||
DatePicker(
|
||||
controller: widget.controller,
|
||||
onSelectDate: onSelectDate,
|
||||
onSelectDate: _onSelectDate,
|
||||
theme: widget.theme,
|
||||
textStyle: widget.textStyle,
|
||||
date: DateTime(
|
||||
widget.controller.browsingDate.year,
|
||||
widget.controller.browsingDate.month - 1,
|
||||
1,
|
||||
),
|
||||
date: previousDate,
|
||||
dateTimeConstraint: widget.dateTimeConstraint,
|
||||
showWeekDays: widget.showWeekDays,
|
||||
),
|
||||
DatePicker(
|
||||
controller: widget.controller,
|
||||
onSelectDate: onSelectDate,
|
||||
onSelectDate: _onSelectDate,
|
||||
theme: widget.theme,
|
||||
textStyle: widget.textStyle,
|
||||
date: widget.controller.browsingDate,
|
||||
showWeekDays: widget.showWeekDays,
|
||||
dateTimeConstraint: widget.dateTimeConstraint,
|
||||
),
|
||||
DatePicker(
|
||||
controller: widget.controller,
|
||||
onSelectDate: onSelectDate,
|
||||
onSelectDate: _onSelectDate,
|
||||
theme: widget.theme,
|
||||
textStyle: widget.textStyle,
|
||||
date: DateTime(
|
||||
widget.controller.browsingDate.year,
|
||||
widget.controller.browsingDate.month + 1,
|
||||
1,
|
||||
),
|
||||
date: nextDate,
|
||||
dateTimeConstraint: widget.dateTimeConstraint,
|
||||
showWeekDays: widget.showWeekDays,
|
||||
),
|
||||
],
|
||||
|
@ -125,7 +157,7 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
|
|||
);
|
||||
}
|
||||
|
||||
void goToNextPage() async {
|
||||
void _goToNextPage() async {
|
||||
setState(() {
|
||||
usesButtons = true;
|
||||
});
|
||||
|
@ -133,10 +165,10 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
|
|||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
nextPage();
|
||||
_nextPage();
|
||||
}
|
||||
|
||||
void goToPreviousPage() async {
|
||||
void _goToPreviousPage() async {
|
||||
setState(() {
|
||||
usesButtons = true;
|
||||
});
|
||||
|
@ -144,41 +176,59 @@ class _OverlayDateTimeContentState extends State<OverlayDateTimeContent> {
|
|||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
previousPage();
|
||||
_previousPage();
|
||||
}
|
||||
|
||||
void nextPage() {
|
||||
void _nextPage() {
|
||||
widget.onNextDate.call();
|
||||
if (!mounted) return;
|
||||
_pageController.jumpToPage(1);
|
||||
setState(() {
|
||||
usesButtons = false;
|
||||
});
|
||||
_pageController.jumpToPage(1);
|
||||
_setDates();
|
||||
}
|
||||
|
||||
void previousPage() {
|
||||
void _previousPage() {
|
||||
widget.onPreviousDate.call();
|
||||
if (!mounted) return;
|
||||
_pageController.jumpToPage(1);
|
||||
setState(() {
|
||||
usesButtons = false;
|
||||
});
|
||||
_pageController.jumpToPage(1);
|
||||
_setDates();
|
||||
}
|
||||
|
||||
void movePage(int direction) {
|
||||
void _movePage(int direction) {
|
||||
if (direction < 0) {
|
||||
nextPage();
|
||||
_nextPage();
|
||||
} else if (direction > 0) {
|
||||
previousPage();
|
||||
_previousPage();
|
||||
}
|
||||
}
|
||||
|
||||
void onSelectDate(DateTime date) {
|
||||
void _onSelectDate(DateTime date) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
widget.controller.selectedDate = date;
|
||||
movePage(widget.controller.browsingDate.month - date.month);
|
||||
_movePage(widget.controller.browsingDate.month - date.month);
|
||||
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,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,6 @@ class PickableDate extends StatelessWidget {
|
|||
TextStyle? getStyle(bool isToday, bool isSelected) {
|
||||
if (isToday) return theme.highlightTheme.textStyle;
|
||||
if (isSelected) return theme.selectedTheme.textStyle;
|
||||
return null;
|
||||
return theme.baseTheme.textStyle;
|
||||
}
|
||||
}
|
||||
|
|
BIN
overlay_date_time_picker.gif
Normal file
BIN
overlay_date_time_picker.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 182 KiB |
39
pubspec.yaml
39
pubspec.yaml
|
@ -1,6 +1,6 @@
|
|||
name: flutter_date_time_picker
|
||||
description: A new Flutter package project.
|
||||
version: 0.0.1
|
||||
version: 2.0.0
|
||||
homepage: https://iconica.nl/
|
||||
|
||||
environment:
|
||||
|
@ -16,40 +16,3 @@ dev_dependencies:
|
|||
flutter_test:
|
||||
sdk: flutter
|
||||
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
|
||||
|
|
219
test/date_constraint_test.dart
Normal file
219
test/date_constraint_test.dart
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue