@@ -7,6 +7,15 @@ import 'package:flutter/material.dart';
77import '../../calendar_view.dart' ;
88import '../extensions.dart' ;
99
10+ /// Controls how [MonthView] pages are scrolled.
11+ enum MonthViewMode {
12+ /// Existing behavior: month pages scroll horizontally.
13+ standard,
14+
15+ /// Month pages scroll vertically.
16+ verticalMonth,
17+ }
18+
1019class MonthView <T extends Object ?> extends StatefulWidget {
1120 /// Main [Widget] to display month view.
1221 const MonthView ({
@@ -19,6 +28,7 @@ class MonthView<T extends Object?> extends StatefulWidget {
1928 this .selectedDate,
2029 this .multiDateSelectionRange = const {},
2130 this .multiDateSelectionColor,
31+ this .monthViewMode = MonthViewMode .standard,
2232 }) : super (key: key);
2333
2434 /// A required parameters that controls events for month view.
@@ -58,6 +68,9 @@ class MonthView<T extends Object?> extends StatefulWidget {
5868 /// Color of the date cells selected via [MonthViewBuilders.onDateLongPressMoveUpdate]
5969 final Color ? multiDateSelectionColor;
6070
71+ /// Controls scroll direction and layout behavior for the month pages.
72+ final MonthViewMode monthViewMode;
73+
6174 @override
6275 MonthViewState <T > createState () => MonthViewState <T >();
6376}
@@ -217,21 +230,23 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
217230 super .dispose ();
218231 }
219232
220- void onHorizontalDragEnd (
233+ void _onBoundaryDragEnd (
221234 DragEndDetails dragEndDetails, {
222235 required bool isFirstPage,
223236 required bool isLastPage,
237+ required Axis scrollDirection,
224238 TextDirection textDirection = TextDirection .ltr,
225239 }) {
226240 final velocity = dragEndDetails.primaryVelocity ?? 0 ;
227241 if (velocity == 0 ) return ;
228242
229243 final isRtl = textDirection == TextDirection .rtl;
230-
231- // In LTR: swipe right (velocity > 0) = previous, swipe left (velocity < 0) = next
232- // In RTL: swipe right (velocity > 0) = next, swipe left (velocity < 0) = previous
233- final isSwipingToPrevious = isRtl ? velocity < 0 : velocity > 0 ;
234- final isSwipingToNext = isRtl ? velocity > 0 : velocity < 0 ;
244+ final isSwipingToPrevious = scrollDirection == Axis .horizontal
245+ ? (isRtl ? velocity < 0 : velocity > 0 )
246+ : velocity > 0 ;
247+ final isSwipingToNext = scrollDirection == Axis .horizontal
248+ ? (isRtl ? velocity > 0 : velocity < 0 )
249+ : velocity < 0 ;
235250
236251 if (isFirstPage && isLastPage) {
237252 // Only one page - trigger both callbacks based on swipe direction
@@ -281,6 +296,9 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
281296 ),
282297 Expanded (
283298 child: PageView .builder (
299+ scrollDirection: widget.monthViewMode == MonthViewMode .standard
300+ ? Axis .horizontal
301+ : Axis .vertical,
284302 controller: _pageController,
285303 physics: _isMultiDateSelectionInProgress
286304 ? const NeverScrollableScrollPhysics ()
@@ -370,13 +388,29 @@ class MonthViewState<T extends Object?> extends State<MonthView<T>> {
370388 final isFirstPage = index == 0 ;
371389 final isLastPage = index == _totalMonths - 1 ;
372390 if (isFirstPage || isLastPage) {
391+ final axis =
392+ widget.monthViewMode == MonthViewMode .standard
393+ ? Axis .horizontal
394+ : Axis .vertical;
373395 return GestureDetector (
374- onHorizontalDragEnd: (details) => onHorizontalDragEnd (
375- details,
376- isFirstPage: isFirstPage,
377- isLastPage: isLastPage,
378- textDirection: textDirection,
379- ),
396+ onHorizontalDragEnd: axis == Axis .horizontal
397+ ? (details) => _onBoundaryDragEnd (
398+ details,
399+ isFirstPage: isFirstPage,
400+ isLastPage: isLastPage,
401+ scrollDirection: axis,
402+ textDirection: textDirection,
403+ )
404+ : null ,
405+ onVerticalDragEnd: axis == Axis .vertical
406+ ? (details) => _onBoundaryDragEnd (
407+ details,
408+ isFirstPage: isFirstPage,
409+ isLastPage: isLastPage,
410+ scrollDirection: axis,
411+ textDirection: textDirection,
412+ )
413+ : null ,
380414 child: monthPageContent,
381415 );
382416 }
0 commit comments