diff --git a/CHANGELOG.md b/CHANGELOG.md index 543e1f8a..babf1a52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# [1.0.5] (UnReleased)(https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.0.5) + +- Fixed issue related to auto scroll to initial duration for day + view-[#269](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/269) +- Added + feature added a callback for the default header title + - [#241](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/241) + # [1.0.4 - 9 Aug 2023](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.0.4) - Fixed @@ -8,10 +16,9 @@ Issue [#237 - DayView & MonthView layout issue in landscape mode](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/237) - Added Feature [#57 - Change default start hour in DayView](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/57) -- Fixed +- Fixed Issue [#225 - Unwanted space at top in DayView while using sliver](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/225) - # [1.0.3 - 3 Apr 2023](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.0.3) - Added diff --git a/README.md b/README.md index 3192b892..3a864ece 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,9 @@ DayView( eventArranger: SideEventArranger(), // To define how simultaneous events will be arranged. onEventTap: (events, date) => print(events), onDateLongPress: (date) => print(date), + hourLinePainter: (lineColor, lineHeight, offset, minuteHeight, showVerticalLine, verticalLineOffset) { + return //Your custom painter. + } ); ``` @@ -200,9 +203,15 @@ WeekView( onEventTap: (events, date) => print(events), onDateLongPress: (date) => print(date), startDay: WeekDays.sunday, // To change the first day of the week. + showVerticalLines: false, // Show the vertical line between days. + hourLinePainter: (lineColor, lineHeight, offset, minuteHeight, showVerticalLine, verticalLineOffset) { + return //Your custom painter. + } ); ``` + + To see the list of all parameters and detailed description of parameters visit [documentation](https://pub.dev/documentation/calendar_view/latest/calendar_view/calendar_view-library.html) . diff --git a/lib/src/day_view/_internal_day_view_page.dart b/lib/src/day_view/_internal_day_view_page.dart index 706cf02c..29fe183f 100644 --- a/lib/src/day_view/_internal_day_view_page.dart +++ b/lib/src/day_view/_internal_day_view_page.dart @@ -39,6 +39,9 @@ class InternalDayViewPage extends StatelessWidget { /// Settings for hour indicator lines. final HourIndicatorSettings hourIndicatorSettings; + /// Custom painter for hour line. + final CustomHourLinePainter hourLinePainter; + /// Flag to display live time indicator. /// If true then indicator will be displayed else not. final bool showLiveLine; @@ -110,6 +113,7 @@ class InternalDayViewPage extends StatelessWidget { required this.controller, required this.timeLineBuilder, required this.hourIndicatorSettings, + required this.hourLinePainter, required this.showLiveLine, required this.liveTimeIndicatorSettings, required this.heightPerMinute, @@ -152,16 +156,16 @@ class InternalDayViewPage extends StatelessWidget { children: [ CustomPaint( size: Size(width, height), - painter: HourLinePainter( - lineColor: hourIndicatorSettings.color, - lineHeight: hourIndicatorSettings.height, - offset: timeLineWidth + hourIndicatorSettings.offset, - minuteHeight: heightPerMinute, - verticalLineOffset: verticalLineOffset, - showVerticalLine: showVerticalLine, - lineStyle: hourIndicatorSettings.lineStyle, - dashWidth: hourIndicatorSettings.dashWidth, - dashSpaceWidth: hourIndicatorSettings.dashSpaceWidth, + painter: hourLinePainter( + hourIndicatorSettings.color, + hourIndicatorSettings.height, + timeLineWidth + hourIndicatorSettings.offset, + heightPerMinute, + showVerticalLine, + verticalLineOffset, + hourIndicatorSettings.lineStyle, + hourIndicatorSettings.dashWidth, + hourIndicatorSettings.dashSpaceWidth, ), ), if (showHalfHours) diff --git a/lib/src/day_view/day_view.dart b/lib/src/day_view/day_view.dart index 73ef9bee..54dec239 100644 --- a/lib/src/day_view/day_view.dart +++ b/lib/src/day_view/day_view.dart @@ -18,6 +18,7 @@ import '../event_arrangers/event_arrangers.dart'; import '../event_controller.dart'; import '../extensions.dart'; import '../modals.dart'; +import '../painters.dart'; import '../style/header_style.dart'; import '../typedefs.dart'; import '_internal_day_view_page.dart'; @@ -79,6 +80,11 @@ class DayView extends StatefulWidget { /// Pass [HourIndicatorSettings.none] to remove Hour lines. final HourIndicatorSettings? hourIndicatorSettings; + /// A funtion that returns a [CustomPainter]. + /// + /// Use this if you want to paint custom hour lines. + final CustomHourLinePainter? hourLinePainter; + /// Defines settings for live time indicator. /// /// Pass [HourIndicatorSettings.none] to remove live time indicator. @@ -145,8 +151,12 @@ class DayView extends StatefulWidget { /// Background colour of day view page. final Color? backgroundColor; - /// Scroll offset of day view page. - final double scrollOffset; + /// Defines initial offset of first page that will be displayed when + /// [DayView] is initialized. + /// + /// If [scrollOffset] is null then [startDuration] will be considered for + /// initial offset. + final double? scrollOffset; /// This method will be called when user taps on event tile. final CellTapCallback? onEventTap; @@ -184,10 +194,13 @@ class DayView extends StatefulWidget { final bool showHalfHours; - /// Duration from where default day view will be visible + /// It define the starting duration from where day view page will be visible /// By default it will be Duration(hours:0) final Duration startDuration; + /// Callback for the Header title + final HeaderTitleCallback? onHeaderTitleTap; + /// Main widget for day view. const DayView({ Key? key, @@ -203,6 +216,7 @@ class DayView extends StatefulWidget { this.maxDay, this.initialDay, this.hourIndicatorSettings, + this.hourLinePainter, this.heightPerMinute = 0.7, this.timeLineBuilder, this.timeLineWidth, @@ -214,7 +228,7 @@ class DayView extends StatefulWidget { this.eventArranger, this.verticalLineOffset = 10, this.backgroundColor = Colors.white, - this.scrollOffset = 0.0, + this.scrollOffset, this.onEventTap, this.onDateLongPress, this.onDateTap, @@ -228,7 +242,10 @@ class DayView extends StatefulWidget { this.showHalfHours = false, this.halfHourIndicatorSettings, this.startDuration = const Duration(hours: 0), - }) : assert(timeLineOffset >= 0, + this.onHeaderTitleTap, + }) : assert(!(onHeaderTitleTap != null && dayTitleBuilder != null), + "can't use [onHeaderTitleTap] & [dayTitleBuilder] simultaneously"), + assert(timeLineOffset >= 0, "timeLineOffset must be greater than or equal to 0"), assert(width == null || width > 0, "Calendar width must be greater than 0."), @@ -262,6 +279,8 @@ class DayViewState extends State> { late HourIndicatorSettings _hourIndicatorSettings; late HourIndicatorSettings _halfHourIndicatorSettings; + late CustomHourLinePainter _hourLinePainter; + late HourIndicatorSettings _liveTimeIndicatorSettings; late PageController _pageController; @@ -298,8 +317,9 @@ class DayViewState extends State> { _regulateCurrentDate(); _calculateHeights(); - _scrollController = - ScrollController(initialScrollOffset: widget.scrollOffset); + _scrollController = ScrollController( + initialScrollOffset: widget.scrollOffset ?? + widget.startDuration.inMinutes * widget.heightPerMinute); _pageController = PageController(initialPage: _currentIndex); _eventArranger = widget.eventArranger ?? SideEventArranger(); _assignBuilders(); @@ -323,10 +343,6 @@ class DayViewState extends State> { // user adds new events. ..addListener(_reloadCallback); } - - WidgetsBinding.instance.addPostFrameCallback((_) { - animateToDuration(widget.startDuration); - }); } @override @@ -407,6 +423,7 @@ class DayViewState extends State> { eventTileBuilder: _eventTileBuilder, heightPerMinute: widget.heightPerMinute, hourIndicatorSettings: _hourIndicatorSettings, + hourLinePainter: _hourLinePainter, date: date, onTileTap: widget.onEventTap, onDateLongPress: widget.onDateLongPress, @@ -510,6 +527,7 @@ class DayViewState extends State> { widget.fullDayEventBuilder ?? _defaultFullDayEventBuilder; _dayDetectorBuilder = widget.dayDetectorBuilder ?? _defaultPressDetectorBuilder; + _hourLinePainter = widget.hourLinePainter ?? _defaultHourLinePainter; } /// Sets the current date of this month. @@ -638,15 +656,19 @@ class DayViewState extends State> { onNextDay: nextPage, onPreviousDay: previousPage, onTitleTapped: () async { - final selectedDate = await showDatePicker( - context: context, - initialDate: date, - firstDate: _minDate, - lastDate: _maxDate, - ); - - if (selectedDate == null) return; - jumpToDate(selectedDate); + if (widget.onHeaderTitleTap != null) { + widget.onHeaderTitleTap!(date); + } else { + final selectedDate = await showDatePicker( + context: context, + initialDate: date, + firstDate: _minDate, + lastDate: _maxDate, + ); + + if (selectedDate == null) return; + jumpToDate(selectedDate); + } }, headerStyle: widget.headerStyle, ); @@ -656,6 +678,30 @@ class DayViewState extends State> { List> events, DateTime date) => FullDayEventView(events: events, date: date); + HourLinePainter _defaultHourLinePainter( + Color lineColor, + double lineHeight, + double offset, + double minuteHeight, + bool showVerticalLine, + double verticalLineOffset, + LineStyle lineStyle, + double dashWidth, + double dashSpaceWidth, + ) { + return HourLinePainter( + lineColor: lineColor, + lineHeight: lineHeight, + offset: offset, + minuteHeight: minuteHeight, + verticalLineOffset: verticalLineOffset, + showVerticalLine: showVerticalLine, + lineStyle: lineStyle, + dashWidth: dashWidth, + dashSpaceWidth: dashSpaceWidth, + ); + } + /// Called when user change page using any gesture or inbuilt functions. /// void _onPageChange(int index) { @@ -799,8 +845,7 @@ class DayViewState extends State> { // above 24 hrs then we take it max as 24 hours only final offset = offSetForSingleMinute * (startDurationInMinutes > 3600 ? 3600 : startDurationInMinutes); - debugPrint("offSet $offset"); - _scrollController.animateTo( + animateTo( offset.toDouble(), duration: duration, curve: curve, diff --git a/lib/src/event_arrangers/merge_event_arranger.dart b/lib/src/event_arrangers/merge_event_arranger.dart index d9bae4fc..37e9ca6a 100644 --- a/lib/src/event_arrangers/merge_event_arranger.dart +++ b/lib/src/event_arrangers/merge_event_arranger.dart @@ -124,10 +124,15 @@ class MergeEventArranger extends EventArranger { bool _checkIsOverlapping(int arrangedEventStart, int arrangedEventEnd, int eventStart, int eventEnd) { - return (arrangedEventStart >= eventStart && + var result = (arrangedEventStart >= eventStart && arrangedEventStart <= eventEnd) || (arrangedEventEnd >= eventStart && arrangedEventEnd <= eventEnd) || (eventStart >= arrangedEventStart && eventStart <= arrangedEventEnd) || (eventEnd >= arrangedEventStart && eventEnd <= arrangedEventEnd); + + if (result) { + result = result && (arrangedEventEnd != eventStart); + } + return result; } } diff --git a/lib/src/month_view/month_view.dart b/lib/src/month_view/month_view.dart index b19f7851..2966adfd 100644 --- a/lib/src/month_view/month_view.dart +++ b/lib/src/month_view/month_view.dart @@ -138,6 +138,9 @@ class MonthView extends StatefulWidget { /// Option for SafeArea. final SafeAreaOption safeAreaOption; + /// Callback for the Header title + final HeaderTitleCallback? onHeaderTitleTap; + /// Defines scroll physics for a page of a month view. /// /// This can be used to disable the vertical scroll of a page. @@ -172,8 +175,11 @@ class MonthView extends StatefulWidget { this.weekDayStringBuilder, this.headerStyle = const HeaderStyle(), this.safeAreaOption = const SafeAreaOption(), + this.onHeaderTitleTap, this.pagePhysics = const ClampingScrollPhysics(), - }) : super(key: key); + }) : assert(!(onHeaderTitleTap != null && headerBuilder != null), + "can't use [onHeaderTitleTap] & [headerBuilder] simultaneously"), + super(key: key); @override MonthViewState createState() => MonthViewState(); @@ -470,15 +476,19 @@ class MonthViewState extends State> { Widget _defaultHeaderBuilder(DateTime date) { return MonthPageHeader( onTitleTapped: () async { - final selectedDate = await showDatePicker( - context: context, - initialDate: date, - firstDate: _minDate, - lastDate: _maxDate, - ); + if (widget.onHeaderTitleTap != null) { + widget.onHeaderTitleTap!(date); + } else { + final selectedDate = await showDatePicker( + context: context, + initialDate: date, + firstDate: _minDate, + lastDate: _maxDate, + ); - if (selectedDate == null) return; - jumpToMonth(selectedDate); + if (selectedDate == null) return; + jumpToMonth(selectedDate); + } }, onPreviousMonth: previousPage, date: date, diff --git a/lib/src/typedefs.dart b/lib/src/typedefs.dart index 76f0b64d..cf0d6f14 100644 --- a/lib/src/typedefs.dart +++ b/lib/src/typedefs.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; -import 'calendar_event_data.dart'; -import 'enumerations.dart'; +import '../calendar_view.dart'; typedef CellBuilder = Widget Function( DateTime date, @@ -34,9 +33,9 @@ typedef WeekDayBuilder = Widget Function( int day, ); -typedef DateWidgetBuilder = Widget Function( - DateTime date, -); +typedef DateWidgetBuilder = Widget Function(DateTime date); + +typedef HeaderTitleCallback = Future Function(DateTime date); typedef WeekNumberBuilder = Widget? Function( DateTime firstDayOfWeek, @@ -56,7 +55,9 @@ typedef StringProvider = String Function(DateTime date, {DateTime? secondaryDate}); typedef WeekPageHeaderBuilder = Widget Function( - DateTime startDate, DateTime endDate); + DateTime startDate, + DateTime endDate, +); typedef TileTapCallback = void Function( CalendarEventData event, DateTime date); @@ -70,3 +71,15 @@ typedef DateTapCallback = void Function(DateTime date); typedef EventFilter = List> Function( DateTime date, List> events); + +typedef CustomHourLinePainter = CustomPainter Function( + Color lineColor, + double lineHeight, + double offset, + double minuteHeight, + bool showVerticalLine, + double verticalLineOffset, + LineStyle lineStyle, + double dashWidth, + double dashSpaceWidth, +); diff --git a/lib/src/week_view/_internal_week_view_page.dart b/lib/src/week_view/_internal_week_view_page.dart index 3f7ec3b4..b0113231 100644 --- a/lib/src/week_view/_internal_week_view_page.dart +++ b/lib/src/week_view/_internal_week_view_page.dart @@ -10,7 +10,6 @@ import '../enumerations.dart'; import '../event_arrangers/event_arrangers.dart'; import '../event_controller.dart'; import '../modals.dart'; -import '../painters.dart'; import '../typedefs.dart'; /// A single page for week view. @@ -37,6 +36,9 @@ class InternalWeekViewPage extends StatelessWidget { /// Settings for hour indicator lines. final HourIndicatorSettings hourIndicatorSettings; + /// Custom painter for hour line. + final CustomHourLinePainter hourLinePainter; + /// Flag to display live line. final bool showLiveLine; @@ -124,6 +126,7 @@ class InternalWeekViewPage extends StatelessWidget { required this.controller, required this.timeLineBuilder, required this.hourIndicatorSettings, + required this.hourLinePainter, required this.showLiveLine, required this.liveTimeIndicatorSettings, required this.heightPerMinute, @@ -216,13 +219,16 @@ class InternalWeekViewPage extends StatelessWidget { children: [ CustomPaint( size: Size(width, height), - painter: HourLinePainter( - lineColor: hourIndicatorSettings.color, - lineHeight: hourIndicatorSettings.height, - offset: timeLineWidth + hourIndicatorSettings.offset, - minuteHeight: heightPerMinute, - verticalLineOffset: verticalLineOffset, - showVerticalLine: showVerticalLine, + painter: hourLinePainter( + hourIndicatorSettings.color, + hourIndicatorSettings.height, + timeLineWidth + hourIndicatorSettings.offset, + heightPerMinute, + showVerticalLine, + verticalLineOffset, + hourIndicatorSettings.lineStyle, + hourIndicatorSettings.dashWidth, + hourIndicatorSettings.dashSpaceWidth, ), ), if (showLiveLine && liveTimeIndicatorSettings.height > 0) @@ -243,14 +249,16 @@ class InternalWeekViewPage extends StatelessWidget { ...List.generate( filteredDates.length, (index) => Container( - decoration: BoxDecoration( - border: Border( - right: BorderSide( - color: hourIndicatorSettings.color, - width: hourIndicatorSettings.height, - ), - ), - ), + decoration: showVerticalLine + ? BoxDecoration( + border: Border( + right: BorderSide( + color: hourIndicatorSettings.color, + width: hourIndicatorSettings.height, + ), + ), + ) + : null, height: height, width: weekTitleWidth, child: Stack( diff --git a/lib/src/week_view/week_view.dart b/lib/src/week_view/week_view.dart index 8357e98c..82e90d98 100644 --- a/lib/src/week_view/week_view.dart +++ b/lib/src/week_view/week_view.dart @@ -16,6 +16,7 @@ import '../event_arrangers/event_arrangers.dart'; import '../event_controller.dart'; import '../extensions.dart'; import '../modals.dart'; +import '../painters.dart'; import '../style/header_style.dart'; import '../typedefs.dart'; import '_internal_week_view_page.dart'; @@ -85,6 +86,11 @@ class WeekView extends StatefulWidget { /// Settings for hour indicator settings. final HourIndicatorSettings? hourIndicatorSettings; + /// A funtion that returns a [CustomPainter]. + /// + /// Use this if you want to paint custom hour lines. + final CustomHourLinePainter? hourLinePainter; + /// Settings for live time indicator settings. final HourIndicatorSettings? liveTimeIndicatorSettings; @@ -114,6 +120,9 @@ class WeekView extends StatefulWidget { /// Width of week view. If null provided device width will be considered. final double? width; + /// If true this will display vertical lines between each day. + final bool showVerticalLines; + /// Height of week day title, final double weekTitleHeight; @@ -183,6 +192,9 @@ class WeekView extends StatefulWidget { /// Display full day event builder. final FullDayEventBuilder? fullDayEventBuilder; + /// Callback for the Header title + final HeaderTitleCallback? onHeaderTitleTap; + /// Main widget for week view. const WeekView({ Key? key, @@ -193,11 +205,13 @@ class WeekView extends StatefulWidget { this.heightPerMinute = 1, this.timeLineOffset = 0, this.showLiveTimeLineInAllDays = false, + this.showVerticalLines = true, this.width, this.minDay, this.maxDay, this.initialDay, this.hourIndicatorSettings, + this.hourLinePainter, this.timeLineBuilder, this.timeLineWidth, this.liveTimeIndicatorSettings, @@ -224,7 +238,10 @@ class WeekView extends StatefulWidget { this.headerStyle = const HeaderStyle(), this.safeAreaOption = const SafeAreaOption(), this.fullDayEventBuilder, - }) : assert((timeLineOffset) >= 0, + this.onHeaderTitleTap, + }) : assert(!(onHeaderTitleTap != null && weekPageHeaderBuilder != null), + "can't use [onHeaderTitleTap] & [weekPageHeaderBuilder] simultaneously"), + assert((timeLineOffset) >= 0, "timeLineOffset must be greater than or equal to 0"), assert(width == null || width > 0, "Calendar width must be greater than 0."), @@ -259,6 +276,8 @@ class WeekViewState extends State> { late EventArranger _eventArranger; late HourIndicatorSettings _hourIndicatorSettings; + late CustomHourLinePainter _hourLinePainter; + late HourIndicatorSettings _liveTimeIndicatorSettings; late PageController _pageController; @@ -381,7 +400,10 @@ class WeekViewState extends State> { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - _weekHeaderBuilder(_currentStartDate, _currentEndDate), + _weekHeaderBuilder( + _currentStartDate, + _currentEndDate, + ), Expanded( child: DecoratedBox( decoration: BoxDecoration(color: widget.backgroundColor), @@ -418,13 +440,14 @@ class WeekViewState extends State> { eventTileBuilder: _eventTileBuilder, heightPerMinute: widget.heightPerMinute, hourIndicatorSettings: _hourIndicatorSettings, + hourLinePainter: _hourLinePainter, dates: dates, showLiveLine: widget.showLiveTimeLineInAllDays || _showLiveTimeIndicator(dates), timeLineOffset: widget.timeLineOffset, timeLineWidth: _timeLineWidth, verticalLineOffset: 0, - showVerticalLine: true, + showVerticalLine: widget.showVerticalLines, controller: controller, hourHeight: _hourHeight, scrollController: _scrollController, @@ -528,6 +551,7 @@ class WeekViewState extends State> { _weekNumberBuilder = widget.weekNumberBuilder ?? _defaultWeekNumberBuilder; _fullDayEventBuilder = widget.fullDayEventBuilder ?? _defaultFullDayEventBuilder; + _hourLinePainter = widget.hourLinePainter ?? _defaultHourLinePainter; } Widget _defaultFullDayEventBuilder( @@ -710,28 +734,59 @@ class WeekViewState extends State> { /// Default view header builder. This builder will be used if /// [widget.dayTitleBuilder] is null. - Widget _defaultWeekPageHeaderBuilder(DateTime startDate, DateTime endDate) { + Widget _defaultWeekPageHeaderBuilder( + DateTime startDate, + DateTime endDate, + ) { return WeekPageHeader( startDate: _currentStartDate, endDate: _currentEndDate, onNextDay: nextPage, onPreviousDay: previousPage, onTitleTapped: () async { - final selectedDate = await showDatePicker( - context: context, - initialDate: startDate, - firstDate: _minDate, - lastDate: _maxDate, - ); - - if (selectedDate == null) return; - jumpToWeek(selectedDate); + if (widget.onHeaderTitleTap != null) { + widget.onHeaderTitleTap!(startDate); + } else { + final selectedDate = await showDatePicker( + context: context, + initialDate: startDate, + firstDate: _minDate, + lastDate: _maxDate, + ); + + if (selectedDate == null) return; + jumpToWeek(selectedDate); + } }, headerStringBuilder: widget.headerStringBuilder, headerStyle: widget.headerStyle, ); } + HourLinePainter _defaultHourLinePainter( + Color lineColor, + double lineHeight, + double offset, + double minuteHeight, + bool showVerticalLine, + double verticalLineOffset, + LineStyle lineStyle, + double dashWidth, + double dashSpaceWidth, + ) { + return HourLinePainter( + lineColor: lineColor, + lineHeight: lineHeight, + offset: offset, + minuteHeight: minuteHeight, + verticalLineOffset: verticalLineOffset, + showVerticalLine: showVerticalLine, + lineStyle: lineStyle, + dashWidth: dashWidth, + dashSpaceWidth: dashSpaceWidth, + ); + } + /// Called when user change page using any gesture or inbuilt functions. void _onPageChange(int index) { if (mounted) {