Skip to content

Commit

Permalink
Support timezone and hour limitation
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianMong committed Oct 25, 2024
1 parent 79b9840 commit d39475f
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 27 deletions.
31 changes: 21 additions & 10 deletions lib/src/components/_internal_components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,19 @@ class LiveTimeIndicator extends StatefulWidget {
/// Defines height occupied by one minute.
final double heightPerMinute;

// Start time to display
final TimeOfDay? startTime;

/// Widget to display tile line according to current time.
const LiveTimeIndicator(
{Key? key,
required this.width,
required this.height,
required this.timeLineWidth,
required this.liveTimeIndicatorSettings,
required this.heightPerMinute})
: super(key: key);
const LiveTimeIndicator({
Key? key,
required this.width,
required this.height,
required this.timeLineWidth,
required this.liveTimeIndicatorSettings,
required this.heightPerMinute,
this.startTime,
}) : super(key: key);

@override
_LiveTimeIndicatorState createState() => _LiveTimeIndicatorState();
Expand Down Expand Up @@ -81,14 +85,20 @@ class _LiveTimeIndicatorState extends State<LiveTimeIndicator> {

@override
Widget build(BuildContext context) {
int currentMinutes = _currentTime.getTotalMinutes;

if (widget.startTime != null) {
currentMinutes -= widget.startTime!.getTotalMinutes;
}

return CustomPaint(
size: Size(widget.width, widget.height),
painter: CurrentTimeLinePainter(
color: widget.liveTimeIndicatorSettings.color,
height: widget.liveTimeIndicatorSettings.height,
offset: Offset(
widget.timeLineWidth + widget.liveTimeIndicatorSettings.offset,
_currentTime.getTotalMinutes * widget.heightPerMinute,
currentMinutes * widget.heightPerMinute,
),
),
);
Expand Down Expand Up @@ -148,7 +158,7 @@ class TimeLine extends StatelessWidget {

@override
Widget build(BuildContext context) {
int? initialHour = startTime != null ? startTime!.hour : 1;
int? initialHour = startTime != null ? startTime!.hour : 0;
int? hoursADay = endTime != null ? endTime!.hour : Constants.hoursADay;
int totalHours = hoursADay - initialHour;
return ConstrainedBox(
Expand Down Expand Up @@ -289,6 +299,7 @@ class EventGenerator<T extends Object?> extends StatelessWidget {
heightPerMinute: heightPerMinute,
);

// position tile
return List.generate(events.length, (index) {
return Positioned(
top: events[index].top,
Expand Down
1 change: 1 addition & 0 deletions lib/src/day_view/_internal_day_view_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ class InternalDayViewPage<T extends Object?> extends StatelessWidget {
height: height,
heightPerMinute: heightPerMinute,
timeLineWidth: timeLineWidth,
startTime: startTime,
),
),
],
Expand Down
42 changes: 37 additions & 5 deletions lib/src/day_view/day_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import '../enumerations.dart';
import '../event_arrangers/event_arrangers.dart';
import '../event_controller.dart';
import '../extensions.dart';
import '../helpers/time_zone.dart';
import '../modals.dart';
import '../painters.dart';
import '../style/header_style.dart';
Expand Down Expand Up @@ -333,10 +334,18 @@ class DayViewState<T extends Object?> extends State<DayView<T>> {

final _scrollConfiguration = EventScrollConfiguration<T>();

late TimeOfDay? startTime;

late TimeOfDay? endTime;

int timeZoneOffset = 0;

@override
void initState() {
super.initState();

_updateTimeToCurrentTimeZone();

_reloadCallback = _reload;
_setDateRange();

Expand All @@ -349,10 +358,29 @@ class DayViewState<T extends Object?> extends State<DayView<T>> {
initialScrollOffset: widget.scrollOffset ??
widget.startDuration.inMinutes * widget.heightPerMinute);
_pageController = PageController(initialPage: _currentIndex);
_eventArranger = widget.eventArranger ?? SideEventArranger<T>();
_eventArranger = widget.eventArranger ??
SideEventArranger<T>(startTime: widget.startTime);
_assignBuilders();
}

void _updateTimeToCurrentTimeZone() {
final int currentTimeZoneOffset = widget.locationName != null
? TimeZoneHelper.getTimeZoneOffset(widget.locationName!)
: 0;
final TimeOfDay? finalStartTime = widget.startTime != null
? TimeZoneHelper.addHour(widget.startTime!, currentTimeZoneOffset)
: null;
final TimeOfDay? finalEndTime = widget.endTime != null
? TimeZoneHelper.addHour(widget.endTime!, currentTimeZoneOffset)
: null;

setState(() {
timeZoneOffset = currentTimeZoneOffset;
startTime = finalStartTime;
endTime = finalEndTime;
});
}

@override
void didChangeDependencies() {
super.didChangeDependencies();
Expand All @@ -376,6 +404,9 @@ class DayViewState<T extends Object?> extends State<DayView<T>> {
@override
void didUpdateWidget(DayView<T> oldWidget) {
super.didUpdateWidget(oldWidget);

_updateTimeToCurrentTimeZone();

// Update controller.
final newController = widget.controller ??
CalendarControllerProvider.of<T>(context).controller;
Expand All @@ -395,7 +426,8 @@ class DayViewState<T extends Object?> extends State<DayView<T>> {
_pageController.jumpToPage(_currentIndex);
}

_eventArranger = widget.eventArranger ?? SideEventArranger<T>();
_eventArranger = widget.eventArranger ??
SideEventArranger<T>(startTime: widget.startTime);

// Update heights.
_calculateHeights();
Expand Down Expand Up @@ -479,8 +511,8 @@ class DayViewState<T extends Object?> extends State<DayView<T>> {
emulateVerticalOffsetBy:
widget.emulateVerticalOffsetBy,
locationName: widget.locationName,
startTime: widget.startTime,
endTime: widget.endTime,
startTime: startTime,
endTime: endTime,
),
);
},
Expand Down Expand Up @@ -639,7 +671,7 @@ class DayViewState<T extends Object?> extends State<DayView<T>> {
required MinuteSlotSize minuteSlotSize,
}) {
int hoursADay = _getHoursADay().toInt();
int startHour = widget.startTime != null ? widget.startTime!.hour : 0;
int startHour = startTime != null ? startTime!.hour : 0;

final heightPerSlot = minuteSlotSize.minutes * heightPerMinute;
final slots = (hoursADay * 60) ~/ minuteSlotSize.minutes;
Expand Down
1 change: 1 addition & 0 deletions lib/src/event_arrangers/event_arrangers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:math' as math;

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import '../calendar_event_data.dart';
import '../constants.dart';
Expand Down
15 changes: 13 additions & 2 deletions lib/src/event_arrangers/merge_event_arranger.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class MergeEventArranger<T extends Object?> extends EventArranger<T> {
/// [OrganizedCalendarEventData.events] will gives
/// list of all the combined events.
const MergeEventArranger({
this.startTime,
this.includeEdges = true,
});

Expand All @@ -21,6 +22,9 @@ class MergeEventArranger<T extends Object?> extends EventArranger<T> {
///
final bool includeEdges;

// Start time to display
final TimeOfDay? startTime;

/// {@macro event_arranger_arrange_method_doc}
///
/// Make sure that all the events that are passed in [events], must be in
Expand All @@ -37,6 +41,13 @@ class MergeEventArranger<T extends Object?> extends EventArranger<T> {
//
final arrangedEvents = <OrganizedCalendarEventData<T>>[];

int startMinutes = 0;

if (startTime != null) {
// Subtract start time to calculate correct tile position
startMinutes = startTime!.getTotalMinutes * -1;
}

for (final event in events) {
// Checks if an event has valid start and end time.
if (event.startTime == null ||
Expand All @@ -62,10 +73,10 @@ class MergeEventArranger<T extends Object?> extends EventArranger<T> {
final startTime = event.startTime!;
final endTime = event.endTime!;

final eventStart = startTime.getTotalMinutes;
final eventStart = startTime.getTotalMinutes + startMinutes;
final eventEnd = endTime.getTotalMinutes == 0
? Constants.minutesADay
: endTime.getTotalMinutes;
: endTime.getTotalMinutes + startMinutes;

final arrangeEventLen = arrangedEvents.length;

Expand Down
22 changes: 17 additions & 5 deletions lib/src/event_arrangers/side_event_arranger.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class SideEventArranger<T extends Object?> extends EventArranger<T> {
/// This class will provide method that will arrange
/// all the events side by side.
const SideEventArranger({
this.startTime,
this.includeEdges = false,
});

Expand All @@ -19,6 +20,9 @@ class SideEventArranger<T extends Object?> extends EventArranger<T> {
///
final bool includeEdges;

// Start time to display
final TimeOfDay? startTime;

/// {@macro event_arranger_arrange_method_doc}
///
/// Make sure that all the events that are passed in [events], must be in
Expand All @@ -30,9 +34,9 @@ class SideEventArranger<T extends Object?> extends EventArranger<T> {
required double width,
required double heightPerMinute,
}) {
final mergedEvents = MergeEventArranger<T>(
includeEdges: includeEdges,
).arrange(
final mergedEvents =
MergeEventArranger<T>(includeEdges: includeEdges, startTime: startTime)
.arrange(
events: events,
height: height,
width: width,
Expand Down Expand Up @@ -83,6 +87,13 @@ class SideEventArranger<T extends Object?> extends EventArranger<T> {

final slotWidth = width / column;

int startMinutes = 0;

if (startTime != null) {
// Subtract start time to calculate correct tile position
startMinutes = startTime!.getTotalMinutes * -1;
}

for (final sideEvent in sideEventData) {
if (sideEvent.event.startTime == null ||
sideEvent.event.endTime == null) {
Expand All @@ -103,12 +114,13 @@ class SideEventArranger<T extends Object?> extends EventArranger<T> {
final bottom = height -
(endTime.getTotalMinutes == 0
? Constants.minutesADay
: endTime.getTotalMinutes) *
: endTime.getTotalMinutes + startMinutes) *
heightPerMinute;
// ou ici
arrangedEvents.add(OrganizedCalendarEventData<T>(
left: slotWidth * (sideEvent.column - 1),
right: slotWidth * (column - sideEvent.column),
top: startTime.getTotalMinutes * heightPerMinute,
top: (startTime.getTotalMinutes + startMinutes) * heightPerMinute,
bottom: bottom,
startDuration: startTime,
endDuration: endTime,
Expand Down
24 changes: 24 additions & 0 deletions lib/src/helpers/time_zone.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:timezone/standalone.dart' as tz;
import 'package:timezone/timezone.dart';

class TimeZoneHelper {
static DateTime? getTzDateFromDateTime(
DateTime? dateTime, String locationName) {
if (dateTime == null) {
return null;
}
final Location location = tz.getLocation(locationName);
return TZDateTime.from(dateTime, location);
}

static int getTimeZoneOffset(String location) {
final now = DateTime.now();
return now.timeZoneOffset.inHours -
getTzDateFromDateTime(now, location)!.timeZoneOffset.inHours;
}

static TimeOfDay addHour(TimeOfDay time, int hour) {
return TimeOfDay(hour: time.hour + hour, minute: time.minute);
}
}
1 change: 1 addition & 0 deletions lib/src/week_view/_internal_week_view_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ class InternalWeekViewPage<T extends Object?> extends StatelessWidget {
height: height,
heightPerMinute: heightPerMinute,
timeLineWidth: timeLineWidth,
startTime: startTime,
),
Align(
alignment: Alignment.centerRight,
Expand Down
Loading

0 comments on commit d39475f

Please sign in to comment.