diff --git a/example/lib/main.dart b/example/lib/main.dart index 146e23af..4735cb2a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -43,7 +43,7 @@ List _events = [ endTime: DateTime(_now.year, _now.month, _now.day, 22), ), CalendarEventData( - date: _now.add(Duration(days: 1)), + date: _now.add(Duration(days: 2)), startTime: DateTime(_now.year, _now.month, _now.day, 18), endTime: DateTime(_now.year, _now.month, _now.day, 19), title: "Wedding anniversary", diff --git a/example/lib/widgets/month_view_widget.dart b/example/lib/widgets/month_view_widget.dart index bacec7eb..6bfd75ac 100644 --- a/example/lib/widgets/month_view_widget.dart +++ b/example/lib/widgets/month_view_widget.dart @@ -18,7 +18,9 @@ class MonthViewWidget extends StatelessWidget { return MonthView( key: state, width: width, - hideDaysNotInMonth: false, + showWeekends: false, + useAvailableVerticalSpace: true, + hideDaysNotInMonth: true, onEventTap: (event, date) { Navigator.of(context).push( MaterialPageRoute( diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index 36077fd0..bc89b549 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -87,9 +87,30 @@ extension DateTimeExtensions on DateTime { /// All the dates are week based that means it will return array of size 42 /// which will contain 6 weeks that is the maximum number of weeks a month /// can have. - List datesOfMonths({WeekDays startDay = WeekDays.monday}) { + List datesOfMonths({ + WeekDays startDay = WeekDays.monday, + bool hideDaysNotInMonth = false, + }) { final monthDays = []; + // Friday's date for hidden weekends + final lastDateOfFirstWeek = firstDayOfWeek().add(const Duration(days: 4)); + // Start is the first weekday for each week in a month for (var i = 1, start = 1; i < 7; i++, start += 7) { + // Any date of week is in current month + final anyDateInCurrentMonth = DateTime(year, month, start) + .datesOfWeek(start: startDay) + .any((date) => date.month == month); + + if (hideDaysNotInMonth) { + // Check if first row need to skip + if (i == 1 && lastDateOfFirstWeek.month != month) { + continue; + } + // Check if last row need to skip + if (i == 6 && !anyDateInCurrentMonth) { + continue; + } + } monthDays .addAll(DateTime(year, month, start).datesOfWeek(start: startDay)); } diff --git a/lib/src/month_view/month_view.dart b/lib/src/month_view/month_view.dart index 51690910..3da386ee 100644 --- a/lib/src/month_view/month_view.dart +++ b/lib/src/month_view/month_view.dart @@ -64,6 +64,11 @@ class MonthView extends StatefulWidget { /// This method will be called when user double taps on event tile. final TileTapCallback? onEventDoubleTap; + /// Show weekends or not + /// + /// Default value is true. + final bool showWeekends; + /// Builds the name of the weeks. /// /// Used default week builder if null. @@ -184,6 +189,7 @@ class MonthView extends StatefulWidget { this.maxMonth, this.controller, this.initialMonth, + this.showWeekends = true, this.borderSize = 1, this.useAvailableVerticalSpace = false, this.cellAspectRatio = 0.55, @@ -352,7 +358,7 @@ class MonthViewState extends State> { width: _width, child: Row( children: List.generate( - 7, + widget.showWeekends ? 7 : 5, (index) => Expanded( child: SizedBox( width: _cellWidth, @@ -365,10 +371,15 @@ class MonthViewState extends State> { ), Expanded( child: LayoutBuilder(builder: (context, constraints) { + final datesInMonth = date.datesOfMonths( + startDay: widget.startDay, + hideDaysNotInMonth: widget.hideDaysNotInMonth, + ); final _cellAspectRatio = widget.useAvailableVerticalSpace ? calculateCellAspectRatio( - constraints.maxHeight, + height: constraints.maxHeight, + daysInMonth: datesInMonth.length, ) : widget.cellAspectRatio; @@ -391,6 +402,7 @@ class MonthViewState extends State> { startDay: widget.startDay, physics: widget.pagePhysics, hideDaysNotInMonth: widget.hideDaysNotInMonth, + weekDays: widget.showWeekends ? 7 : 5, ), ); }), @@ -432,8 +444,12 @@ class MonthViewState extends State> { _height = _cellHeight * 6; } - double calculateCellAspectRatio(double height) { - final _cellHeight = height / 6; + double calculateCellAspectRatio({ + required double height, + required int daysInMonth, + }) { + final rows = daysInMonth / 7; + final _cellHeight = height / rows; return _cellWidth / _cellHeight; } @@ -663,6 +679,7 @@ class _MonthPageBuilder extends StatelessWidget { final WeekDays startDay; final ScrollPhysics physics; final bool hideDaysNotInMonth; + final int weekDays; const _MonthPageBuilder({ Key? key, @@ -680,26 +697,76 @@ class _MonthPageBuilder extends StatelessWidget { required this.startDay, required this.physics, required this.hideDaysNotInMonth, + required this.weekDays, }) : super(key: key); @override Widget build(BuildContext context) { - final monthDays = date.datesOfMonths(startDay: startDay); - return Container( + final maxCells = _findMaxCells(); + final gridViewItems = _generateGridItems(); + + // Highlight tiles which is not in current month + return SizedBox( width: width, height: height, child: GridView.builder( padding: EdgeInsets.zero, physics: physics, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 7, + crossAxisCount: weekDays, childAspectRatio: cellRatio, ), - itemCount: 42, + itemCount: maxCells, shrinkWrap: true, - itemBuilder: (context, index) { - final events = controller.getEventsOnDay(monthDays[index]); - return GestureDetector( + itemBuilder: (context, index) => gridViewItems[index], + ), + ); + } + + int _findMaxCells() { + final daysInMonth = date + .datesOfMonths( + startDay: startDay, + hideDaysNotInMonth: hideDaysNotInMonth, + ) + .length; + + // Show weekends - true + if (weekDays == 7) { + // Show days not in month + if (!hideDaysNotInMonth) { + return 42; + } + return daysInMonth <= 28 ? 28 : 35; + } else { + // Hide weekends and show days not in month + if (!hideDaysNotInMonth) { + // 6 weeks: 5 week days * 6 weeks = 30 + return 30; + } else { + // When weekends are hidden & hide days not in month is true + // If daysInMonth is less than 28 max rows we can have is 4 otherwise 5. + // Weekends are included in daysInMonth + return daysInMonth <= 28 ? 20 : 25; + } + } + } + + List _generateGridItems() { + final gridViewItems = []; + final monthDays = date.datesOfMonths( + startDay: startDay, hideDaysNotInMonth: hideDaysNotInMonth); + + for (var index = 0; index < monthDays.length; index++) { + final events = controller.getEventsOnDay(monthDays[index]); + final isWeekend = monthDays[index].weekday == DateTime.saturday || + monthDays[index].weekday == DateTime.sunday; + if (isWeekend && weekDays == 5) { + continue; + } + if (!isWeekend || isWeekend && weekDays == 7) { + gridViewItems.add( + GestureDetector( onTap: () => onCellTap?.call(events, monthDays[index]), onLongPress: () => onDateLongPress?.call(monthDays[index]), child: Container( @@ -719,10 +786,11 @@ class _MonthPageBuilder extends StatelessWidget { hideDaysNotInMonth, ), ), - ); - }, - ), - ); + ), + ); + } + } + return gridViewItems; } }