Skip to content

Commit

Permalink
feat: Fixes issue #385: Add showWeekends flag in month view
Browse files Browse the repository at this point in the history
  • Loading branch information
shubham-jitiya-simform committed Dec 19, 2024
1 parent cc99a0e commit 198f9ca
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 63 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# [1.4.0](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.4.0)
- Adds `showWeekends` flag in month view to hide & show weekends view.
Default is `showWeekends = true` shows all weekdays. [#385](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/385)
- Events are now hidden for days not in the current month when hideDaysNotInMonth = true

# [1.3.0 - 12 Nov 2024](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.3.0)

- Fixes full day event position when fullHeaderTitle is empty.
Expand Down Expand Up @@ -199,4 +204,4 @@

# [0.0.1 - 26 Aug 2021](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/0.0.1)

- Initial release
- Initial release
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ MonthView(
headerBuilder: MonthHeader.hidden, // To hide month header
showWeekTileBorder: false, // To show or hide header border
hideDaysNotInMonth: true, // To hide days or cell that are not in current month
showWeekends: false, // To hide weekends default value is true
);
```

Expand Down
5 changes: 4 additions & 1 deletion example/lib/widgets/month_view_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ class MonthViewWidget extends StatelessWidget {
return MonthView(
key: state,
width: width,
hideDaysNotInMonth: false,
showWeekends: false,
startDay: WeekDays.friday,
useAvailableVerticalSpace: true,
hideDaysNotInMonth: true,
onEventTap: (event, date) {
Navigator.of(context).push(
MaterialPageRoute(
Expand Down
1 change: 1 addition & 0 deletions example/lib/widgets/week_view_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class WeekViewWidget extends StatelessWidget {
return WeekView(
key: state,
width: width,
showWeekends: false,
showLiveTimeLineInAllDays: true,
eventArranger: SideEventArranger(maxWidth: 30),
timeLineWidth: 65,
Expand Down
64 changes: 50 additions & 14 deletions lib/src/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ extension DateTimeExtensions on DateTime {
/// will return dates
/// [6,7,8,9,10,11,12]
/// Where on 6th there will be monday and on 12th there will be Sunday
List<DateTime> datesOfWeek({WeekDays start = WeekDays.monday}) {
List<DateTime> datesOfWeek({
WeekDays start = WeekDays.monday,
bool showWeekEnds = true,
}) {
// Here %7 ensure that we do not subtract >6 and <0 days.
// Initial formula is,
// difference = (weekday - startInt)%7
Expand All @@ -63,16 +66,20 @@ extension DateTimeExtensions on DateTime {
//
final startDay =
DateTime(year, month, day - (weekday - start.index - 1) % 7);

return [
startDay,
DateTime(startDay.year, startDay.month, startDay.day + 1),
DateTime(startDay.year, startDay.month, startDay.day + 2),
DateTime(startDay.year, startDay.month, startDay.day + 3),
DateTime(startDay.year, startDay.month, startDay.day + 4),
DateTime(startDay.year, startDay.month, startDay.day + 5),
DateTime(startDay.year, startDay.month, startDay.day + 6),
];
final days = List.generate(
7,
(index) => DateTime(startDay.year, startDay.month, startDay.day + index),
);

// Remove weekends
if (!showWeekEnds) {
days.removeWhere(
(date) =>
date.weekday == DateTime.saturday ||
date.weekday == DateTime.sunday,
);
}
return days;
}

/// Returns the first date of week containing the current date
Expand All @@ -87,11 +94,40 @@ 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<DateTime> datesOfMonths({WeekDays startDay = WeekDays.monday}) {
///
/// It excludes week if `hideDaysNotInMonth` is set true and
/// if all dates in week comes in next month then it will excludes that week.
List<DateTime> datesOfMonths({
WeekDays startDay = WeekDays.monday,
bool hideDaysNotInMonth = false,
bool showWeekends = true,
}) {
final monthDays = <DateTime>[];
// Start is the first weekday for each week in a month
for (var i = 1, start = 1; i < 7; i++, start += 7) {
monthDays
.addAll(DateTime(year, month, start).datesOfWeek(start: startDay));
final datesInWeek =
DateTime(year, month, start).datesOfWeek(start: startDay).where(
(day) {
if (showWeekends) {
return true;
} else {
if (day.weekday != DateTime.saturday &&
day.weekday != DateTime.sunday) {
return true;
}
return false;
}
},
);
// Check does every date of week belongs to different month
final allDatesNotInCurrentMonth = datesInWeek.every((date) {
return date.month != month;
});
// if entire row contains dates of other month then skip it
if (hideDaysNotInMonth && allDatesNotInCurrentMonth) {
continue;
}
monthDays.addAll(datesInWeek);
}
return monthDays;
}
Expand Down
118 changes: 72 additions & 46 deletions lib/src/month_view/month_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,8 @@

import 'package:flutter/material.dart';

import '../calendar_constants.dart';
import '../calendar_controller_provider.dart';
import '../calendar_event_data.dart';
import '../components/components.dart';
import '../../calendar_view.dart';
import '../constants.dart';
import '../enumerations.dart';
import '../event_controller.dart';
import '../extensions.dart';
import '../style/header_style.dart';
import '../typedefs.dart';

class MonthView<T extends Object?> extends StatefulWidget {
/// A function that returns a [Widget] that determines appearance of
Expand Down Expand Up @@ -64,6 +56,10 @@ class MonthView<T extends Object?> extends StatefulWidget {
/// This method will be called when user double taps on event tile.
final TileTapCallback<T>? onEventDoubleTap;

/// Show weekends or not.
/// Default value is true.
final bool showWeekends;

/// Builds the name of the weeks.
///
/// Used default week builder if null.
Expand Down Expand Up @@ -184,6 +180,7 @@ class MonthView<T extends Object?> extends StatefulWidget {
this.maxMonth,
this.controller,
this.initialMonth,
this.showWeekends = true,
this.borderSize = 1,
this.useAvailableVerticalSpace = false,
this.cellAspectRatio = 0.55,
Expand Down Expand Up @@ -342,7 +339,10 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
onPageChanged: _onPageChange,
itemBuilder: (_, index) {
final date = DateTime(_minDate.year, _minDate.month + index);
final weekDays = date.datesOfWeek(start: widget.startDay);
final weekDays = date.datesOfWeek(
start: widget.startDay,
showWeekEnds: widget.showWeekends,
);

return Column(
mainAxisSize: MainAxisSize.min,
Expand All @@ -352,7 +352,8 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
width: _width,
child: Row(
children: List.generate(
7,
// TODO(Shubham): This may not required if we remove weekdays from list
widget.showWeekends ? 7 : 5,
(index) => Expanded(
child: SizedBox(
width: _cellWidth,
Expand All @@ -364,36 +365,45 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
),
),
Expanded(
child: LayoutBuilder(builder: (context, constraints) {
final _cellAspectRatio =
widget.useAvailableVerticalSpace
? calculateCellAspectRatio(
constraints.maxHeight,
)
: widget.cellAspectRatio;

return SizedBox(
height: _height,
width: _width,
child: _MonthPageBuilder<T>(
key: ValueKey(date.toIso8601String()),
onCellTap: widget.onCellTap,
onDateLongPress: widget.onDateLongPress,
width: _width,
height: _height,
controller: controller,
borderColor: widget.borderColor,
borderSize: widget.borderSize,
cellBuilder: _cellBuilder,
cellRatio: _cellAspectRatio,
date: date,
showBorder: widget.showBorder,
child: LayoutBuilder(
builder: (context, constraints) {
final dates = date.datesOfMonths(
startDay: widget.startDay,
physics: widget.pagePhysics,
hideDaysNotInMonth: widget.hideDaysNotInMonth,
),
);
}),
showWeekends: widget.showWeekends,
);
final _cellAspectRatio =
widget.useAvailableVerticalSpace
? calculateCellAspectRatio(
height: constraints.maxHeight,
daysInMonth: dates.length,
)
: widget.cellAspectRatio;

return SizedBox(
height: _height,
width: _width,
child: _MonthPageBuilder<T>(
key: ValueKey(date.toIso8601String()),
onCellTap: widget.onCellTap,
onDateLongPress: widget.onDateLongPress,
width: _width,
height: _height,
controller: controller,
borderColor: widget.borderColor,
borderSize: widget.borderSize,
cellBuilder: _cellBuilder,
cellRatio: _cellAspectRatio,
date: date,
showBorder: widget.showBorder,
startDay: widget.startDay,
physics: widget.pagePhysics,
hideDaysNotInMonth: widget.hideDaysNotInMonth,
weekDays: widget.showWeekends ? 7 : 5,
),
);
},
),
),
],
);
Expand Down Expand Up @@ -432,8 +442,12 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
_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;
}

Expand Down Expand Up @@ -663,6 +677,7 @@ class _MonthPageBuilder<T> extends StatelessWidget {
final WeekDays startDay;
final ScrollPhysics physics;
final bool hideDaysNotInMonth;
final int weekDays;

const _MonthPageBuilder({
Key? key,
Expand All @@ -680,25 +695,36 @@ class _MonthPageBuilder<T> 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 monthDays = date.datesOfMonths(
startDay: startDay,
hideDaysNotInMonth: hideDaysNotInMonth,
showWeekends: weekDays == 7,
);

// 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: monthDays.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final events = controller.getEventsOnDay(monthDays[index]);
// Hide events if `hideDaysNotInMonth` true
final events =
hideDaysNotInMonth & (monthDays[index].month != date.month)
? <CalendarEventData<T>>[]
: controller.getEventsOnDay(monthDays[index]);
return GestureDetector(
onTap: () => onCellTap?.call(events, monthDays[index]),
onLongPress: () => onDateLongPress?.call(monthDays[index]),
Expand Down
5 changes: 4 additions & 1 deletion lib/src/week_view/week_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,10 @@ class WeekViewState<T extends Object?> extends State<WeekView<T>> {
itemBuilder: (_, index) {
final dates = DateTime(_minDate.year, _minDate.month,
_minDate.day + (index * DateTime.daysPerWeek))
.datesOfWeek(start: widget.startDay);
.datesOfWeek(
start: widget.startDay,
showWeekEnds: widget.showWeekends,
);

return ValueListenableBuilder(
valueListenable: _scrollConfiguration,
Expand Down

0 comments on commit 198f9ca

Please sign in to comment.