Skip to content

Commit

Permalink
feat: ✨ Added show time on live timeline (#217)
Browse files Browse the repository at this point in the history
* Initial implementation to show time on live timeline

* Automatic adjust on timeLineWidth increases

* Expose two properties of LiveTimeIndicatorSettings

* Fixed error produced by dart formatter

* Fixed formatting

* Formatting fixed

* Fixed formatting

* Upgraded min dart sdk

* Initial implementation to show time on live timeline

* Automatic adjust on timeLineWidth increases

* Expose two properties of LiveTimeIndicatorSettings

* Fixed error produced by dart formatter

* Formatting fixed

* Fixed formatting

* Upgraded min dart sdk

* offset corrected
  • Loading branch information
DevyankShaw authored Feb 21, 2024
1 parent d65bb7f commit c003d1b
Show file tree
Hide file tree
Showing 11 changed files with 256 additions and 61 deletions.
9 changes: 9 additions & 0 deletions example/lib/widgets/day_view_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ class DayViewWidget extends StatelessWidget {
color: Theme.of(context).dividerColor,
lineStyle: LineStyle.dashed,
),
verticalLineOffset: 0,
timeLineWidth: 65,
showLiveTimeLineInAllDays: true,
liveTimeIndicatorSettings: LiveTimeIndicatorSettings(
color: Colors.redAccent,
showBullet: false,
showTime: true,
showTimeBackgroundView: true,
),
);
}

Expand Down
6 changes: 6 additions & 0 deletions example/lib/widgets/week_view_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ class WeekViewWidget extends StatelessWidget {
return WeekView(
key: state,
width: width,
showLiveTimeLineInAllDays: true,
timeLineWidth: 65,
liveTimeIndicatorSettings: LiveTimeIndicatorSettings(
color: Colors.redAccent,
showTime: true,
),
onEventTap: (events, date) {
Navigator.of(context).push(
MaterialPageRoute(
Expand Down
143 changes: 105 additions & 38 deletions lib/src/components/_internal_components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class LiveTimeIndicator extends StatefulWidget {
final double timeLineWidth;

/// settings for time line. Defines color, extra offset,
/// and height of indicator.
final HourIndicatorSettings liveTimeIndicatorSettings;
/// height of indicator and also allow to show time with custom format.
final LiveTimeIndicatorSettings liveTimeIndicatorSettings;

/// Defines height occupied by one minute.
final double heightPerMinute;
Expand Down Expand Up @@ -79,6 +79,12 @@ class _LiveTimeIndicatorState extends State<LiveTimeIndicator> {

@override
Widget build(BuildContext context) {
final currentHour = _currentTime.hourOfPeriod.appendLeadingZero();
final currentMinute = _currentTime.minute.appendLeadingZero();
final currentPeriod = _currentTime.period.name;
final timeString = widget.liveTimeIndicatorSettings.timeStringBuilder
?.call(DateTime.now()) ??
'$currentHour:$currentMinute $currentPeriod';
return CustomPaint(
size: Size(widget.width, widget.height),
painter: CurrentTimeLinePainter(
Expand All @@ -88,13 +94,21 @@ class _LiveTimeIndicatorState extends State<LiveTimeIndicator> {
widget.timeLineWidth + widget.liveTimeIndicatorSettings.offset,
_currentTime.getTotalMinutes * widget.heightPerMinute,
),
timeString: timeString,
showBullet: widget.liveTimeIndicatorSettings.showBullet,
showTime: widget.liveTimeIndicatorSettings.showTime,
showTimeBackgroundView:
widget.liveTimeIndicatorSettings.showTimeBackgroundView,
bulletRadius: widget.liveTimeIndicatorSettings.bulletRadius,
timeBackgroundViewWidth:
widget.liveTimeIndicatorSettings.timeBackgroundViewWidth,
),
);
}
}

/// Time line to display time at left side of day or week view.
class TimeLine extends StatelessWidget {
class TimeLine extends StatefulWidget {
/// Width of timeline
final double timeLineWidth;

Expand All @@ -116,6 +130,10 @@ class TimeLine extends StatelessWidget {
/// Flag to display quarter hours.
final bool showQuarterHours;

/// settings for time line. Defines color, extra offset,
/// height of indicator and also allow to show time with custom format.
final LiveTimeIndicatorSettings liveTimeIndicatorSettings;

static DateTime get _date => DateTime.now();

double get _halfHourHeight => hourHeight / 2;
Expand All @@ -130,53 +148,95 @@ class TimeLine extends StatelessWidget {
required this.timeLineBuilder,
this.showHalfHours = false,
this.showQuarterHours = false,
required this.liveTimeIndicatorSettings,
}) : super(key: key);

@override
State<TimeLine> createState() => _TimeLineState();
}

class _TimeLineState extends State<TimeLine> {
late Timer _timer;
late TimeOfDay _currentTime = TimeOfDay.now();

@override
void initState() {
super.initState();
_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(
key: ValueKey(hourHeight),
key: ValueKey(widget.hourHeight),
constraints: BoxConstraints(
maxWidth: timeLineWidth,
minWidth: timeLineWidth,
maxHeight: height,
minHeight: height,
maxWidth: widget.timeLineWidth,
minWidth: widget.timeLineWidth,
maxHeight: widget.height,
minHeight: widget.height,
),
child: Stack(
children: [
for (int i = 1; i < Constants.hoursADay; i++)
_timelinePositioned(
topPosition: hourHeight * i - timeLineOffset,
bottomPosition: height - (hourHeight * (i + 1)) + timeLineOffset,
topPosition: widget.hourHeight * i - widget.timeLineOffset,
bottomPosition: widget.height -
(widget.hourHeight * (i + 1)) +
widget.timeLineOffset,
hour: i,
),
if (showHalfHours)
if (widget.showHalfHours)
for (int i = 0; i < Constants.hoursADay; i++)
_timelinePositioned(
topPosition: hourHeight * i - timeLineOffset + _halfHourHeight,
bottomPosition:
height - (hourHeight * (i + 1)) + timeLineOffset,
topPosition: widget.hourHeight * i -
widget.timeLineOffset +
widget._halfHourHeight,
bottomPosition: widget.height -
(widget.hourHeight * (i + 1)) +
widget.timeLineOffset,
hour: i,
minutes: 30,
),
if (showQuarterHours)
if (widget.showQuarterHours)
for (int i = 0; i < Constants.hoursADay; i++) ...[
/// this is for 15 minutes
_timelinePositioned(
topPosition:
hourHeight * i - timeLineOffset + hourHeight * 0.25,
bottomPosition:
height - (hourHeight * (i + 1)) + timeLineOffset,
topPosition: widget.hourHeight * i -
widget.timeLineOffset +
widget.hourHeight * 0.25,
bottomPosition: widget.height -
(widget.hourHeight * (i + 1)) +
widget.timeLineOffset,
hour: i,
minutes: 15,
),

/// this is for 45 minutes
_timelinePositioned(
topPosition:
hourHeight * i - timeLineOffset + hourHeight * 0.75,
bottomPosition:
height - (hourHeight * (i + 1)) + timeLineOffset,
topPosition: widget.hourHeight * i -
widget.timeLineOffset +
widget.hourHeight * 0.75,
bottomPosition: widget.height -
(widget.hourHeight * (i + 1)) +
widget.timeLineOffset,
hour: i,
minutes: 45,
),
Expand All @@ -186,27 +246,34 @@ class TimeLine extends StatelessWidget {
);
}

/// 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
Widget _timelinePositioned({
required double topPosition,
required double bottomPosition,
required int hour,
int minutes = 0,
}) {
return Positioned(
top: topPosition,
left: 0,
right: 0,
bottom: bottomPosition,
child: Container(
height: hourHeight,
width: timeLineWidth,
child: timeLineBuilder.call(
DateTime(
_date.year,
_date.month,
_date.day,
hour,
minutes,
return Visibility(
visible: !((_currentTime.minute >= 45 && _currentTime.hour == hour - 1) ||
(_currentTime.minute <= 15 && _currentTime.hour == hour)),
child: Positioned(
top: topPosition,
left: 0,
right: 0,
bottom: bottomPosition,
child: Container(
height: widget.hourHeight,
width: widget.timeLineWidth,
child: widget.timeLineBuilder.call(
DateTime(
TimeLine._date.year,
TimeLine._date.month,
TimeLine._date.day,
hour,
minutes,
),
),
),
),
Expand Down
3 changes: 2 additions & 1 deletion lib/src/day_view/_internal_day_view_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class InternalDayViewPage<T extends Object?> extends StatelessWidget {
final bool showLiveLine;

/// Settings for live time indicator.
final HourIndicatorSettings liveTimeIndicatorSettings;
final LiveTimeIndicatorSettings liveTimeIndicatorSettings;

/// Height occupied by one minute of time span.
final double heightPerMinute;
Expand Down Expand Up @@ -247,6 +247,7 @@ class InternalDayViewPage<T extends Object?> extends StatelessWidget {
showHalfHours: showHalfHours,
showQuarterHours: showQuarterHours,
key: ValueKey(heightPerMinute),
liveTimeIndicatorSettings: liveTimeIndicatorSettings,
),
if (showLiveLine && liveTimeIndicatorSettings.height > 0)
IgnorePointer(
Expand Down
8 changes: 4 additions & 4 deletions lib/src/day_view/day_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ class DayView<T extends Object?> extends StatefulWidget {

/// Defines settings for live time indicator.
///
/// Pass [HourIndicatorSettings.none] to remove live time indicator.
final HourIndicatorSettings? liveTimeIndicatorSettings;
/// Pass [LiveTimeIndicatorSettings.none] to remove live time indicator.
final LiveTimeIndicatorSettings? liveTimeIndicatorSettings;

/// Defines settings for half hour indication lines.
///
Expand Down Expand Up @@ -297,7 +297,7 @@ class DayViewState<T extends Object?> extends State<DayView<T>> {
late HourIndicatorSettings _quarterHourIndicatorSettings;
late CustomHourLinePainter _hourLinePainter;

late HourIndicatorSettings _liveTimeIndicatorSettings;
late LiveTimeIndicatorSettings _liveTimeIndicatorSettings;

late PageController _pageController;

Expand Down Expand Up @@ -505,7 +505,7 @@ class DayViewState<T extends Object?> extends State<DayView<T>> {
_timeLineWidth = widget.timeLineWidth ?? _width * 0.13;

_liveTimeIndicatorSettings = widget.liveTimeIndicatorSettings ??
HourIndicatorSettings(
LiveTimeIndicatorSettings(
color: Constants.defaultLiveTimeIndicatorColor,
height: widget.heightPerMinute,
offset: 5 + widget.verticalLineOffset,
Expand Down
6 changes: 6 additions & 0 deletions lib/src/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,9 @@ extension MyList on List<CalendarEventData> {
extension TimerOfDayExtension on TimeOfDay {
int get getTotalMinutes => hour * 60 + minute;
}

extension IntExtension on int {
String appendLeadingZero() {
return toString().padLeft(2, '0');
}
}
51 changes: 51 additions & 0 deletions lib/src/modals.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'package:flutter/material.dart';

import 'enumerations.dart';
import 'typedefs.dart';

/// Settings for hour lines
class HourIndicatorSettings {
Expand All @@ -30,3 +31,53 @@ class HourIndicatorSettings {
height: 0.0,
);
}

/// Settings for live time line
class LiveTimeIndicatorSettings {
/// Color of time indicator.
final Color color;

/// Height of time indicator.
final double height;

/// offset of time indicator.
final double offset;

/// StringProvider for time string
final StringProvider? timeStringBuilder;

/// Flag to show bullet at left side or not.
final bool showBullet;

/// Flag to show time on live time line.
final bool showTime;

/// Flag to show time backgroud view.
final bool showTimeBackgroundView;

/// Radius of bullet.
final double bulletRadius;

/// Width of time backgroud view.
final double timeBackgroundViewWidth;

/// Settings for live time line
const LiveTimeIndicatorSettings({
this.height = 1.0,
this.offset = 5.0,
this.color = Colors.grey,
this.timeStringBuilder,
this.showBullet = true,
this.showTime = false,
this.showTimeBackgroundView = false,
this.bulletRadius = 5.0,
this.timeBackgroundViewWidth = 60.0,
}) : assert(height >= 0, "Height must be greater than or equal to 0.");

factory LiveTimeIndicatorSettings.none() => LiveTimeIndicatorSettings(
color: Colors.transparent,
height: 0.0,
offset: 0.0,
showBullet: false,
);
}
Loading

0 comments on commit c003d1b

Please sign in to comment.