Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fit: pagination start end month #453

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion example/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.4.2" apply false
id "org.jetbrains.kotlin.android" version "1.6.21" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}

include ":app"
7 changes: 7 additions & 0 deletions example/lib/widgets/month_view_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ class MonthViewWidget extends StatelessWidget {
showWeekends: true,
startDay: WeekDays.friday,
useAvailableVerticalSpace: true,
callBackStartEndPage: true,
onHasReachedStart: (date, page) => debugPrint(
'🚀 MonthViewWidget - date - ${date.toString()} - date - ${page.toString()}'),
onHasReachedEnd: (date, page) => debugPrint(
'🚀 MonthViewWidget - date - ${date.toString()} - date - ${page.toString()}'),
//onPageChange: (date, pageIndex) => debugPrint(
// '🚀 MonthViewWidget - date - ${date.toString()} - date - ${pageIndex.toString()}'),
onEventTap: (event, date) {
Navigator.of(context).push(
MaterialPageRoute(
Expand Down
288 changes: 210 additions & 78 deletions lib/src/month_view/month_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ class MonthView<T extends Object?> extends StatefulWidget {
/// Called when user changes month.
final CalendarPageChangeCallBack? onPageChange;

///Called when the user drags the last page to the left. Requesting a new page.
///Made for pagination with a request to the database.
final CalendarPageChangeCallBack? onHasReachedEnd;

///Called when the user drags the first page to the right.
///Requesting a new previous page. Made for paging with a request to the database.
final CalendarPageChangeCallBack? onHasReachedStart;

/// This function will be called when user taps on month view cell.
final CellTapCallback<T>? onCellTap;

Expand Down Expand Up @@ -142,7 +150,7 @@ class MonthView<T extends Object?> extends StatefulWidget {
/// This method will be called when user long press on calendar.
final DatePressCallback? onDateLongPress;

/// /// Defines the day from which the week starts.
/// Defines the day from which the week starts.
///
/// Default value is [WeekDays.monday].
final WeekDays startDay;
Expand Down Expand Up @@ -170,6 +178,10 @@ class MonthView<T extends Object?> extends StatefulWidget {
/// defines that show and hide cell not is in current month
final bool hideDaysNotInMonth;

//defines to receive new page request when there is no previous and next page.
//Suitable for database request.
final bool callBackStartEndPage;

/// Main [Widget] to display month view.
const MonthView({
Key? key,
Expand All @@ -190,6 +202,8 @@ class MonthView<T extends Object?> extends StatefulWidget {
this.pageTransitionCurve = Curves.ease,
this.width,
this.onPageChange,
this.onHasReachedEnd,
this.onHasReachedStart,
this.onCellTap,
this.onEventTap,
this.onEventLongTap,
Expand All @@ -202,12 +216,17 @@ class MonthView<T extends Object?> extends StatefulWidget {
this.safeAreaOption = const SafeAreaOption(),
this.onHeaderTitleTap,
this.pagePhysics = const ClampingScrollPhysics(),
this.pageViewPhysics,
this.pageViewPhysics, //
this.onEventDoubleTap,
this.showWeekTileBorder = true,
this.hideDaysNotInMonth = false,
this.callBackStartEndPage = false,
}) : assert(!(onHeaderTitleTap != null && headerBuilder != null),
"can't use [onHeaderTitleTap] & [headerBuilder] simultaneously"),
assert(
!(callBackStartEndPage &&
(onHasReachedEnd == null || onHasReachedStart == null)),
"When [callBackStartEndPage] is true, [onHasReachedEnd] and [onHasReachedStart] must not be null"),
super(key: key);

@override
Expand Down Expand Up @@ -252,11 +271,13 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
_setDateRange();

// Initialize current date.

_currentDate = (widget.initialMonth ?? DateTime.now()).withoutTime;

_regulateCurrentDate();

// Initialize page controller to control page actions.

_pageController = PageController(initialPage: _currentIndex);

_assignBuilders();
Expand Down Expand Up @@ -315,12 +336,194 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
@override
void dispose() {
_controller?.removeListener(_reloadCallback);

_pageController.dispose();
super.dispose();
}

void onHorizontalDragStartEnd(DragEndDetails dragEndDetails,
{required bool isFirstPage, required bool isLastPage}) {
if (isFirstPage && isLastPage) {
if (dragEndDetails.primaryVelocity! > 0) {
previousPage();
}
if (dragEndDetails.primaryVelocity! < 0) {
widget.onHasReachedEnd?.call(_currentDate, _currentIndex);
}
if (dragEndDetails.primaryVelocity! < 0) {
nextPage();
}
if (dragEndDetails.primaryVelocity! > 0) {
widget.onHasReachedStart?.call(_currentDate, _currentIndex);
}
} else if (isLastPage) {
if (dragEndDetails.primaryVelocity! > 0) {
previousPage();
}
if (dragEndDetails.primaryVelocity! < 0) {
widget.onHasReachedEnd?.call(_currentDate, _currentIndex);
}
} else if (isFirstPage) {
if (dragEndDetails.primaryVelocity! < 0) {
nextPage();
}
if (dragEndDetails.primaryVelocity! > 0) {
widget.onHasReachedStart?.call(_currentDate, _currentIndex);
}
}
}

@override
Widget build(BuildContext context) {
final pageView = PageView.builder(
controller: _pageController,
physics: widget.pageViewPhysics,
onPageChanged: _onPageChange,
itemBuilder: (_, index) {
final date = DateTime(_minDate.year, _minDate.month + index);
final weekDays = date.datesOfWeek(
start: widget.startDay,
showWeekEnds: widget.showWeekends,
);
if (widget.callBackStartEndPage) {
// build callBack Drags Pagination
//
final bool isFirstPage = index == 0;
final bool isLastPage = index == _totalMonths - 1;
if (isFirstPage || isLastPage) {
return GestureDetector(
onHorizontalDragEnd: (details) => onHorizontalDragStartEnd(
details,
isFirstPage: isFirstPage,
isLastPage: isLastPage),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: _width,
child: Row(
children: List.generate(
widget.showWeekends ? 7 : 5,
(index) => Expanded(
child: SizedBox(
width: _cellWidth,
child: _weekBuilder(weekDays[index].weekday - 1),
),
),
),
),
),
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
final dates = date.datesOfMonths(
startDay: widget.startDay,
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,
),
);
},
),
),
],
),
);
}
}

return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: _width,
child: Row(
children: List.generate(
widget.showWeekends ? 7 : 5,
(index) => Expanded(
child: SizedBox(
width: _cellWidth,
child: _weekBuilder(weekDays[index].weekday - 1),
),
),
),
),
),
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
final dates = date.datesOfMonths(
startDay: widget.startDay,
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,
),
);
},
),
),
],
);
},
itemCount: _totalMonths,
);
return SafeAreaWrapper(
option: widget.safeAreaOption,
child: SizedBox(
Expand All @@ -333,82 +536,7 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
child: _headerBuilder(_currentDate),
),
Expanded(
child: PageView.builder(
controller: _pageController,
physics: widget.pageViewPhysics,
onPageChanged: _onPageChange,
itemBuilder: (_, index) {
final date = DateTime(_minDate.year, _minDate.month + index);
final weekDays = date.datesOfWeek(
start: widget.startDay,
showWeekEnds: widget.showWeekends,
);

return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: _width,
child: Row(
children: List.generate(
widget.showWeekends ? 7 : 5,
(index) => Expanded(
child: SizedBox(
width: _cellWidth,
child:
_weekBuilder(weekDays[index].weekday - 1),
),
),
),
),
),
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
final dates = date.datesOfMonths(
startDay: widget.startDay,
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,
),
);
},
),
),
],
);
},
itemCount: _totalMonths,
),
child: pageView,
),
],
),
Expand Down Expand Up @@ -484,15 +612,19 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {

// Calculate the current index of page view.
_currentIndex = _minDate.getMonthDifference(_currentDate) - 1;
//index = _currentIndex;
}

/// Sets the minimum and maximum dates for current view.
void _setDateRange() {
// Initialize minimum date.
_minDate = (widget.minMonth ?? CalendarConstants.epochDate).withoutTime;
//final now = DateTime.now();
//_minDate = DateTime(now.year, now.month - 1);

// Initialize maximum date.
_maxDate = (widget.maxMonth ?? CalendarConstants.maxDate).withoutTime;
//_maxDate = DateTime(now.year, now.month + 1);

assert(
_minDate.isBefore(_maxDate),
Expand Down
Loading