diff --git a/example/lib/main.dart b/example/lib/main.dart index 244c2d0..327e6c7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -16,13 +16,13 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', + title: 'Demo drag down date time picker', theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( appBar: AppBar( - title: const Text('Roster'), + title: const Text('Demo'), ), body: const DatePickerDemo(), ), @@ -34,32 +34,95 @@ class DatePickerDemo extends StatelessWidget { const DatePickerDemo({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return DateTimePicker( - dateTimePickerTheme: const DateTimePickerTheme( - backgroundColor: Colors.white, - markedIndicatorColor: Colors.red, - baseTheme: DateBoxBaseTheme( - Colors.white, - TextStyle(color: Colors.black), - ), - selectedTheme: DateBoxSelectedTheme( - Color(0x4BF44336), - TextStyle( - color: Colors.red, - ), - ), - highlightTheme: DateBoxHighlightTheme( - Colors.red, - TextStyle( - color: Colors.white, - ), - ), - barTheme: DateTimePickerBarTheme( - barColor: Colors.black, - barOpacity: 1, + const dateTimePickerTheme = DateTimePickerTheme( + dateBoxShape: DateBoxShape.roundedRectangle, + backgroundColor: Colors.white, + markedIndicatorColor: Colors.red, + baseTheme: DateBoxBaseTheme( + Colors.white, + TextStyle(color: Colors.black), + ), + selectedTheme: DateBoxSelectedTheme( + Color(0x4BF44336), + TextStyle( + color: Colors.red, ), ), - markedDates: [DateTime(2022, 9, 6)], + highlightTheme: DateBoxHighlightTheme( + Colors.red, + TextStyle( + color: Colors.white, + ), + ), + barTheme: DateTimePickerBarTheme( + barColor: Colors.black, + barOpacity: 1, + ), + ); + + return Stack( + children: [ + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + OverlayDateTimePicker( + theme: dateTimePickerTheme, + alignment: Alignment.bottomCenter, + child: const Text("Select Day"), + onTapDay: (date) {}, + ), + OverlayDateTimePicker( + theme: dateTimePickerTheme, + alignment: Alignment.center, + buttonBuilder: (key, onPressed) => TextButton( + key: key, + onPressed: onPressed, + child: const Text("Select Day"), + ), + ), + OverlayDateTimePicker( + theme: dateTimePickerTheme, + alignment: Alignment.topCenter, + buttonBuilder: (key, onPressed) => IconButton( + key: key, + onPressed: onPressed, + icon: const Icon( + Icons.schedule, + ), + ), + ) + ], + ), + ), + DragDownDateTimePicker( + dateTimePickerTheme: const DateTimePickerTheme( + backgroundColor: Colors.white, + markedIndicatorColor: Colors.red, + baseTheme: DateBoxBaseTheme( + Colors.white, + TextStyle(color: Colors.black), + ), + selectedTheme: DateBoxSelectedTheme( + Color(0x4BF44336), + TextStyle( + color: Colors.red, + ), + ), + highlightTheme: DateBoxHighlightTheme( + Colors.red, + TextStyle( + color: Colors.white, + ), + ), + barTheme: DateTimePickerBarTheme( + barColor: Colors.black, + barOpacity: 1, + ), + ), + markedDates: [DateTime(2022, 9, 6)], + ) + ], ); } } diff --git a/example/web/favicon.png b/example/web/favicon.png deleted file mode 100644 index 8aaa46a..0000000 Binary files a/example/web/favicon.png and /dev/null differ diff --git a/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfe..0000000 Binary files a/example/web/icons/Icon-192.png and /dev/null differ diff --git a/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48..0000000 Binary files a/example/web/icons/Icon-512.png and /dev/null differ diff --git a/example/web/icons/Icon-maskable-192.png b/example/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d7..0000000 Binary files a/example/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/example/web/icons/Icon-maskable-512.png b/example/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c566..0000000 Binary files a/example/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/example/web/index.html b/example/web/index.html deleted file mode 100644 index 41b3bc3..0000000 --- a/example/web/index.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - example - - - - - - - - - - diff --git a/example/web/manifest.json b/example/web/manifest.json deleted file mode 100644 index 096edf8..0000000 --- a/example/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "example", - "short_name": "example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/lib/flutter_date_time_picker.dart b/lib/flutter_date_time_picker.dart index b37e430..83adb30 100644 --- a/lib/flutter_date_time_picker.dart +++ b/lib/flutter_date_time_picker.dart @@ -4,7 +4,8 @@ library flutter_date_time_picker; -export 'src/date_time_picker.dart' show DateTimePicker; +export 'src/drag_down_date_time_picker.dart' show DragDownDateTimePicker; +export 'src/overlay_date_time_picker.dart' show OverlayDateTimePicker; export 'src/enums/date_box_shape.dart'; export 'src/models/date_box_base_theme.dart'; export 'src/models/date_box_disabled_theme.dart'; diff --git a/lib/src/date_time_picker.dart b/lib/src/drag_down_date_time_picker.dart similarity index 92% rename from lib/src/date_time_picker.dart rename to lib/src/drag_down_date_time_picker.dart index e857be6..12acfcc 100644 --- a/lib/src/date_time_picker.dart +++ b/lib/src/drag_down_date_time_picker.dart @@ -11,7 +11,7 @@ import 'package:flutter_date_time_picker/src/widgets/month_date_time_picker/mont import 'package:flutter_date_time_picker/src/widgets/week_date_time_picker/week_date_time_picker_sheet.dart'; import 'package:intl/date_symbol_data_local.dart'; -class DateTimePicker extends StatefulWidget { +class DragDownDateTimePicker extends StatefulWidget { /// A widget that displays a date picker from a sheet form the top of the screen. /// This sheet displays initially displays a week but can be dragged down to show a full month. /// Both views can be dragged sideways to show the next or previous week/month. @@ -37,7 +37,7 @@ class DateTimePicker extends StatefulWidget { /// child: ListBody( /// children: const [ /// Text( - /// 'The time you try to choose is diabled, try to pick another time.'), + /// 'The time you try to choose is disabled, try to pick another time.'), /// ], /// ), /// ), @@ -112,7 +112,7 @@ class DateTimePicker extends StatefulWidget { /// ), /// ), ///``` - DateTimePicker({ + DragDownDateTimePicker({ this.dateTimePickerTheme = const DateTimePickerTheme(), this.header, this.onTapDay, @@ -136,29 +136,29 @@ class DateTimePicker extends StatefulWidget { /// A [Widget] to display when the user picks a disabled time in the [TimePickerDialog] final Widget? wrongTimeDialog; - /// Visual properties for the [DateTimePicker] + /// Visual properties for the [DragDownDateTimePicker] final DateTimePickerTheme dateTimePickerTheme; - /// Widget shown at the top of the [DateTimePicker] + /// Widget shown at the top of the [DragDownDateTimePicker] final Widget? header; /// Callback that provides the date tapped on as a [DateTime] object. final Function(DateTime)? onTapDay; - /// Whether the current day should be highlighted in the [DateTimePicker] + /// Whether the current day should be highlighted in the [DragDownDateTimePicker] final bool highlightToday; /// a [bool] to set de clock on [TimePickerDialog] to a fixed 24 or 12-hour format. /// By default this gets determined by the [Locale] on the device. late final bool alwaysUse24HourFormat; - /// [pickTime] is a [bool] that determines if the user is able to pick a time after picking a date usring the [TimePickerDialog]. + /// [pickTime] 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 [DateTimePicker] by a small dot. + /// [markedDates] contain the dates [DateTime] that will be marked in the [DragDownDateTimePicker] by a small dot. final List? markedDates; /// a [List] of [DateTime] objects that will be disabled and cannot be interacted with whatsoever. @@ -168,10 +168,10 @@ class DateTimePicker extends StatefulWidget { final List? disabledTimes; @override - State createState() => _DateTimePickerState(); + State createState() => _DragDownDateTimePickerState(); } -class _DateTimePickerState extends State { +class _DragDownDateTimePickerState extends State { late DateTimePickerController _dateTimePickerController; final DraggableScrollableController _dragController = @@ -251,7 +251,9 @@ class _DateTimePickerState extends State { ), ], ), - child: dragSize < _dateTimePickerController.theme.weekMonthTriggerSize + child: dragSize < + _dateTimePickerController + .theme.weekMonthTriggerSize ? WeekDateTimePickerSheet( dateTimePickerController: _dateTimePickerController, diff --git a/lib/src/models/date_time_picker_theme.dart b/lib/src/models/date_time_picker_theme.dart index cebfa23..e573180 100644 --- a/lib/src/models/date_time_picker_theme.dart +++ b/lib/src/models/date_time_picker_theme.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_date_time_picker/flutter_date_time_picker.dart'; class DateTimePickerTheme { - /// The [DateTimePickerTheme] to style [DateTimePicker] in. Define a custom shape for the dates and specifically style + /// The [DateTimePickerTheme] to style [DragDownDateTimePicker] in. Define a custom shape for the dates and specifically style /// a basic, hightlighted, selected and disabled date. const DateTimePickerTheme({ this.weekDateBoxSize = 35, diff --git a/lib/src/overlay_date_time_picker.dart b/lib/src/overlay_date_time_picker.dart new file mode 100644 index 0000000..bb72c54 --- /dev/null +++ b/lib/src/overlay_date_time_picker.dart @@ -0,0 +1,250 @@ +// SPDX-FileCopyrightText: 2022 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +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/widgets/overlay_date_time_picker/overlay.dart'; + +class OverlayDateTimePicker extends StatefulWidget { + const OverlayDateTimePicker({ + this.theme = const DateTimePickerTheme(), + this.alignment = Alignment.bottomRight, + this.initialDate, + this.size = const Size(325, 325), + this.wrongTimeDialog, + this.onTapDay, + this.highlightToday = true, + this.alwaysUse24HourFormat = true, + this.pickTime = false, + this.markedDates, + this.disabledDates, + this.disabledTimes, + this.child, + super.key, + this.buttonBuilder, + this.closeOnSelectDate = true, + }) : 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; + + /// Callback that provides the date tapped on as a [DateTime] object. + final Function(DateTime date)? onTapDay; + + /// Whether the current day should be highlighted in the [OverlayDateTimePicker] + final bool highlightToday; + + /// 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]. + 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. + final List? markedDates; + + /// a [List] of [DateTime] objects that will be disabled and cannot be interacted with whatsoever. + final List? disabledDates; + + /// a [List] of [TimeOfDay] objects that cannot be picked in the [TimePickerDialog]. + final List? disabledTimes; + + /// an [Alignment] to align the overlay relative to the button + final Alignment alignment; + + /// a [Size] that indicates the size of the overlay + final Size size; + + /// [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. + final bool closeOnSelectDate; + + @override + State createState() => _OverlayDateTimePickerState(); +} + +class _OverlayDateTimePickerState extends State { + final GlobalKey buttonKey = GlobalKey( + debugLabel: "Overlay Date Time Picker - Button", + ); + + bool _isShown = false; + + late OverlayState? _overlayState; + + late final OverlayEntry _overlay = OverlayEntry( + builder: (context) { + var box = buttonKey.currentContext?.findRenderObject() as RenderBox; + var offset = _calculateOffset( + alignment: widget.alignment, + position: box.localToGlobal( + const Offset(0, 0), + ), + buttonSize: box.size, + overlaySize: widget.size, + ); + return Positioned( + top: offset.dy, + left: offset.dx, + child: Material( + child: _buildOverlay(context), + ), + ); + }, + ); + late final DateTimePickerController _dateTimePickerController = + DateTimePickerController( + highlightToday: widget.highlightToday, + alwaysUse24HourFormat: widget.alwaysUse24HourFormat, + pickTime: widget.pickTime, + theme: widget.theme, + markedDates: widget.markedDates, + disabledDates: widget.disabledDates, + disabledTimes: widget.disabledTimes, + onTapDayCallBack: (date) { + widget.onTapDay?.call(date); + if (widget.closeOnSelectDate) { + _toggleOverlay(); + } + }, + browsingDate: widget.initialDate ?? DateTime.now(), + selectedDate: widget.initialDate ?? DateTime.now(), + ); + + @override + void dispose() { + _overlay.dispose(); + _overlayState?.dispose(); + _dateTimePickerController.dispose(); + super.dispose(); + } + + void _toggleOverlay() { + if (mounted) { + setState(() { + if (!_isShown) { + _overlayState?.insert(_overlay); + } else { + _overlay.remove(); + } + _isShown = !_isShown; + }); + } + } + + Offset _calculateOffset({ + required Alignment alignment, + required Offset position, + required Size buttonSize, + required Size overlaySize, + }) { + double offsetX = 0; + double offsetY = 0; + + offsetX = position.dx + // adds the world x position of the button + buttonSize.width * + 0.5 - // centers the pivot of the button of the calculation to the center of the button + overlaySize.width * + 0.5 + // centers the pivot of the overlay of the calculation to the center of the overlay + (overlaySize.width + buttonSize.width) * 0.5 * alignment.x; + offsetY = position.dy + // adds the world y position of the button + buttonSize.height * 0.5 - + overlaySize.height * 0.5 + + (overlaySize.height + buttonSize.height) * 0.5 * alignment.y; + + return Offset(offsetX, offsetY); + } + + @override + Widget build(BuildContext context) { + _overlayState = Overlay.of(context); + + if (widget.buttonBuilder != null) { + return widget.buttonBuilder!.call( + buttonKey, + () { + _toggleOverlay(); + }, + ); + } + return ElevatedButton( + key: buttonKey, + onPressed: () { + _toggleOverlay(); + }, + child: widget.child); + } + + Widget _buildOverlay(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: widget.theme.backgroundColor, + borderRadius: const BorderRadius.all(Radius.circular(16)), + boxShadow: [ + BoxShadow( + blurRadius: 5, + color: Colors.black.withOpacity(0.25), + ), + ], + ), + child: SizedBox( + width: widget.size.width, + height: widget.size.height, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: OverlayDateTimeContent( + theme: widget.theme, + size: widget.size, + controller: _dateTimePickerController, + onNextDate: nextDate, + onPreviousDate: previousDate, + ), + ), + ), + ); + } + + void nextDate() { + if (!mounted) return; + setState(() { + _dateTimePickerController.browsingDate = + _dateTimePickerController.browsingDate.add( + Duration( + days: DateTime( + _dateTimePickerController.browsingDate.year, + _dateTimePickerController.browsingDate.month, + ).daysInMonth(), + ), + ); + }); + } + + void previousDate() { + if (!mounted) return; + setState(() { + _dateTimePickerController.browsingDate = + _dateTimePickerController.browsingDate.subtract( + Duration( + days: DateTime( + _dateTimePickerController.browsingDate.year, + _dateTimePickerController.browsingDate.month, + ).daysInMonth(), + ), + ); + }); + } +} diff --git a/lib/src/widgets/overlay_date_time_picker/date_picker.dart b/lib/src/widgets/overlay_date_time_picker/date_picker.dart new file mode 100644 index 0000000..042a15e --- /dev/null +++ b/lib/src/widgets/overlay_date_time_picker/date_picker.dart @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2022 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +import 'package:flutter/material.dart'; +import 'package:flutter_date_time_picker/flutter_date_time_picker.dart'; +import 'package:flutter_date_time_picker/src/extensions/date_time.dart'; +import 'package:flutter_date_time_picker/src/utils/date_time_picker_controller.dart'; +import 'package:flutter_date_time_picker/src/widgets/overlay_date_time_picker/pickable_date.dart'; + +class DatePicker extends StatelessWidget { + const DatePicker({ + super.key, + required this.controller, + required this.theme, + required this.onSelectDate, + required this.date, + }); + + final DateTimePickerController controller; + final DateTimePickerTheme theme; + final void Function(DateTime date) onSelectDate; + final DateTime date; + + @override + Widget build(BuildContext context) { + int daysToSkip = DateTime( + date.year, + date.month, + 0, + 12, + ).weekday; + + int addedIndex = 0; + + if (daysToSkip >= 7) { + addedIndex = 7; + } + + int length = DateTime(date.year, date.month).daysInMonth() + daysToSkip; + int daysToAdd = 7 - length % 7; + return GridView.count( + physics: const NeverScrollableScrollPhysics(), + crossAxisCount: 7, + children: List.generate( + length + daysToAdd, + (index) { + DateTime todayDate = DateTime( + date.year, + date.month, + addedIndex + index + 1 - daysToSkip, + ); + return Padding( + padding: const EdgeInsets.all(2.0), + child: PickableDate( + isOffMonth: date.month != todayDate.month, + isDisabled: isDisabled(addedIndex + index, daysToSkip), + isSelected: controller.selectedDate == todayDate, + isToday: isToday(todayDate) && controller.highlightToday, + theme: theme, + date: todayDate, + onPressed: onSelectDate, + ), + ); + }, + ), + ); + } + + bool isToday(DateTime date) { + DateTime now = DateTime.now(); + return date.year == now.year && + date.month == now.month && + date.day == now.day; + } + + bool isDisabled(int index, int daysToSkip) { + return DateTime( + date.year, + date.month, + index + 1 - daysToSkip, + ).containsAny( + controller.disabledDates ?? [], + ); + } +} diff --git a/lib/src/widgets/overlay_date_time_picker/overlay.dart b/lib/src/widgets/overlay_date_time_picker/overlay.dart new file mode 100644 index 0000000..ccb6f64 --- /dev/null +++ b/lib/src/widgets/overlay_date_time_picker/overlay.dart @@ -0,0 +1,174 @@ +// SPDX-FileCopyrightText: 2022 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +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/widgets/overlay_date_time_picker/date_picker.dart'; +import 'package:intl/intl.dart'; + +class OverlayDateTimeContent extends StatefulWidget { + const OverlayDateTimeContent({ + super.key, + required this.theme, + required this.size, + required this.controller, + required this.onNextDate, + required this.onPreviousDate, + }); + + final DateTimePickerTheme theme; + final Size size; + final DateTimePickerController controller; + final void Function() onNextDate; + final void Function() onPreviousDate; + + @override + State createState() => _OverlayDateTimeContentState(); +} + +class _OverlayDateTimeContentState extends State { + bool usesButtons = false; + late final PageController _pageController; + @override + void initState() { + _pageController = PageController(initialPage: 1); + super.initState(); + } + + @override + void dispose() { + _pageController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + onPressed: goToPreviousPage, + icon: const Icon(Icons.arrow_circle_left_outlined), + color: widget.theme.barTheme.barColor, + ), + Text(DateFormat.yMMMM().format( + widget.controller.browsingDate, + )), + IconButton( + onPressed: goToNextPage, + icon: const Icon(Icons.arrow_circle_right_outlined), + color: widget.theme.barTheme.barColor, + ), + ], + ), + Container( + height: 2, + decoration: BoxDecoration( + color: widget.theme.barTheme.barColor, + ), + ), + Expanded( + child: PageView( + controller: _pageController, + onPageChanged: (value) { + if (!usesButtons) movePage(1 - value); + }, + pageSnapping: true, + scrollDirection: Axis.horizontal, + allowImplicitScrolling: true, + children: [ + DatePicker( + controller: widget.controller, + onSelectDate: onSelectDate, + theme: widget.theme, + date: DateTime( + widget.controller.browsingDate.year, + widget.controller.browsingDate.month - 1, + 1, + ), + ), + DatePicker( + controller: widget.controller, + onSelectDate: onSelectDate, + theme: widget.theme, + date: widget.controller.browsingDate, + ), + DatePicker( + controller: widget.controller, + onSelectDate: onSelectDate, + theme: widget.theme, + date: DateTime( + widget.controller.browsingDate.year, + widget.controller.browsingDate.month + 1, + 1, + ), + ), + ], + ), + ) + ], + ); + } + + void goToNextPage() async { + setState(() { + usesButtons = true; + }); + await _pageController.nextPage( + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut, + ); + nextPage(); + } + + void goToPreviousPage() async { + setState(() { + usesButtons = true; + }); + await _pageController.previousPage( + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut, + ); + previousPage(); + } + + void nextPage() { + widget.onNextDate.call(); + if (!mounted) return; + setState(() { + usesButtons = false; + }); + _pageController.jumpToPage(1); + } + + void previousPage() { + widget.onPreviousDate.call(); + if (!mounted) return; + setState(() { + usesButtons = false; + }); + _pageController.jumpToPage(1); + } + + void movePage(int direction) { + if (direction < 0) { + nextPage(); + } else if (direction > 0) { + previousPage(); + } + } + + void onSelectDate(DateTime date) { + if (!mounted) return; + setState(() { + widget.controller.selectedDate = date; + movePage(widget.controller.browsingDate.month - date.month); + widget.controller.onTapDayCallBack?.call(date); + }); + } +} diff --git a/lib/src/widgets/overlay_date_time_picker/pickable_date.dart b/lib/src/widgets/overlay_date_time_picker/pickable_date.dart new file mode 100644 index 0000000..b2f40d8 --- /dev/null +++ b/lib/src/widgets/overlay_date_time_picker/pickable_date.dart @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: 2022 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +import 'package:flutter/material.dart'; +import 'package:flutter_date_time_picker/flutter_date_time_picker.dart'; + +class PickableDate extends StatelessWidget { + const PickableDate({ + super.key, + required this.isSelected, + required this.isDisabled, + required this.theme, + required this.onPressed, + required this.date, + required this.isOffMonth, + required this.isToday, + }); + + final bool isSelected; + final bool isDisabled; + final bool isToday; + final bool isOffMonth; + final DateTime date; + final DateTimePickerTheme theme; + final void Function(DateTime date) onPressed; + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + if (isDisabled) return; + onPressed.call(date); + }, + child: Container( + decoration: BoxDecoration( + color: getColor( + isToday, + isSelected, + ), + borderRadius: getBorder(theme.dateBoxShape), + ), + child: Center( + child: Opacity( + opacity: (isDisabled || isOffMonth) ? 0.5 : 1, + child: Text( + date.day.toString(), + style: getStyle( + isToday, + isSelected, + ), + ), + ), + ), + ), + ); + } + + BorderRadiusGeometry? getBorder(DateBoxShape shape) { + switch (shape) { + case DateBoxShape.circle: + return BorderRadius.all(Radius.circular(theme.monthDateBoxSize)); + case DateBoxShape.roundedRectangle: + return const BorderRadius.all(Radius.circular(10)); + case DateBoxShape.rectangle: + return null; + } + } + + Color? getColor(bool isToday, bool isSelected) { + if (isToday) return theme.highlightTheme.backgroundColor; + if (isSelected) return theme.selectedTheme.backgroundColor; + return null; + } + + TextStyle? getStyle(bool isToday, bool isSelected) { + if (isToday) return theme.highlightTheme.textStyle; + if (isSelected) return theme.selectedTheme.textStyle; + return null; + } +} diff --git a/test/flutter_date_time_picker_test.dart b/test/flutter_date_time_picker_test.dart index a55089c..8b9ef20 100644 --- a/test/flutter_date_time_picker_test.dart +++ b/test/flutter_date_time_picker_test.dart @@ -12,7 +12,7 @@ void main() { await tester.pumpWidget(MaterialApp( home: Scaffold( appBar: AppBar(), - body: DateTimePicker( + body: DragDownDateTimePicker( pickTime: false, child: Container(), ), @@ -26,7 +26,7 @@ void main() { await tester.pumpWidget(MaterialApp( home: Scaffold( appBar: AppBar(), - body: DateTimePicker( + body: DragDownDateTimePicker( pickTime: false, child: Container(), ),