diff --git a/CHANGELOG.md b/CHANGELOG.md index 88551ec0..c1bbfb58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# [2.0.0 - Unreleased] + +- Adds flag `showEndHours` to show start and end time. [#267](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/267) + - Introduced 2 new typedefs `TimeLineTimeBuilder` and `TimeStringBuilder`. +### Breaking Changes +- Use `TimeLineTimeBuilder` instead of `DateWidgetBuilder` to show time widget in timer line for `WeekView` and `DayView`. +- User `TimeStringBuilder` instead of `StringProvider` to get the time string in time line for `WeekView` and `DayView`. + # [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) @@ -211,4 +219,4 @@ # [0.0.1 - 26 Aug 2021](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/0.0.1) -- Initial release +- Initial release \ No newline at end of file diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 9a0c28fc..5a8d0ad4 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -127,7 +127,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3db53b6e..b52b2e69 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ _events = [ date: _now, title: "Project meeting", description: "Today is project meeting.", - startTime: DateTime(_now.year, _now.month, _now.day, 18, 30), - endTime: DateTime(_now.year, _now.month, _now.day, 22), + startTime: DateTime(_now.year, _now.month, _now.day, 0, 0), + endTime: DateTime(_now.year, _now.month, _now.day, 4, 0), ), CalendarEventData( date: _now.subtract(Duration(days: 3)), diff --git a/example/lib/widgets/day_view_widget.dart b/example/lib/widgets/day_view_widget.dart index a02c189f..8dd5b063 100644 --- a/example/lib/widgets/day_view_widget.dart +++ b/example/lib/widgets/day_view_widget.dart @@ -21,7 +21,7 @@ class DayViewWidget extends StatelessWidget { startDuration: Duration(hours: 8), showHalfHours: true, heightPerMinute: 3, - timeLineBuilder: _timeLineBuilder, + // timeLineBuilder: _timeLineBuilder, scrollPhysics: const BouncingScrollPhysics(), eventArranger: SideEventArranger(maxWidth: 30), hourIndicatorSettings: HourIndicatorSettings( @@ -33,6 +33,7 @@ class DayViewWidget extends StatelessWidget { ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }, + showQuarterHours: true, onEventTap: (events, date) { Navigator.of(context).push( MaterialPageRoute( @@ -57,14 +58,16 @@ class DayViewWidget extends StatelessWidget { liveTimeIndicatorSettings: LiveTimeIndicatorSettings( color: Colors.redAccent, showBullet: false, - showTime: true, - showTimeBackgroundView: true, + showTime: false, + showTimeBackgroundView: false, ), + showEndHours: true, + showStartHours: true, ); } - Widget _timeLineBuilder(DateTime date) { - if (date.minute != 0) { + Widget _timeLineBuilder(TimeOfDay time, DateTime _) { + if (time.minute != 0) { return Stack( clipBehavior: Clip.none, children: [ @@ -72,7 +75,7 @@ class DayViewWidget extends StatelessWidget { top: -8, right: 8, child: Text( - "${date.hour}:${date.minute}", + "${time.hour}:${time.minute}", textAlign: TextAlign.right, style: TextStyle( color: Colors.black.withAlpha(50), @@ -85,7 +88,40 @@ class DayViewWidget extends StatelessWidget { ); } - final hour = ((date.hour - 1) % 12) + 1; + final hour = ((time.hour - 1) % 12) + 1; + + if (time.hour == 0 && time.minute == 0) { + return Stack( + clipBehavior: Clip.none, + children: [ + Positioned.fill( + top: -7, + right: 8, + child: Text( + "$hour ${time.hour ~/ 12 == 0 ? "am" : "pm"}", + textAlign: TextAlign.right, + ), + ), + ], + ); + } + + if (time.hour == 24 && time.minute == 0) { + return Stack( + clipBehavior: Clip.none, + children: [ + Positioned.fill( + top: -18, + right: 8, + child: Text( + "$hour ${time.hour ~/ 12 == 0 ? "am" : "pm"}", + textAlign: TextAlign.right, + ), + ), + ], + ); + } + return Stack( clipBehavior: Clip.none, children: [ @@ -93,7 +129,7 @@ class DayViewWidget extends StatelessWidget { top: -8, right: 8, child: Text( - "$hour ${date.hour ~/ 12 == 0 ? "am" : "pm"}", + "$hour ${time.hour ~/ 12 == 0 ? "am" : "pm"}", textAlign: TextAlign.right, ), ), diff --git a/example/lib/widgets/event_provider.dart b/example/lib/widgets/event_provider.dart deleted file mode 100644 index 8b137891..00000000 --- a/example/lib/widgets/event_provider.dart +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/src/components/_internal_components.dart b/lib/src/components/_internal_components.dart index a13bd432..9fdd9d12 100644 --- a/lib/src/components/_internal_components.dart +++ b/lib/src/components/_internal_components.dart @@ -41,6 +41,8 @@ class LiveTimeIndicator extends StatefulWidget { /// This field will be used to set end hour for day and week view final int endHour; + final EdgeInsets padding; + /// Widget to display tile line according to current time. const LiveTimeIndicator({ Key? key, @@ -51,6 +53,7 @@ class LiveTimeIndicator extends StatefulWidget { required this.heightPerMinute, required this.startHour, this.endHour = Constants.hoursADay, + required this.padding, }) : super(key: key); @override @@ -59,7 +62,7 @@ class LiveTimeIndicator extends StatefulWidget { class _LiveTimeIndicatorState extends State { late Timer _timer; - late TimeOfDay _currentTime = TimeOfDay.now(); + late TimeOfDay _currentTime = TimeOfDay(hour: 24, minute: 0); @override void initState() { @@ -78,7 +81,7 @@ class _LiveTimeIndicatorState extends State { /// This will rebuild TimeLineIndicator every second. This will allow us /// to indicate live time in Week and Day view. void _onTick(Timer? timer) { - final time = TimeOfDay.now(); + final time = TimeOfDay(hour: 24, minute: 0); if (time != _currentTime && mounted) { _currentTime = time; setState(() {}); @@ -104,9 +107,10 @@ class _LiveTimeIndicatorState extends State { /// e.g. startHour : 1:00, endHour : 13:00 and live time is 17:00 /// then no need to display live time indicator on timeline if (_currentTime.hour > widget.startHour && - widget.endHour <= _currentTime.hour) { + widget.endHour < _currentTime.hour) { return SizedBox.shrink(); } + return CustomPaint( size: Size(widget.width, widget.liveTimeIndicatorSettings.height), painter: CurrentTimeLinePainter( @@ -125,6 +129,7 @@ class _LiveTimeIndicatorState extends State { bulletRadius: widget.liveTimeIndicatorSettings.bulletRadius, timeBackgroundViewWidth: widget.liveTimeIndicatorSettings.timeBackgroundViewWidth, + padding: widget.padding, ), ); } @@ -145,7 +150,7 @@ class TimeLine extends StatefulWidget { final double timeLineOffset; /// This will display time string in timeline. - final DateWidgetBuilder timeLineBuilder; + final TimeLineTimeBuilder timeLineBuilder; /// This method will be called when user taps on timestamp in timeline. final TimestampCallback? onTimestampTap; @@ -170,6 +175,14 @@ class TimeLine extends StatefulWidget { /// This field will be used to set end hour for day and week view final int endHour; + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showEndHours; + + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showStartHours; + + final EdgeInsets padding; + /// Time line to display time at left side of day or week view. const TimeLine({ Key? key, @@ -184,6 +197,9 @@ class TimeLine extends StatefulWidget { this.showQuarterHours = false, required this.liveTimeIndicatorSettings, this.endHour = Constants.hoursADay, + required this.showEndHours, + required this.showStartHours, + required this.padding, }) : super(key: key); @override @@ -200,24 +216,6 @@ class _TimeLineState extends State { _timer = Timer.periodic(Duration(seconds: 1), _onTick); } - @override - void dispose() { - _timer.cancel(); - super.dispose(); - } - - /// Creates an recursive call that runs every 1 seconds. - /// This will rebuild TimeLine every second. This will allow us - /// to show/hide time line when there is overlap with - /// live time line indicator in Week and Day view. - void _onTick(Timer? timer) { - final time = TimeOfDay.now(); - if (time != _currentTime && mounted) { - _currentTime = time; - setState(() {}); - } - } - @override Widget build(BuildContext context) { return ConstrainedBox( @@ -230,13 +228,17 @@ class _TimeLineState extends State { ), child: Stack( children: [ - for (int i = widget.startHour + 1; i < widget.endHour; i++) + for (int i = widget.startHour + (widget.showStartHours ? 0 : 1); + i < widget.endHour + (widget.showEndHours ? 1 : 0); + i++) _timelinePositioned( topPosition: widget.hourHeight * (i - widget.startHour) - - widget.timeLineOffset, + widget.timeLineOffset + + widget.padding.top, bottomPosition: widget.height - (widget.hourHeight * (i - widget.startHour + 1)) + - widget.timeLineOffset, + widget.timeLineOffset - + widget.padding.bottom, hour: i, ), if (widget.showHalfHours) @@ -244,10 +246,12 @@ class _TimeLineState extends State { _timelinePositioned( topPosition: widget.hourHeight * (i - widget.startHour) - widget.timeLineOffset + - widget._halfHourHeight, + widget._halfHourHeight + + widget.padding.top, bottomPosition: widget.height - (widget.hourHeight * (i - widget.startHour + 1)) + - widget.timeLineOffset, + widget.timeLineOffset - + widget.padding.bottom, hour: i, minutes: 30, ), @@ -257,10 +261,12 @@ class _TimeLineState extends State { _timelinePositioned( topPosition: widget.hourHeight * (i - widget.startHour) - widget.timeLineOffset + - widget.hourHeight * 0.25, + widget.hourHeight * 0.25 + + widget.padding.top, bottomPosition: widget.height - (widget.hourHeight * (i - widget.startHour + 1)) + - widget.timeLineOffset, + widget.timeLineOffset - + widget.padding.bottom, hour: i, minutes: 15, ), @@ -269,10 +275,12 @@ class _TimeLineState extends State { _timelinePositioned( topPosition: widget.hourHeight * (i - widget.startHour) - widget.timeLineOffset + - widget.hourHeight * 0.75, + widget.hourHeight * 0.75 + + widget.padding.top, bottomPosition: widget.height - (widget.hourHeight * (i - widget.startHour + 1)) + - widget.timeLineOffset, + widget.timeLineOffset - + widget.padding.bottom, hour: i, minutes: 45, ), @@ -282,6 +290,24 @@ class _TimeLineState extends State { ); } + @override + void dispose() { + _timer.cancel(); + super.dispose(); + } + + /// Creates an recursive call that runs every 1 seconds. + /// This will rebuild TimeLine every second. This will allow us + /// to show/hide time line when there is overlap with + /// live time line indicator in Week and Day view. + void _onTick(Timer? timer) { + final time = TimeOfDay.now(); + if (time != _currentTime && mounted) { + _currentTime = time; + setState(() {}); + } + } + /// To avoid overlap of live time line indicator, show time line when /// current min is less than 45 min and is previous hour or /// current min is greater than 15 min and is current hour @@ -309,7 +335,7 @@ class _TimeLineState extends State { left: 0, right: 0, bottom: bottomPosition, - child: Container( + child: SizedBox( height: widget.hourHeight, width: widget.timeLineWidth, child: InkWell( @@ -318,7 +344,14 @@ class _TimeLineState extends State { widget.onTimestampTap!(dateTime); } }, - child: widget.timeLineBuilder.call(dateTime), + child: widget.timeLineBuilder.call( + TimeOfDay(hour: hour, minute: minutes), + DateTime( + TimeLine._date.year, + TimeLine._date.month, + TimeLine._date.day, + ), + ), ), ), ), diff --git a/lib/src/components/common_components.dart b/lib/src/components/common_components.dart index cf2f7f29..0d90e21f 100644 --- a/lib/src/components/common_components.dart +++ b/lib/src/components/common_components.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import '../calendar_event_data.dart'; -import '../constants.dart'; import '../enumerations.dart'; import '../extensions.dart'; import '../typedefs.dart'; @@ -23,6 +22,8 @@ class DefaultPressDetector extends StatelessWidget { this.onDateTap, this.onDateLongPress, this.startHour = 0, + required this.padding, + required this.endHour, }); final DateTime date; @@ -33,11 +34,13 @@ class DefaultPressDetector extends StatelessWidget { final DateTapCallback? onDateTap; final DatePressCallback? onDateLongPress; final int startHour; + final int endHour; + final EdgeInsets padding; @override Widget build(BuildContext context) { final heightPerSlot = minuteSlotSize.minutes * heightPerMinute; - final slots = (Constants.hoursADay * 60) ~/ minuteSlotSize.minutes; + final slots = ((endHour - startHour) * 60) ~/ minuteSlotSize.minutes; return SizedBox( height: height, @@ -46,10 +49,10 @@ class DefaultPressDetector extends StatelessWidget { children: [ for (int i = 0; i < slots; i++) Positioned( - top: heightPerSlot * i, + top: padding.top + heightPerSlot * i, left: 0, right: 0, - bottom: height - (heightPerSlot * (i + 1)), + bottom: height - (heightPerSlot * (i + 1)) - padding.bottom, child: GestureDetector( behavior: HitTestBehavior.translucent, onLongPress: () => onDateLongPress?.call( diff --git a/lib/src/components/day_view_components.dart b/lib/src/components/day_view_components.dart index b8e28e9e..147eac10 100644 --- a/lib/src/components/day_view_components.dart +++ b/lib/src/components/day_view_components.dart @@ -111,11 +111,14 @@ class RoundedEventTile extends StatelessWidget { } class DefaultTimeLineMark extends StatelessWidget { - /// Defines time to display + /// Defines the date for which the time if being displayed. final DateTime date; - /// StringProvider for time string - final StringProvider? timeStringBuilder; + // Defines the time to show. + final TimeOfDay time; + + /// String provider for time string + final TimeStringBuilder? timeStringBuilder; /// Text style for time string. final TextStyle? markingStyle; @@ -124,20 +127,22 @@ class DefaultTimeLineMark extends StatelessWidget { const DefaultTimeLineMark({ Key? key, required this.date, + required this.time, this.markingStyle, this.timeStringBuilder, }) : super(key: key); @override Widget build(BuildContext context) { - final hour = ((date.hour - 1) % 12) + 1; + final hour = ((time.hour - 1) % 12) + 1; final timeString = (timeStringBuilder != null) - ? timeStringBuilder!(date) - : date.minute != 0 - ? "$hour:${date.minute}" - : "$hour ${date.hour ~/ 12 == 0 ? "am" : "pm"}"; + ? timeStringBuilder!(time, date) + : time.minute != 0 + ? "$hour:${time.minute}" + : "$hour ${time.hour ~/ 12 == 0 ? "am" : "pm"}"; + return Transform.translate( - offset: Offset(0, -7.5), + offset: Offset(0, -8), child: Padding( padding: const EdgeInsets.only(right: 7.0), child: Text( diff --git a/lib/src/day_view/_internal_day_view_page.dart b/lib/src/day_view/_internal_day_view_page.dart index 28424c74..4ddb138e 100644 --- a/lib/src/day_view/_internal_day_view_page.dart +++ b/lib/src/day_view/_internal_day_view_page.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a MIT-style license // that can be found in the LICENSE file. +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../components/_internal_components.dart'; @@ -31,7 +32,7 @@ class InternalDayViewPage extends StatefulWidget { final EventController controller; /// A builder that builds time line. - final DateWidgetBuilder timeLineBuilder; + final TimeLineTimeBuilder timeLineBuilder; /// Builds custom PressDetector widget final DetectorBuilder dayDetectorBuilder; @@ -138,6 +139,15 @@ class InternalDayViewPage extends StatefulWidget { final TimestampCallback? onTimestampTap; + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showEndHours; + + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showStartHours; + + /// + final EdgeInsets pagePadding; + /// Defines a single day page. const InternalDayViewPage({ Key? key, @@ -180,6 +190,9 @@ class InternalDayViewPage extends StatefulWidget { required this.onTileDoubleTap, required this.onTimestampTap, this.keepScrollOffset = false, + required this.showEndHours, + required this.showStartHours, + required this.pagePadding, }) : super(key: key); @override @@ -252,6 +265,9 @@ class _InternalDayViewPageState widget.emulateVerticalOffsetBy, widget.startHour, widget.endHour, + widget.showStartHours, + widget.showEndHours, + widget.pagePadding, ), ), if (widget.showHalfHours) @@ -269,6 +285,10 @@ class _InternalDayViewPageState widget.halfHourIndicatorSettings.dashSpaceWidth, startHour: widget.startHour, endHour: widget.endHour, + + showStartHour: widget.showStartHours, + showEndHour: widget.showEndHours, + padding: widget.pagePadding, ), ), if (widget.showQuarterHours) @@ -287,6 +307,9 @@ class _InternalDayViewPageState widget.quarterHourIndicatorSettings.dashWidth, dashSpaceWidth: widget .quarterHourIndicatorSettings.dashSpaceWidth, + padding: widget.pagePadding, + showEndHour: widget.showEndHours, + showStartHour: widget.showStartHours, ), ), widget.dayDetectorBuilder( @@ -295,67 +318,75 @@ class _InternalDayViewPageState heightPerMinute: widget.heightPerMinute, date: widget.date, minuteSlotSize: widget.minuteSlotSize, + pagePadding: widget.pagePadding, + ), - Align( - alignment: Alignment.centerRight, - child: EventGenerator( - height: widget.height, - date: widget.date, - onTileLongTap: widget.onTileLongTap, - onTileDoubleTap: widget.onTileDoubleTap, - onTileTap: widget.onTileTap, - eventArranger: widget.eventArranger, - events: widget.controller.getEventsOnDay( - widget.date, - includeFullDayEvents: false, + Padding( + padding: widget.pagePadding, + + child: Align( + alignment: Alignment.centerRight, + child: EventGenerator( + height: widget.height - widget.pagePadding.vertical, + date: widget.date, + onTileLongTap: widget.onTileLongTap, + onTileDoubleTap: widget.onTileDoubleTap, + onTileTap: widget.onTileTap, + eventArranger: widget.eventArranger, + events: widget.controller.getEventsOnDay( + widget.date, + includeFullDayEvents: false, + ), + heightPerMinute: widget.heightPerMinute, + eventTileBuilder: widget.eventTileBuilder, + scrollNotifier: widget.scrollNotifier, + startHour: widget.startHour, + endHour: widget.endHour, + width: widget.width - + widget.timeLineWidth - + widget.hourIndicatorSettings.offset - + widget.verticalLineOffset, ), + ), + ), + ), + TimeLine( + height: widget.height, + hourHeight: widget.hourHeight, + timeLineBuilder: widget.timeLineBuilder, + timeLineOffset: widget.timeLineOffset, + timeLineWidth: widget.timeLineWidth, + showHalfHours: widget.showHalfHours, + startHour: widget.startHour, + endHour: widget.endHour, + showQuarterHours: widget.showQuarterHours, + key: ValueKey(widget.heightPerMinute), + liveTimeIndicatorSettings: widget.liveTimeIndicatorSettings, + showEndHours: widget.showEndHours, + showStartHours: widget.showStartHours, + padding: widget.pagePadding, + onTimestampTap: widget.onTimestampTap,), + if (widget.showLiveLine && + widget.liveTimeIndicatorSettings.height > 0) + IgnorePointer( + child: LiveTimeIndicator( + liveTimeIndicatorSettings: + widget.liveTimeIndicatorSettings, + width: widget.width, + height: widget.height, heightPerMinute: widget.heightPerMinute, - eventTileBuilder: widget.eventTileBuilder, - scrollNotifier: widget.scrollNotifier, + timeLineWidth: widget.timeLineWidth, startHour: widget.startHour, endHour: widget.endHour, - width: widget.width - - widget.timeLineWidth - - widget.hourIndicatorSettings.offset - - widget.verticalLineOffset, + padding: widget.pagePadding, ), ), - TimeLine( - height: widget.height, - hourHeight: widget.hourHeight, - timeLineBuilder: widget.timeLineBuilder, - timeLineOffset: widget.timeLineOffset, - timeLineWidth: widget.timeLineWidth, - showHalfHours: widget.showHalfHours, - startHour: widget.startHour, - endHour: widget.endHour, - showQuarterHours: widget.showQuarterHours, - key: ValueKey(widget.heightPerMinute), - liveTimeIndicatorSettings: - widget.liveTimeIndicatorSettings, - onTimestampTap: widget.onTimestampTap, - ), - if (widget.showLiveLine && - widget.liveTimeIndicatorSettings.height > 0) - IgnorePointer( - child: LiveTimeIndicator( - liveTimeIndicatorSettings: - widget.liveTimeIndicatorSettings, - width: widget.width, - height: widget.height, - heightPerMinute: widget.heightPerMinute, - timeLineWidth: widget.timeLineWidth, - startHour: widget.startHour, - endHour: widget.endHour, - ), - ), - ], - ), + ], ), ), ), - ], - ), + ), + ], ); } } diff --git a/lib/src/day_view/day_view.dart b/lib/src/day_view/day_view.dart index 35e76bf4..e621aeb7 100644 --- a/lib/src/day_view/day_view.dart +++ b/lib/src/day_view/day_view.dart @@ -22,14 +22,14 @@ class DayView extends StatefulWidget { /// A function to generate the TimeString in the timeline. /// Useful for I18n - final StringProvider? timeStringBuilder; + final TimeStringBuilder? timeStringBuilder; /// A function that returns a [Widget] that will be displayed left side of /// day view. /// /// If null is provided then no time line will be visible. /// - final DateWidgetBuilder? timeLineBuilder; + final TimeLineTimeBuilder? timeLineBuilder; /// Builds day title bar. /// @@ -75,7 +75,7 @@ class DayView extends StatefulWidget { /// Pass [HourIndicatorSettings.none] to remove Hour lines. final HourIndicatorSettings? hourIndicatorSettings; - /// A funtion that returns a [CustomPainter]. + /// A function that returns a [CustomPainter]. /// /// Use this if you want to paint custom hour lines. final CustomHourLinePainter? hourLinePainter; @@ -226,6 +226,15 @@ class DayView extends StatefulWidget { /// Flag to keep scrollOffset of pages on page change final bool keepScrollOffset; + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showEndHours; + + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showStartHours; + + /// Padding used in the day's page. + final EdgeInsets? dayPagePadding; + /// Main widget for day view. const DayView({ Key? key, @@ -277,6 +286,9 @@ class DayView extends StatefulWidget { this.endHour = Constants.hoursADay, this.keepScrollOffset = false, this.onTimestampTap, + this.showEndHours = false, + this.showStartHours = false, + this.dayPagePadding, }) : assert(!(onHeaderTitleTap != null && dayTitleBuilder != null), "can't use [onHeaderTitleTap] & [dayTitleBuilder] simultaneously"), assert(timeLineOffset >= 0, @@ -329,7 +341,7 @@ class DayViewState extends State> { late PageController _pageController; - late DateWidgetBuilder _timeLineBuilder; + late TimeLineTimeBuilder _timeLineBuilder; late EventTileBuilder _eventTileBuilder; @@ -349,6 +361,8 @@ class DayViewState extends State> { final _scrollConfiguration = EventScrollConfiguration(); + late EdgeInsets _pagePadding; + @override void initState() { super.initState(); @@ -505,6 +519,9 @@ class DayViewState extends State> { scrollPhysics: widget.scrollPhysics, scrollListener: _scrollPageListener, keepScrollOffset: widget.keepScrollOffset, + showEndHours: widget.showEndHours, + showStartHours: widget.showStartHours, + pagePadding: _pagePadding, ), ); }, @@ -585,8 +602,15 @@ class DayViewState extends State> { } void _calculateHeights() { + _pagePadding = widget.dayPagePadding ?? + EdgeInsets.only( + top: widget.showStartHours ? 12 : 0, + bottom: widget.showEndHours ? 12 : 0, + ); + _hourHeight = widget.heightPerMinute * 60; - _height = _hourHeight * (widget.endHour - widget.startHour); + _height = (_hourHeight * (widget.endHour - widget.startHour)) + + _pagePadding.vertical; } void _assignBuilders() { @@ -641,6 +665,7 @@ class DayViewState extends State> { required double width, required double heightPerMinute, required MinuteSlotSize minuteSlotSize, + required EdgeInsets pagePadding, }) => DefaultPressDetector( date: date, @@ -651,13 +676,19 @@ class DayViewState extends State> { onDateTap: widget.onDateTap, onDateLongPress: widget.onDateLongPress, startHour: widget.startHour, + endHour: widget.endHour, + padding: pagePadding, ); /// Default timeline builder this builder will be used if /// [widget.eventTileBuilder] is null /// - Widget _defaultTimeLineBuilder(date) => DefaultTimeLineMark( - date: date, timeStringBuilder: widget.timeStringBuilder); + Widget _defaultTimeLineBuilder(TimeOfDay time, DateTime date) => + DefaultTimeLineMark( + time: time, + date: date, + timeStringBuilder: widget.timeStringBuilder, + ); /// Default timeline builder. This builder will be used if /// [widget.eventTileBuilder] is null @@ -728,6 +759,9 @@ class DayViewState extends State> { double emulateVerticalOffsetBy, int startHour, int endHour, + bool showStartHour, + bool showEndHour, + EdgeInsets padding, ) { return HourLinePainter( lineColor: lineColor, @@ -742,6 +776,9 @@ class DayViewState extends State> { emulateVerticalOffsetBy: emulateVerticalOffsetBy, startHour: startHour, endHour: endHour, + showStartHour: showStartHour, + showEndHour: showEndHour, + padding: padding, ); } diff --git a/lib/src/painters.dart b/lib/src/painters.dart index 4498bfb3..e3b74216 100644 --- a/lib/src/painters.dart +++ b/lib/src/painters.dart @@ -47,6 +47,10 @@ class HourLinePainter extends CustomPainter { /// This field will be used to set end hour for day and week view final int endHour; + final bool showStartHour; + final bool showEndHour; + final EdgeInsets padding; + /// Paints 24 hour lines. HourLinePainter({ required this.lineColor, @@ -61,17 +65,25 @@ class HourLinePainter extends CustomPainter { this.lineStyle = LineStyle.solid, this.dashWidth = 4, this.dashSpaceWidth = 4, + required this.padding, + required this.showEndHour, + required this.showStartHour, }); @override void paint(Canvas canvas, Size size) { + final startOffset = padding.top; final dx = offset + emulateVerticalOffsetBy; final paint = Paint() ..color = lineColor ..strokeWidth = lineHeight; - for (var i = startHour + 1; i < endHour; i++) { - final dy = (i - startHour) * minuteHeight * 60; + final start = startHour + (showStartHour ? 0 : 1); + final end = endHour + (showEndHour ? 1 : 0); + + for (var i = start; i < end; i++) { + final dy = startOffset + ((i - startHour) * minuteHeight * 60); + if (lineStyle == LineStyle.dashed) { var startX = dx; while (startX < size.width) { @@ -84,6 +96,7 @@ class HourLinePainter extends CustomPainter { } } + // Make separate painter for this. if (showVerticalLine) { if (lineStyle == LineStyle.dashed) { var startY = 0.0; @@ -138,6 +151,10 @@ class HalfHourLinePainter extends CustomPainter { /// This field will be used to set end hour for day and week view final int endHour; + final bool showStartHour; + final bool showEndHour; + final EdgeInsets padding; + /// Paint half hour lines HalfHourLinePainter({ required this.lineColor, @@ -149,16 +166,23 @@ class HalfHourLinePainter extends CustomPainter { this.dashWidth = 4, this.dashSpaceWidth = 4, this.endHour = Constants.hoursADay, + required this.showStartHour, + required this.showEndHour, + required this.padding, }); @override void paint(Canvas canvas, Size size) { + final startOffset = padding.top; + final paint = Paint() ..color = lineColor ..strokeWidth = lineHeight; for (var i = startHour; i < endHour; i++) { - final dy = (i - startHour) * minuteHeight * 60 + (minuteHeight * 30); + final dy = (i - startHour) * minuteHeight * 60 + + (minuteHeight * 30) + + startOffset; if (lineStyle == LineStyle.dashed) { var startX = offset; while (startX < size.width) { @@ -205,6 +229,10 @@ class QuarterHourLinePainter extends CustomPainter { /// Line dash space width when using the [LineStyle.dashed] style final double dashSpaceWidth; + final bool showStartHour; + final bool showEndHour; + final EdgeInsets padding; + /// Paint quarter hour lines QuarterHourLinePainter({ required this.lineColor, @@ -214,17 +242,22 @@ class QuarterHourLinePainter extends CustomPainter { required this.lineStyle, this.dashWidth = 4, this.dashSpaceWidth = 4, + required this.padding, + required this.showEndHour, + required this.showStartHour, }); @override void paint(Canvas canvas, Size size) { + final startOffset = padding.top; + final paint = Paint() ..color = lineColor ..strokeWidth = lineHeight; for (var i = 0; i < Constants.hoursADay; i++) { - final dy1 = i * minuteHeight * 60 + (minuteHeight * 15); - final dy2 = i * minuteHeight * 60 + (minuteHeight * 45); + final dy1 = i * minuteHeight * 60 + (minuteHeight * 15) + startOffset; + final dy2 = i * minuteHeight * 60 + (minuteHeight * 45) + startOffset; if (lineStyle == LineStyle.dashed) { var startX = offset; @@ -283,6 +316,8 @@ class CurrentTimeLinePainter extends CustomPainter { /// Width of time backgroud view. final double timeBackgroundViewWidth; + final EdgeInsets padding; + /// Paints a single horizontal line at [offset]. CurrentTimeLinePainter({ required this.showBullet, @@ -294,13 +329,16 @@ class CurrentTimeLinePainter extends CustomPainter { required this.showTime, required this.showTimeBackgroundView, required this.timeBackgroundViewWidth, + required this.padding, }); @override void paint(Canvas canvas, Size size) { + final top = offset.dy + padding.top; + canvas.drawLine( - Offset(offset.dx - (showBullet ? 0 : 8), offset.dy), - Offset(size.width, offset.dy), + Offset(offset.dx - (showBullet ? 0 : 8), top), + Offset(size.width, top), Paint() ..color = color ..strokeWidth = height, @@ -308,7 +346,7 @@ class CurrentTimeLinePainter extends CustomPainter { if (showBullet) { canvas.drawCircle( - Offset(offset.dx, offset.dy), bulletRadius, Paint()..color = color); + Offset(offset.dx, top), bulletRadius, Paint()..color = color); } if (showTimeBackgroundView) { @@ -316,7 +354,7 @@ class CurrentTimeLinePainter extends CustomPainter { RRect.fromRectAndRadius( Rect.fromLTWH( max(3, offset.dx - 68), - offset.dy - 11, + top - 11, timeBackgroundViewWidth, 24, ), @@ -341,7 +379,7 @@ class CurrentTimeLinePainter extends CustomPainter { ), ) ..layout() - ..paint(canvas, Offset(offset.dx - 62, offset.dy - 6)); + ..paint(canvas, Offset(offset.dx - 62, top - 6)); } } diff --git a/lib/src/typedefs.dart b/lib/src/typedefs.dart index 9c51397d..3357a816 100644 --- a/lib/src/typedefs.dart +++ b/lib/src/typedefs.dart @@ -28,6 +28,7 @@ typedef DetectorBuilder = Widget Function({ required double width, required double heightPerMinute, required MinuteSlotSize minuteSlotSize, + required EdgeInsets pagePadding, }); typedef WeekDayBuilder = Widget Function( @@ -36,6 +37,8 @@ typedef WeekDayBuilder = Widget Function( typedef DateWidgetBuilder = Widget Function(DateTime date); +typedef TimeLineTimeBuilder = Widget Function(TimeOfDay time, DateTime date); + typedef HeaderTitleCallback = Future Function(DateTime date); typedef WeekNumberBuilder = Widget? Function( @@ -55,6 +58,8 @@ typedef PageChangeCallback = void Function( typedef StringProvider = String Function(DateTime date, {DateTime? secondaryDate}); +typedef TimeStringBuilder = String Function(TimeOfDay time, DateTime date); + typedef WeekPageHeaderBuilder = Widget Function( DateTime startDate, DateTime endDate, @@ -92,6 +97,9 @@ typedef CustomHourLinePainter = CustomPainter Function( double emulateVerticalOffsetBy, int startHour, int endHour, + bool showStartHour, + bool showEndHour, + EdgeInsets padding, ); typedef TestPredicate = bool Function(T element); diff --git a/lib/src/week_view/_internal_week_view_page.dart b/lib/src/week_view/_internal_week_view_page.dart index 85d36b54..cc0ce091 100644 --- a/lib/src/week_view/_internal_week_view_page.dart +++ b/lib/src/week_view/_internal_week_view_page.dart @@ -4,15 +4,9 @@ import 'package:flutter/material.dart'; +import '../../calendar_view.dart'; import '../components/_internal_components.dart'; -import '../components/event_scroll_notifier.dart'; -import '../components/week_view_components.dart'; -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. class InternalWeekViewPage extends StatefulWidget { @@ -33,7 +27,7 @@ class InternalWeekViewPage extends StatefulWidget { final EventController controller; /// A builder to build time line. - final DateWidgetBuilder timeLineBuilder; + final TimeLineTimeBuilder timeLineBuilder; /// Settings for hour indicator lines. final HourIndicatorSettings hourIndicatorSettings; @@ -166,6 +160,14 @@ class InternalWeekViewPage extends StatefulWidget { /// This method will be called when user taps on timestamp in timeline. final TimestampCallback? onTimestampTap; + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showEndHours; + + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showStartHours; + + final EdgeInsets pagePadding; + /// A single page for week view. const InternalWeekViewPage({ Key? key, @@ -216,6 +218,9 @@ class InternalWeekViewPage extends StatefulWidget { required this.weekViewScrollController, this.lastScrollOffset = 0.0, this.keepScrollOffset = false, + required this.showEndHours, + required this.showStartHours, + required this.pagePadding, }) : super(key: key); @override @@ -251,254 +256,277 @@ class _InternalWeekViewPageState @override Widget build(BuildContext context) { final filteredDates = _filteredDate(); - return Container( + return SizedBox( height: widget.height + widget.weekTitleHeight, width: widget.width, - child: Column( - verticalDirection: widget.showWeekDayAtBottom - ? VerticalDirection.up - : VerticalDirection.down, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - SizedBox( - width: widget.width, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: widget.weekTitleHeight, - width: widget.timeLineWidth + - widget.hourIndicatorSettings.offset, - child: widget.weekNumberBuilder.call(filteredDates[0]), - ), - ...List.generate( - filteredDates.length, - (index) => SizedBox( - height: widget.weekTitleHeight, - width: widget.weekTitleWidth, - child: widget.weekDayBuilder( - filteredDates[index], - ), - ), - ) - ], - ), - ), - Divider( - thickness: 1, - height: 1, - ), - SizedBox( - width: widget.width, - child: Container( - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: widget.hourIndicatorSettings.color, - width: 2, - ), - ), - ), + child: Padding( + padding: widget.pagePadding, + child: Column( + verticalDirection: widget.showWeekDayAtBottom + ? VerticalDirection.up + : VerticalDirection.down, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + SizedBox( + width: widget.width, child: Row( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( + height: widget.weekTitleHeight, width: widget.timeLineWidth + widget.hourIndicatorSettings.offset, - child: widget.fullDayHeaderTitle.isNotEmpty - ? Padding( - padding: const EdgeInsets.symmetric( - vertical: 2, - horizontal: 1, - ), - child: Text( - widget.fullDayHeaderTitle, - textAlign: - widget.fullDayHeaderTextConfig.textAlign, - maxLines: widget.fullDayHeaderTextConfig.maxLines, - overflow: - widget.fullDayHeaderTextConfig.textOverflow, - ), - ) - : SizedBox.shrink(), + child: widget.weekNumberBuilder.call(filteredDates[0]), ), ...List.generate( filteredDates.length, - (index) { - final fullDayEventList = widget.controller - .getFullDayEvent(filteredDates[index]); - return Container( - width: widget.weekTitleWidth, - child: fullDayEventList.isEmpty - ? null - : widget.fullDayEventBuilder.call( - fullDayEventList, - widget.dates[index], - ), - ); - }, + (index) => SizedBox( + height: widget.weekTitleHeight, + width: widget.weekTitleWidth, + child: widget.weekDayBuilder( + filteredDates[index], + ), + ), ) ], ), ), - ), - Expanded( - child: SingleChildScrollView( - controller: widget.keepScrollOffset - ? scrollController - : widget.weekViewScrollController, - physics: widget.scrollPhysics, - child: SizedBox( - height: widget.height, - width: widget.width, - child: Stack( + Divider( + thickness: 1, + height: 1, + ), + SizedBox( + width: widget.width, + child: Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: widget.hourIndicatorSettings.color, + width: 2, + ), + ), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, children: [ - CustomPaint( - size: Size(widget.width, widget.height), - painter: HourLinePainter( - lineColor: widget.hourIndicatorSettings.color, - lineHeight: widget.hourIndicatorSettings.height, - offset: widget.timeLineWidth + - widget.hourIndicatorSettings.offset, - minuteHeight: widget.heightPerMinute, - verticalLineOffset: widget.verticalLineOffset, - showVerticalLine: widget.showVerticalLine, - lineStyle: widget.hourIndicatorSettings.lineStyle, - dashWidth: widget.hourIndicatorSettings.dashWidth, - dashSpaceWidth: - widget.hourIndicatorSettings.dashSpaceWidth, - emulateVerticalOffsetBy: widget.emulateVerticalOffsetBy, - startHour: widget.startHour, - endHour: widget.endHour, - ), + SizedBox( + width: widget.timeLineWidth + + widget.hourIndicatorSettings.offset, + child: widget.fullDayHeaderTitle.isNotEmpty + ? Padding( + padding: const EdgeInsets.symmetric( + vertical: 2, + horizontal: 1, + ), + child: Text( + widget.fullDayHeaderTitle, + textAlign: + widget.fullDayHeaderTextConfig.textAlign, + maxLines: + widget.fullDayHeaderTextConfig.maxLines, + overflow: + widget.fullDayHeaderTextConfig.textOverflow, + ), + ) + : SizedBox.shrink(), ), - if (widget.showHalfHours) + ...List.generate( + filteredDates.length, + (index) { + final fullDayEventList = widget.controller + .getFullDayEvent(filteredDates[index]); + return Container( + width: widget.weekTitleWidth, + child: fullDayEventList.isEmpty + ? null + : widget.fullDayEventBuilder.call( + fullDayEventList, + widget.dates[index], + ), + ); + }, + ) + ], + ), + ), + ), + Expanded( + child: SingleChildScrollView( + controller: widget.keepScrollOffset + ? scrollController + : widget.weekViewScrollController, + physics: widget.scrollPhysics, + child: SizedBox( + height: widget.height, + width: widget.width, + child: Stack( + children: [ CustomPaint( size: Size(widget.width, widget.height), - painter: HalfHourLinePainter( - lineColor: widget.halfHourIndicatorSettings.color, - lineHeight: widget.halfHourIndicatorSettings.height, + painter: HourLinePainter( + lineColor: widget.hourIndicatorSettings.color, + lineHeight: widget.hourIndicatorSettings.height, offset: widget.timeLineWidth + - widget.halfHourIndicatorSettings.offset, + widget.hourIndicatorSettings.offset, minuteHeight: widget.heightPerMinute, - lineStyle: widget.halfHourIndicatorSettings.lineStyle, - dashWidth: widget.halfHourIndicatorSettings.dashWidth, + verticalLineOffset: widget.verticalLineOffset, + showVerticalLine: widget.showVerticalLine, + lineStyle: widget.hourIndicatorSettings.lineStyle, + dashWidth: widget.hourIndicatorSettings.dashWidth, dashSpaceWidth: - widget.halfHourIndicatorSettings.dashSpaceWidth, - startHour: widget.halfHourIndicatorSettings.startHour, + widget.hourIndicatorSettings.dashSpaceWidth, + emulateVerticalOffsetBy: + widget.emulateVerticalOffsetBy, + startHour: widget.startHour, endHour: widget.endHour, + // TODO(parth): after merge changes. ), ), - if (widget.showQuarterHours) - CustomPaint( - size: Size(widget.width, widget.height), - painter: QuarterHourLinePainter( - lineColor: widget.quarterHourIndicatorSettings.color, - lineHeight: - widget.quarterHourIndicatorSettings.height, - offset: widget.timeLineWidth + - widget.quarterHourIndicatorSettings.offset, - minuteHeight: widget.heightPerMinute, - lineStyle: - widget.quarterHourIndicatorSettings.lineStyle, - dashWidth: - widget.quarterHourIndicatorSettings.dashWidth, - dashSpaceWidth: widget - .quarterHourIndicatorSettings.dashSpaceWidth, + if (widget.showHalfHours) + CustomPaint( + size: Size(widget.width, widget.height), + painter: HalfHourLinePainter( + lineColor: widget.halfHourIndicatorSettings.color, + lineHeight: widget.halfHourIndicatorSettings.height, + offset: widget.timeLineWidth + + widget.halfHourIndicatorSettings.offset, + minuteHeight: widget.heightPerMinute, + lineStyle: + widget.halfHourIndicatorSettings.lineStyle, + dashWidth: + widget.halfHourIndicatorSettings.dashWidth, + dashSpaceWidth: + widget.halfHourIndicatorSettings.dashSpaceWidth, + startHour: + widget.halfHourIndicatorSettings.startHour, + endHour: widget.endHour, + // TODO(parth): after merge changes. + ), ), - ), - Align( - alignment: Alignment.centerRight, - child: SizedBox( - width: widget.weekTitleWidth * filteredDates.length, - height: widget.height, - child: Row( - children: [ - ...List.generate( - filteredDates.length, - (index) => Container( - decoration: widget.showVerticalLine - ? BoxDecoration( - border: Border( - right: BorderSide( - color: widget - .hourIndicatorSettings.color, - width: widget - .hourIndicatorSettings.height, + if (widget.showQuarterHours) + CustomPaint( + size: Size(widget.width, widget.height), + painter: QuarterHourLinePainter( + lineColor: + widget.quarterHourIndicatorSettings.color, + lineHeight: + widget.quarterHourIndicatorSettings.height, + offset: widget.timeLineWidth + + widget.quarterHourIndicatorSettings.offset, + minuteHeight: widget.heightPerMinute, + lineStyle: + widget.quarterHourIndicatorSettings.lineStyle, + dashWidth: + widget.quarterHourIndicatorSettings.dashWidth, + dashSpaceWidth: widget + .quarterHourIndicatorSettings.dashSpaceWidth, + // TODO(parth): after merge changes. + ), + ), + Align( + alignment: Alignment.centerRight, + child: SizedBox( + width: widget.weekTitleWidth * filteredDates.length, + height: widget.height, + child: Row( + children: [ + ...List.generate( + filteredDates.length, + (index) => Container( + decoration: widget.showVerticalLine + ? BoxDecoration( + border: Border( + right: BorderSide( + color: widget + .hourIndicatorSettings.color, + width: widget + .hourIndicatorSettings.height, + ), ), + ) + : null, + height: widget.height, + width: widget.weekTitleWidth, + child: Stack( + children: [ + Padding( + padding: widget.pagePadding, + child: widget.weekDetectorBuilder( + width: widget.weekTitleWidth, + height: widget.height, + heightPerMinute: + widget.heightPerMinute, + date: widget.dates[index], + minuteSlotSize: widget.minuteSlotSize, + pagePadding: widget.pagePadding, ), - ) - : null, - height: widget.height, - width: widget.weekTitleWidth, - child: Stack( - children: [ - widget.weekDetectorBuilder( - width: widget.weekTitleWidth, - height: widget.height, - heightPerMinute: widget.heightPerMinute, - date: widget.dates[index], - minuteSlotSize: widget.minuteSlotSize, - ), - EventGenerator( - height: widget.height, - date: filteredDates[index], - onTileTap: widget.onTileTap, - onTileLongTap: widget.onTileLongTap, - onTileDoubleTap: widget.onTileDoubleTap, - width: widget.weekTitleWidth, - eventArranger: widget.eventArranger, - eventTileBuilder: widget.eventTileBuilder, - scrollNotifier: - widget.scrollConfiguration, - startHour: widget.startHour, - events: widget.controller.getEventsOnDay( - filteredDates[index], - includeFullDayEvents: false, ), - heightPerMinute: widget.heightPerMinute, - endHour: widget.endHour, - ), - ], + EventGenerator( + height: widget.height, + date: filteredDates[index], + onTileTap: widget.onTileTap, + onTileLongTap: widget.onTileLongTap, + onTileDoubleTap: widget.onTileDoubleTap, + width: widget.weekTitleWidth, + eventArranger: widget.eventArranger, + eventTileBuilder: + widget.eventTileBuilder, + scrollNotifier: + widget.scrollConfiguration, + startHour: widget.startHour, + events: + widget.controller.getEventsOnDay( + filteredDates[index], + includeFullDayEvents: false, + ), + heightPerMinute: widget.heightPerMinute, + endHour: widget.endHour, + ), + ], + ), ), - ), - ) - ], + ) + ], + ), ), ), - ), - TimeLine( - timeLineWidth: widget.timeLineWidth, - hourHeight: widget.hourHeight, - height: widget.height, - timeLineOffset: widget.timeLineOffset, - timeLineBuilder: widget.timeLineBuilder, - startHour: widget.startHour, - showHalfHours: widget.showHalfHours, - showQuarterHours: widget.showQuarterHours, - liveTimeIndicatorSettings: - widget.liveTimeIndicatorSettings, - endHour: widget.endHour, - onTimestampTap: widget.onTimestampTap, - ), - if (widget.showLiveLine && - widget.liveTimeIndicatorSettings.height > 0) - LiveTimeIndicator( - liveTimeIndicatorSettings: - widget.liveTimeIndicatorSettings, - width: widget.width, - height: widget.height, - heightPerMinute: widget.heightPerMinute, + TimeLine( timeLineWidth: widget.timeLineWidth, + hourHeight: widget.hourHeight, + height: widget.height, + timeLineOffset: widget.timeLineOffset, + timeLineBuilder: widget.timeLineBuilder, startHour: widget.startHour, + showHalfHours: widget.showHalfHours, + showQuarterHours: widget.showQuarterHours, + liveTimeIndicatorSettings: + widget.liveTimeIndicatorSettings, endHour: widget.endHour, + onTimestampTap: widget.onTimestampTap, + showEndHours: widget.showEndHours, + showStartHours: widget.showStartHours, + padding: widget.pagePadding, ), - ], + if (widget.showLiveLine && + widget.liveTimeIndicatorSettings.height > 0) + LiveTimeIndicator( + liveTimeIndicatorSettings: + widget.liveTimeIndicatorSettings, + width: widget.width, + height: widget.height, + heightPerMinute: widget.heightPerMinute, + timeLineWidth: widget.timeLineWidth, + startHour: widget.startHour, + endHour: widget.endHour, + padding: widget.pagePadding, + ), + ], + ), ), ), ), - ), - ], + ], + ), ), ); } diff --git a/lib/src/week_view/week_view.dart b/lib/src/week_view/week_view.dart index 19c651b4..76a520f2 100644 --- a/lib/src/week_view/week_view.dart +++ b/lib/src/week_view/week_view.dart @@ -25,7 +25,7 @@ class WeekView extends StatefulWidget { final EventTileBuilder? eventTileBuilder; /// Builder for timeline. - final DateWidgetBuilder? timeLineBuilder; + final TimeLineTimeBuilder? timeLineBuilder; /// Header builder for week page header. /// @@ -49,7 +49,7 @@ class WeekView extends StatefulWidget { /// This function will generate the TimeString in the timeline. /// Useful for I18n - final StringProvider? timeLineStringBuilder; + final TimeStringBuilder? timeLineStringBuilder; /// This function will generate WeekDayString in the weekday. /// Useful for I18n @@ -91,7 +91,7 @@ class WeekView extends StatefulWidget { /// Settings for hour indicator settings. final HourIndicatorSettings? hourIndicatorSettings; - /// A funtion that returns a [CustomPainter]. + /// A function that returns a [CustomPainter]. /// /// Use this if you want to paint custom hour lines. final CustomHourLinePainter? hourLinePainter; @@ -250,6 +250,14 @@ class WeekView extends StatefulWidget { /// Flag to keep scrollOffset of pages on page change final bool keepScrollOffset; + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showEndHours; + + /// Defines if we need to display the 0 hr and 24 hr text in time line or not. + final bool showStartHours; + + final EdgeInsets? weekPagePadding; + /// Main widget for week view. const WeekView({ Key? key, @@ -310,6 +318,9 @@ class WeekView extends StatefulWidget { this.fullDayHeaderTextConfig, this.keepScrollOffset = false, this.onTimestampTap, + this.showEndHours = false, + this.showStartHours = false, + this.weekPagePadding, }) : assert(!(onHeaderTitleTap != null && weekPageHeaderBuilder != null), "can't use [onHeaderTitleTap] & [weekPageHeaderBuilder] simultaneously"), assert((timeLineOffset) >= 0, @@ -365,7 +376,7 @@ class WeekViewState extends State> { late PageController _pageController; - late DateWidgetBuilder _timeLineBuilder; + late TimeLineTimeBuilder _timeLineBuilder; late EventTileBuilder _eventTileBuilder; late WeekPageHeaderBuilder _weekHeaderBuilder; late DateWidgetBuilder _weekDayBuilder; @@ -392,6 +403,8 @@ class WeekViewState extends State> { final _scrollConfiguration = EventScrollConfiguration(); + late EdgeInsets _pagePadding; + @override void initState() { super.initState(); @@ -583,6 +596,9 @@ class WeekViewState extends State> { scrollPhysics: widget.scrollPhysics, scrollListener: _scrollPageListener, keepScrollOffset: widget.keepScrollOffset, + showEndHours: widget.showEndHours, + showStartHours: widget.showStartHours, + pagePadding: _pagePadding, ), ); }, @@ -680,8 +696,14 @@ class WeekViewState extends State> { } void _calculateHeights() { + _pagePadding = widget.weekPagePadding ?? + EdgeInsets.only( + top: widget.showStartHours ? 12 : 0, + bottom: widget.showEndHours ? 12 : 0, + ); + _hourHeight = widget.heightPerMinute * 60; - _height = _hourHeight * (_endHour - _startHour); + _height = _hourHeight * (_endHour - _startHour) + _pagePadding.vertical; } void _assignBuilders() { @@ -760,6 +782,7 @@ class WeekViewState extends State> { required double width, required double heightPerMinute, required MinuteSlotSize minuteSlotSize, + required EdgeInsets pagePadding, }) => DefaultPressDetector( date: date, @@ -770,6 +793,8 @@ class WeekViewState extends State> { onDateTap: widget.onDateTap, onDateLongPress: widget.onDateLongPress, startHour: _startHour, + endHour: _endHour, + padding: pagePadding, ); /// Default builder for week line. @@ -804,8 +829,10 @@ class WeekViewState extends State> { /// Default timeline builder this builder will be used if /// [widget.eventTileBuilder] is null /// - Widget _defaultTimeLineBuilder(DateTime date) => DefaultTimeLineMark( + Widget _defaultTimeLineBuilder(TimeOfDay time, DateTime date) => + DefaultTimeLineMark( date: date, + time: time, timeStringBuilder: widget.timeLineStringBuilder, ); @@ -870,6 +897,9 @@ class WeekViewState extends State> { double emulateVerticalOffsetBy, int startHour, int endHour, + bool showStartHour, + bool showEndHour, + EdgeInsets padding, ) { return HourLinePainter( lineColor: lineColor, @@ -884,6 +914,9 @@ class WeekViewState extends State> { emulateVerticalOffsetBy: emulateVerticalOffsetBy, startHour: startHour, endHour: endHour, + showStartHour: showStartHour, + showEndHour: showEndHour, + padding: padding, ); } diff --git a/pubspec.yaml b/pubspec.yaml index 2d15129f..80f68b80 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ issue_tracker: https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/i environment: sdk: ">=2.15.0 <4.0.0" - flutter: ">=1.17.0" + flutter: ">=2.8.0" dependencies: flutter: