diff --git a/README.md b/README.md index a1ec939..759d267 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ Flutter Date Picker Library that provides a calendar as a horizontal timeline.

+

+ +

+ ## How To Use Import the following package in your dart file @@ -31,6 +35,7 @@ Column( initialSelectedDate: DateTime.now(), selectionColor: Colors.black, selectedTextColor: Colors.white, + // timelineType: TimelineType.MONTH, onDateChange: (date) { // New date selected setState(() { @@ -45,8 +50,7 @@ Column( ##### Constructor: ```dart -DatePicker( - this.startDate, { +DatePicker(this.startDate, { Key key, this.width = 60, this.height = 80, @@ -54,13 +58,15 @@ DatePicker( this.monthTextStyle = defaultMonthTextStyle, this.dayTextStyle = defaultDayTextStyle, this.dateTextStyle = defaultDateTextStyle, + this.yearTextStyle = defaultYearTextStyle, this.selectedTextColor = Colors.white, this.selectionColor = AppColors.defaultSelectionColor, this.initialSelectedDate, this.daysCount = 500, this.onDateChange, this.locale = "en_US", -}) : super(key: key); + this.timelineType = TimelineType.DAY + }) : super(key: key); ``` Author diff --git a/example/lib/main.dart b/example/lib/main.dart index b35e193..64b7608 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -70,6 +70,7 @@ class _MyHomePageState extends State { initialSelectedDate: DateTime.now(), selectionColor: Colors.black, selectedTextColor: Colors.white, +// timelineType: TimelineType.MONTH, onDateChange: (date) { // New date selected setState(() { diff --git a/lib/date_picker_timeline.dart b/lib/date_picker_timeline.dart index dea4fb8..281af9e 100644 --- a/lib/date_picker_timeline.dart +++ b/lib/date_picker_timeline.dart @@ -1,3 +1,4 @@ library date_picker_timeline; export 'date_picker_widget.dart'; +export 'timelineType.dart'; diff --git a/lib/date_picker_widget.dart b/lib/date_picker_widget.dart index b6de39a..26ce6e3 100644 --- a/lib/date_picker_widget.dart +++ b/lib/date_picker_widget.dart @@ -2,6 +2,8 @@ import 'package:date_picker_timeline/date_widget.dart'; import 'package:date_picker_timeline/extra/color.dart'; import 'package:date_picker_timeline/extra/style.dart'; import 'package:date_picker_timeline/gestures/tap.dart'; +import 'package:date_picker_timeline/month_widget.dart'; +import 'package:date_picker_timeline/timelineType.dart'; import 'package:flutter/material.dart'; import 'package:intl/date_symbol_data_local.dart'; @@ -34,6 +36,9 @@ class DatePicker extends StatefulWidget { /// TextStyle for the date Value final TextStyle dateTextStyle; + /// TextStyle for the year Value + final TextStyle yearTextStyle; + /// Current Selected Date final DateTime initialSelectedDate; @@ -47,8 +52,12 @@ class DatePicker extends StatefulWidget { /// Locale for the calendar default: en_us final String locale; - DatePicker( - this.startDate, { + /// Setting the TimelineType + /// TimelineType.DAY & TimelineType.MONTH + /// Default is TimelineType.DAY + final TimelineType timelineType; + + DatePicker(this.startDate, { Key key, this.width = 60, this.height = 80, @@ -56,12 +65,14 @@ class DatePicker extends StatefulWidget { this.monthTextStyle = defaultMonthTextStyle, this.dayTextStyle = defaultDayTextStyle, this.dateTextStyle = defaultDateTextStyle, + this.yearTextStyle = defaultYearTextStyle, this.selectedTextColor = Colors.white, this.selectionColor = AppColors.defaultSelectionColor, this.initialSelectedDate, this.daysCount = 500, this.onDateChange, this.locale = "en_US", + this.timelineType = TimelineType.DAY }) : super(key: key); @override @@ -76,10 +87,16 @@ class _DatePickerState extends State { TextStyle selectedDateStyle; TextStyle selectedMonthStyle; TextStyle selectedDayStyle; + TextStyle selectedYearStyle; + //For Creation of month data + DateTime _monthStartDate; + int _monthDayCount; + List monthList; + // @override void initState() { - // Init the calendar locale + monthList = new List(); initializeDateFormatting(widget.locale, null); // Set initial Values _currentDate = widget.initialSelectedDate; @@ -91,7 +108,11 @@ class _DatePickerState extends State { this.selectedDateStyle = createTextStyle(widget.dateTextStyle); this.selectedMonthStyle = createTextStyle(widget.monthTextStyle); this.selectedDayStyle = createTextStyle(widget.dayTextStyle); - + this.selectedYearStyle = createTextStyle(widget.yearTextStyle); + WidgetsBinding.instance.addPostFrameCallback((_) async { + //Creating month data + await monthDataCreation(); + }); super.initState(); } @@ -111,9 +132,23 @@ class _DatePickerState extends State { } } + ///Creating month data on basis of daysCount parameter passed + ///Selected month will give First Day of the month on selected. + monthDataCreation() async { + _monthStartDate = widget.startDate; + _monthDayCount = 0; + setState(() { + while (_monthDayCount < widget.daysCount) { + monthList.add(DateTime(_monthStartDate.year, _monthStartDate.month, 01)); + _monthStartDate = _monthStartDate.add(Duration(days: 31)); + _monthDayCount++; + } + }); + } + @override Widget build(BuildContext context) { - return Container( + return widget.timelineType == TimelineType.DAY ? Container( height: widget.height, child: ListView.builder( itemCount: widget.daysCount, @@ -123,24 +158,57 @@ class _DatePickerState extends State { // get the date object based on the index position // if widget.startDate is null then use the initialDateValue DateTime date; - DateTime _date = widget.startDate.add(Duration(days: index)); - date = new DateTime(_date.year, _date.month, _date.day); + bool isSelected = false; - // Check if this date is the one that is currently selected - bool isSelected = _currentDate != null? _compareDate(date, _currentDate) : false; + if (widget.timelineType == TimelineType.DAY) { + DateTime _date = widget.startDate.add(Duration(days: index)); + date = new DateTime(_date.year, _date.month, _date.day); + // Check if this date is the one that is currently selected + isSelected = _compareDate(date, _currentDate); + } // Return the Date Widget return DateWidget( date: date, monthTextStyle: - isSelected ? selectedMonthStyle : widget.monthTextStyle, + isSelected ? selectedMonthStyle : widget.monthTextStyle, dateTextStyle: - isSelected ? selectedDateStyle : widget.dateTextStyle, + isSelected ? selectedDateStyle : widget.dateTextStyle, dayTextStyle: isSelected ? selectedDayStyle : widget.dayTextStyle, width: widget.width, locale: widget.locale, selectionColor: - isSelected ? widget.selectionColor : Colors.transparent, + isSelected ? widget.selectionColor : Colors.transparent, + onDateSelected: (selectedDate) { + // A date is selected + if (widget.onDateChange != null) { + widget.onDateChange(selectedDate); + } + setState(() { + _currentDate = selectedDate; + }); + }, + ); + }, + ), + ) : Container( + height: widget.height, + child: ListView.builder( + itemCount: monthList.length, + scrollDirection: Axis.horizontal, + controller: _controller, + itemBuilder: (context, index) { + bool isSelected = _compareMonth(monthList[index], _currentDate); + // Return the Date Widget + return MonthWidget( + date: monthList[index], + monthTextStyle: + isSelected ? selectedMonthStyle : widget.monthTextStyle, + yearTextStyle: isSelected ? selectedYearStyle : widget.yearTextStyle, + width: widget.width, + locale: widget.locale, + selectionColor: + isSelected ? widget.selectionColor : Colors.transparent, onDateSelected: (selectedDate) { // A date is selected if (widget.onDateChange != null) { @@ -163,6 +231,12 @@ class _DatePickerState extends State { date1.month == date2.month && date1.year == date2.year; } + + /// Helper function to compare two dates (month & year) + /// Returns True if both dates(month & year) are the same + bool _compareMonth(DateTime date1, DateTime date2) { + return date1.month == date2.month && date1.year == date2.year; + } } class DatePickerController { @@ -174,7 +248,7 @@ class DatePickerController { void jumpToSelection() { assert(_datePickerState != null, - 'DatePickerController is not attached to any DatePicker View.'); + 'DatePickerController is not attached to any DatePicker View.'); // jump to the current Date _datePickerState._controller @@ -185,7 +259,7 @@ class DatePickerController { void animateToSelection( {duration = const Duration(milliseconds: 500), curve = Curves.linear}) { assert(_datePickerState != null, - 'DatePickerController is not attached to any DatePicker View.'); + 'DatePickerController is not attached to any DatePicker View.'); // animate to the current date _datePickerState._controller.animateTo( @@ -199,7 +273,7 @@ class DatePickerController { void animateToDate(DateTime date, {duration = const Duration(milliseconds: 500), curve = Curves.linear}) { assert(_datePickerState != null, - 'DatePickerController is not attached to any DatePicker View.'); + 'DatePickerController is not attached to any DatePicker View.'); _datePickerState._controller.animateTo(_calculateDateOffset(date), duration: duration, curve: curve); @@ -208,7 +282,9 @@ class DatePickerController { /// Calculate the number of pixels that needs to be scrolled to go to the /// date provided in the argument double _calculateDateOffset(DateTime date) { - int offset = date.difference(_datePickerState.widget.startDate).inDays + 1; + int offset = date + .difference(_datePickerState.widget.startDate) + .inDays + 1; return (offset * _datePickerState.widget.width) + (offset * 6); } } diff --git a/lib/extra/dimen.dart b/lib/extra/dimen.dart index a5d3179..d86e8b3 100644 --- a/lib/extra/dimen.dart +++ b/lib/extra/dimen.dart @@ -11,4 +11,5 @@ class Dimen { static const double dateTextSize = 24; static const double dayTextSize = 11; static const double monthTextSize = 11; + static const double yearTextSize = 15; } diff --git a/lib/extra/style.dart b/lib/extra/style.dart index a72aa53..6ad3605 100644 --- a/lib/extra/style.dart +++ b/lib/extra/style.dart @@ -19,3 +19,10 @@ const TextStyle defaultDayTextStyle = TextStyle( fontSize: Dimen.dayTextSize, fontWeight: FontWeight.w500, ); + + +const TextStyle defaultYearTextStyle = TextStyle( + color: AppColors.defaultDayColor, + fontSize: Dimen.yearTextSize, + fontWeight: FontWeight.w500, +); diff --git a/lib/month_widget.dart b/lib/month_widget.dart new file mode 100644 index 0000000..988323e --- /dev/null +++ b/lib/month_widget.dart @@ -0,0 +1,58 @@ +import 'package:date_picker_timeline/gestures/tap.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class MonthWidget extends StatelessWidget { + final double width; + final DateTime date; + final TextStyle monthTextStyle,yearTextStyle; + final Color selectionColor; + final DateSelectionCallback onDateSelected; + final String locale; + + MonthWidget( + {@required this.date, + @required this.monthTextStyle, + @required this.yearTextStyle, + @required this.selectionColor, + this.width, + this.onDateSelected, + this.locale, + }); + + @override + Widget build(BuildContext context) { + return InkWell( + child: Container( + width: width, + margin: EdgeInsets.all(3.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + color: selectionColor, + ), + child: Padding( + padding: EdgeInsets.all(8), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Text(new DateFormat("yyyy", locale).format(date).toUpperCase(), // Month + style: yearTextStyle), + ), + Text(new DateFormat("MMM", locale).format(date).toUpperCase(), // Month + style: monthTextStyle), + ], + ), + ), + ), + onTap: () { + // Check if onDateSelected is not null + if (onDateSelected != null) { + // Call the onDateSelected Function + onDateSelected(this.date); + } + }, + ); + } +} diff --git a/lib/timelineType.dart b/lib/timelineType.dart new file mode 100644 index 0000000..167305a --- /dev/null +++ b/lib/timelineType.dart @@ -0,0 +1 @@ +enum TimelineType { DAY, MONTH } \ No newline at end of file diff --git a/screenshots/monthDatePicker.png b/screenshots/monthDatePicker.png new file mode 100644 index 0000000..089eb6b Binary files /dev/null and b/screenshots/monthDatePicker.png differ