From eb0feb84d6ce8d3ab3802343072d69ac3da0545c Mon Sep 17 00:00:00 2001 From: Parth Baraiya Date: Wed, 5 Jun 2024 23:49:36 +0530 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20fixes=20issue=20#267.=20show=200=20?= =?UTF-8?q?hr=20and=2024=20hr=20markers=20in=20timeline.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 + example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- example/lib/main.dart | 4 +- example/lib/widgets/day_view_widget.dart | 52 +- example/lib/widgets/event_provider.dart | 1 - lib/src/components/_internal_components.dart | 93 ++-- lib/src/components/common_components.dart | 12 +- lib/src/components/day_view_components.dart | 23 +- lib/src/day_view/_internal_day_view_page.dart | 241 +++++---- lib/src/day_view/day_view.dart | 51 +- lib/src/painters.dart | 58 ++- lib/src/typedefs.dart | 8 + .../week_view/_internal_week_view_page.dart | 467 ++++++++++-------- lib/src/week_view/week_view.dart | 45 +- pubspec.yaml | 2 +- 16 files changed, 665 insertions(+), 404 deletions(-) delete mode 100644 example/lib/widgets/event_provider.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 64b04e1c..3f1b1f09 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.2.0 - 10 May 2024](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.2.0) - Fixed issue when adding full-day events to WeekView, event is not display at correct date. [#259](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/259) 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.add(Duration(days: 1)), diff --git a/example/lib/widgets/day_view_widget.dart b/example/lib/widgets/day_view_widget.dart index 9ec788e8..88d77b25 100644 --- a/example/lib/widgets/day_view_widget.dart +++ b/example/lib/widgets/day_view_widget.dart @@ -21,10 +21,11 @@ class DayViewWidget extends StatelessWidget { startDuration: Duration(hours: 8), showHalfHours: true, heightPerMinute: 3, - timeLineBuilder: _timeLineBuilder, + // timeLineBuilder: _timeLineBuilder, hourIndicatorSettings: HourIndicatorSettings( color: Theme.of(context).dividerColor, ), + showQuarterHours: true, onEventTap: (events, date) { Navigator.of(context).push( MaterialPageRoute( @@ -48,14 +49,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: [ @@ -63,7 +66,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), @@ -76,7 +79,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: [ @@ -84,7 +120,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 129e84c1..2e7cb230 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; /// Flag to display half hours. final bool showHalfHours; @@ -167,6 +172,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, @@ -180,6 +193,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 @@ -196,24 +212,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( @@ -226,13 +224,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) @@ -240,10 +242,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, ), @@ -253,10 +257,12 @@ class _TimeLineState extends State { _timelinePositioned( topPosition: widget.hourHeight * i - widget.timeLineOffset + - widget.hourHeight * 0.25, + widget.hourHeight * 0.25 + + widget.padding.top, bottomPosition: widget.height - (widget.hourHeight * (i + 1)) + - widget.timeLineOffset, + widget.timeLineOffset - + widget.padding.bottom, hour: i, minutes: 15, ), @@ -265,10 +271,12 @@ class _TimeLineState extends State { _timelinePositioned( topPosition: widget.hourHeight * i - widget.timeLineOffset + - widget.hourHeight * 0.75, + widget.hourHeight * 0.75 + + widget.padding.top, bottomPosition: widget.height - (widget.hourHeight * (i + 1)) + - widget.timeLineOffset, + widget.timeLineOffset - + widget.padding.bottom, hour: i, minutes: 45, ), @@ -278,6 +286,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 @@ -297,16 +323,15 @@ class _TimeLineState extends State { left: 0, right: 0, bottom: bottomPosition, - child: Container( + child: SizedBox( height: widget.hourHeight, width: widget.timeLineWidth, child: widget.timeLineBuilder.call( + TimeOfDay(hour: hour, minute: minutes), DateTime( TimeLine._date.year, TimeLine._date.month, TimeLine._date.day, - hour, - minutes, ), ), ), diff --git a/lib/src/components/common_components.dart b/lib/src/components/common_components.dart index 227fc001..4a22ecdf 100644 --- a/lib/src/components/common_components.dart +++ b/lib/src/components/common_components.dart @@ -7,10 +7,10 @@ import 'package:flutter/material.dart'; import '../calendar_event_data.dart'; import '../constants.dart'; +import '../enumerations.dart'; import '../extensions.dart'; import '../style/header_style.dart'; import '../typedefs.dart'; -import '../enumerations.dart'; import 'components.dart'; class CalendarPageHeader extends StatelessWidget { @@ -134,6 +134,8 @@ class DefaultPressDetector extends StatelessWidget { this.onDateTap, this.onDateLongPress, this.startHour = 0, + required this.padding, + required this.endHour, }); final DateTime date; @@ -144,11 +146,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, @@ -157,10 +161,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 745a19b1..ac4aa80b 100644 --- a/lib/src/components/day_view_components.dart +++ b/lib/src/components/day_view_components.dart @@ -146,11 +146,14 @@ class DayPageHeader extends CalendarPageHeader { } 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; @@ -159,20 +162,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 d46be383..d5fd2d24 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; @@ -133,6 +134,15 @@ class InternalDayViewPage 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 pagePadding; + /// Defines a single day page. const InternalDayViewPage({ Key? key, @@ -173,6 +183,9 @@ class InternalDayViewPage extends StatefulWidget { required this.emulateVerticalOffsetBy, required this.onTileDoubleTap, this.keepScrollOffset = false, + required this.showEndHours, + required this.showStartHours, + required this.pagePadding, }) : super(key: key); @override @@ -207,92 +220,107 @@ class _InternalDayViewPageState @override Widget build(BuildContext context) { final fullDayEventList = widget.controller.getFullDayEvent(widget.date); - return Container( - height: widget.height, - width: widget.width, - child: Column( - children: [ - fullDayEventList.isEmpty - ? SizedBox.shrink() - : widget.fullDayEventBuilder( - widget.controller.getFullDayEvent(widget.date), - widget.date, - ), - Expanded( - child: SingleChildScrollView( - controller: widget.keepScrollOffset - ? scrollController - : widget.dayViewScrollController, - child: SizedBox( - height: widget.height, - width: widget.width, - child: Stack( - children: [ + return Column( + children: [ + fullDayEventList.isEmpty + ? SizedBox.shrink() + : widget.fullDayEventBuilder( + widget.controller.getFullDayEvent(widget.date), + widget.date, + ), + Expanded( + child: SingleChildScrollView( + controller: widget.keepScrollOffset + ? scrollController + : widget.dayViewScrollController, + child: SizedBox( + height: widget.height, + width: widget.width, + child: Stack( + children: [ + //#region Time line widgets + // Shows line for one hour. + CustomPaint( + size: Size(widget.width, widget.height), + painter: widget.hourLinePainter( + widget.hourIndicatorSettings.color, + widget.hourIndicatorSettings.height, + widget.timeLineWidth + + widget.hourIndicatorSettings.offset, + widget.heightPerMinute, + widget.showVerticalLine, + widget.verticalLineOffset, + widget.hourIndicatorSettings.lineStyle, + widget.hourIndicatorSettings.dashWidth, + widget.hourIndicatorSettings.dashSpaceWidth, + widget.emulateVerticalOffsetBy, + widget.startHour, + widget.endHour, + widget.showStartHours, + widget.showEndHours, + widget.pagePadding, + ), + ), + // Shows lines for Half hours + if (widget.showHalfHours) CustomPaint( size: Size(widget.width, widget.height), - painter: HourLinePainter( - lineColor: widget.hourIndicatorSettings.color, - lineHeight: widget.hourIndicatorSettings.height, + painter: HalfHourLinePainter( + lineColor: widget.halfHourIndicatorSettings.color, + lineHeight: widget.halfHourIndicatorSettings.height, offset: widget.timeLineWidth + - widget.hourIndicatorSettings.offset, + widget.halfHourIndicatorSettings.offset, minuteHeight: widget.heightPerMinute, - verticalLineOffset: widget.verticalLineOffset, - showVerticalLine: widget.showVerticalLine, - lineStyle: widget.hourIndicatorSettings.lineStyle, - dashWidth: widget.hourIndicatorSettings.dashWidth, + lineStyle: widget.halfHourIndicatorSettings.lineStyle, + dashWidth: widget.halfHourIndicatorSettings.dashWidth, dashSpaceWidth: - widget.hourIndicatorSettings.dashSpaceWidth, - emulateVerticalOffsetBy: widget.emulateVerticalOffsetBy, + widget.halfHourIndicatorSettings.dashSpaceWidth, startHour: widget.startHour, endHour: widget.endHour, + showStartHour: widget.showStartHours, + showEndHour: widget.showEndHours, + padding: widget.pagePadding, ), ), - 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.startHour, - endHour: widget.endHour, - ), - ), - 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, - ), + // Shows lines for quarter hours + 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, + padding: widget.pagePadding, + showEndHour: widget.showEndHours, + showStartHour: widget.showStartHours, ), - widget.dayDetectorBuilder( - width: widget.width, - height: widget.height, - heightPerMinute: widget.heightPerMinute, - date: widget.date, - minuteSlotSize: widget.minuteSlotSize, ), - Align( + //#endregion + + // Enables gesture in empty areas. + widget.dayDetectorBuilder( + width: widget.width, + height: widget.height, + heightPerMinute: widget.heightPerMinute, + date: widget.date, + minuteSlotSize: widget.minuteSlotSize, + pagePadding: widget.pagePadding, + ), + + Padding( + padding: widget.pagePadding, + child: Align( alignment: Alignment.centerRight, child: EventGenerator( - height: widget.height, + height: widget.height - widget.pagePadding.vertical, date: widget.date, onTileLongTap: widget.onTileLongTap, onTileDoubleTap: widget.onTileDoubleTap, @@ -313,41 +341,44 @@ class _InternalDayViewPageState 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, - ), - 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, - ), + ), + 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, + ), + 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, + padding: widget.pagePadding, ), - ], - ), + ), + ], ), ), ), - ], - ), + ), + ], ); } } diff --git a/lib/src/day_view/day_view.dart b/lib/src/day_view/day_view.dart index 163b8937..6cf393db 100644 --- a/lib/src/day_view/day_view.dart +++ b/lib/src/day_view/day_view.dart @@ -35,14 +35,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. final DateWidgetBuilder? dayTitleBuilder; @@ -81,7 +81,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; @@ -229,6 +229,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, @@ -279,6 +288,9 @@ class DayView extends StatefulWidget { this.onEventDoubleTap, this.endHour = Constants.hoursADay, this.keepScrollOffset = false, + this.showEndHours = false, + this.showStartHours = false, + this.dayPagePadding, }) : assert(!(onHeaderTitleTap != null && dayTitleBuilder != null), "can't use [onHeaderTitleTap] & [dayTitleBuilder] simultaneously"), assert(timeLineOffset >= 0, @@ -331,7 +343,7 @@ class DayViewState extends State> { late PageController _pageController; - late DateWidgetBuilder _timeLineBuilder; + late TimeLineTimeBuilder _timeLineBuilder; late EventTileBuilder _eventTileBuilder; @@ -351,6 +363,8 @@ class DayViewState extends State> { final _scrollConfiguration = EventScrollConfiguration(); + late EdgeInsets _pagePadding; + @override void initState() { super.initState(); @@ -505,6 +519,9 @@ class DayViewState extends State> { dayViewScrollController: _scrollController, 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 d966ac0c..23b982ca 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, @@ -90,6 +95,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 2603e890..5437bdc6 100644 --- a/lib/src/week_view/_internal_week_view_page.dart +++ b/lib/src/week_view/_internal_week_view_page.dart @@ -4,15 +4,10 @@ import 'package:flutter/material.dart'; +import '../../calendar_view.dart'; import '../components/_internal_components.dart'; -import '../components/week_view_components.dart'; import '../components/event_scroll_notifier.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 +28,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; @@ -160,6 +155,14 @@ class InternalWeekViewPage 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 pagePadding; + /// A single page for week view. const InternalWeekViewPage({ Key? key, @@ -208,6 +211,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 @@ -242,248 +248,279 @@ 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, - 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, - startHour: widget.startHour, - emulateVerticalOffsetBy: widget.emulateVerticalOffsetBy, - 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, + 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, - 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, + painter: widget.hourLinePainter( + widget.hourIndicatorSettings.color, + widget.hourIndicatorSettings.height, + widget.timeLineWidth + + widget.hourIndicatorSettings.offset, + widget.heightPerMinute, + widget.showVerticalLine, + widget.verticalLineOffset, + widget.hourIndicatorSettings.lineStyle, + widget.hourIndicatorSettings.dashWidth, + widget.hourIndicatorSettings.dashSpaceWidth, + widget.emulateVerticalOffsetBy, + widget.startHour, + widget.endHour, + widget.showStartHours, + widget.showEndHours, + widget.pagePadding, ), ), - 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, + showStartHour: widget.showStartHours, + showEndHour: widget.showEndHours, + padding: widget.pagePadding, + ), ), - ), - 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, + padding: widget.pagePadding, + showEndHour: widget.showEndHours, + showStartHour: widget.showStartHours, + ), + ), + 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, - ), - 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, + 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 dd61214c..1835d551 100644 --- a/lib/src/week_view/week_view.dart +++ b/lib/src/week_view/week_view.dart @@ -28,7 +28,7 @@ class WeekView extends StatefulWidget { final EventTileBuilder? eventTileBuilder; /// Builder for timeline. - final DateWidgetBuilder? timeLineBuilder; + final TimeLineTimeBuilder? timeLineBuilder; /// Header builder for week page header. final WeekPageHeaderBuilder? weekPageHeaderBuilder; @@ -45,7 +45,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 @@ -87,7 +87,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; @@ -240,6 +240,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, @@ -298,6 +306,9 @@ class WeekView extends StatefulWidget { this.fullDayHeaderTitle = '', this.fullDayHeaderTextConfig, this.keepScrollOffset = false, + this.showEndHours = false, + this.showStartHours = false, + this.weekPagePadding, }) : assert(!(onHeaderTitleTap != null && weekPageHeaderBuilder != null), "can't use [onHeaderTitleTap] & [weekPageHeaderBuilder] simultaneously"), assert((timeLineOffset) >= 0, @@ -353,7 +364,7 @@ class WeekViewState extends State> { late PageController _pageController; - late DateWidgetBuilder _timeLineBuilder; + late TimeLineTimeBuilder _timeLineBuilder; late EventTileBuilder _eventTileBuilder; late WeekPageHeaderBuilder _weekHeaderBuilder; late DateWidgetBuilder _weekDayBuilder; @@ -380,6 +391,8 @@ class WeekViewState extends State> { final _scrollConfiguration = EventScrollConfiguration(); + late EdgeInsets _pagePadding; + @override void initState() { super.initState(); @@ -559,6 +572,9 @@ class WeekViewState extends State> { lastScrollOffset: _lastScrollOffset, scrollListener: _scrollPageListener, keepScrollOffset: widget.keepScrollOffset, + showEndHours: widget.showEndHours, + showStartHours: widget.showStartHours, + pagePadding: _pagePadding, ), ); }, @@ -656,8 +672,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() { @@ -736,6 +758,7 @@ class WeekViewState extends State> { required double width, required double heightPerMinute, required MinuteSlotSize minuteSlotSize, + required EdgeInsets pagePadding, }) => DefaultPressDetector( date: date, @@ -746,6 +769,8 @@ class WeekViewState extends State> { onDateTap: widget.onDateTap, onDateLongPress: widget.onDateLongPress, startHour: _startHour, + endHour: _endHour, + padding: pagePadding, ); /// Default builder for week line. @@ -780,8 +805,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, ); @@ -846,6 +873,9 @@ class WeekViewState extends State> { double emulateVerticalOffsetBy, int startHour, int endHour, + bool showStartHour, + bool showEndHour, + EdgeInsets padding, ) { return HourLinePainter( lineColor: lineColor, @@ -860,6 +890,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 ee773355..7a295442 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: