diff --git a/example/pubspec.lock b/example/pubspec.lock index 1429995..9d055ae 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -105,9 +105,11 @@ packages: time_machine: dependency: "direct main" description: - name: time_machine - url: "https://pub.dartlang.org" - source: hosted + path: "." + ref: "fix/localdate-today-calendar" + resolved-ref: c65f0a3b8e98d9966684d091f34d44aaad024c20 + url: "https://github.com/JonasWanke/time_machine.git" + source: git version: "0.9.12" timetable: dependency: "direct main" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4375638..ac40ef7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,10 @@ dependencies: timetable: path: ../ - time_machine: ^0.9.12 + time_machine: + git: + url: https://github.com/JonasWanke/time_machine.git + ref: fix/localdate-today-calendar flutter: uses-material-design: true diff --git a/lib/src/content/current_time_indicator_painter.dart b/lib/src/content/current_time_indicator_painter.dart index 7f16442..23c5166 100644 --- a/lib/src/content/current_time_indicator_painter.dart +++ b/lib/src/content/current_time_indicator_painter.dart @@ -32,8 +32,8 @@ class CurrentTimeIndicatorPainter extends CustomPainter { void paint(Canvas canvas, Size size) { final dateWidth = size.width / controller.visibleRange.visibleDays; - final temporalOffset = - LocalDate.today().epochDay - controller.scrollControllers.page; + final temporalOffset = LocalDate.today(controller.calendar).epochDay - + controller.scrollControllers.page; final left = temporalOffset * dateWidth; final right = left + dateWidth; diff --git a/lib/src/content/date_events.dart b/lib/src/content/date_events.dart index 7179164..f6d74a8 100644 --- a/lib/src/content/date_events.dart +++ b/lib/src/content/date_events.dart @@ -8,7 +8,6 @@ import 'package:time_machine/time_machine.dart' hide Offset; import '../event.dart'; import '../theme.dart'; import '../timetable.dart'; -import '../utils/utils.dart'; class DateEvents extends StatelessWidget { DateEvents({ @@ -145,16 +144,17 @@ class _DayEventsLayoutDelegate final positions = _EventPositions(); var currentGroup = []; - var currentEnd = TimetableLocalDateTime.minIsoValue; + LocalDateTime currentEnd; for (final event in events) { - if (event.start >= currentEnd) { + if (currentEnd != null || event.start >= currentEnd) { _endGroup(positions, currentGroup, height); currentGroup = []; - currentEnd = TimetableLocalDateTime.minIsoValue; + currentEnd = null; } currentGroup.add(event); - currentEnd = currentEnd.coerceAtLeast(_actualEnd(event, height)); + final eventEnd = _actualEnd(event, height); + currentEnd = currentEnd?.coerceAtLeast(eventEnd) ?? eventEnd; } _endGroup(positions, currentGroup, height); @@ -177,7 +177,7 @@ class _DayEventsLayoutDelegate for (final event in currentGroup) { var minColumn = -1; var minIndex = 1 << 31; - var minEnd = TimetableLocalDateTime.minIsoValue; + LocalDateTime minEnd; var columnFound = false; for (var columnIndex = 0; columnIndex < columns.length; columnIndex++) { final column = columns[columnIndex]; @@ -193,12 +193,10 @@ class _DayEventsLayoutDelegate .map((e) => positions.eventPositions[e].index) .max() ?? -1; - final previousEnd = column.fold( - TimetableLocalDateTime.maxIsoValue, - (max, e) => LocalDateTime.max(max, e.end), - ); + final previousEnd = column.map((e) => e.end).max(); // Further at the top and hence wider - if (index < minIndex || (index == minIndex && previousEnd < minEnd)) { + if (index < minIndex || + (index == minIndex && minEnd != null && previousEnd < minEnd)) { minColumn = columnIndex; minIndex = index; minEnd = previousEnd; diff --git a/lib/src/controller.dart b/lib/src/controller.dart index f6887f6..85245ca 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -14,13 +14,18 @@ import 'visible_range.dart'; /// Controls a [Timetable] and manages its state. class TimetableController { TimetableController({ + CalendarSystem calendar, @required this.eventProvider, LocalDate initialDate, this.initialTimeRange = const InitialTimeRange.zoom(1), this.visibleRange = const VisibleRange.week(), this.firstDayOfWeek = DayOfWeek.monday, - }) : assert(eventProvider != null), - initialDate = initialDate ?? LocalDate.today(), + }) : calendar = calendar ?? _defaultCalendar, + assert(eventProvider != null), + initialDate = + initialDate ?? LocalDate.today(calendar ?? _defaultCalendar), + assert(initialDate == null || initialDate.calendar == calendar ?? + _defaultCalendar), assert(initialTimeRange != null), assert(firstDayOfWeek != null), assert(visibleRange != null) { @@ -31,12 +36,15 @@ class TimetableController { ); _dateListenable = scrollControllers.pageListenable - .map((page) => LocalDate.fromEpochDay(page.floor())); + .map((page) => LocalDate.fromEpochDay(page.floor(), calendar)); _currentlyVisibleDatesListenable = scrollControllers.pageListenable .map((page) { return DateInterval( - LocalDate.fromEpochDay(page.floor()), - LocalDate.fromEpochDay(page.ceil() + visibleRange.visibleDays - 1), + LocalDate.fromEpochDay(page.floor(), calendar), + LocalDate.fromEpochDay( + page.ceil() + visibleRange.visibleDays - 1, + calendar, + ), ); }) ..addListener( @@ -44,6 +52,16 @@ class TimetableController { eventProvider.onVisibleDatesChanged(currentlyVisibleDates); } + static final _defaultCalendar = CalendarSystem.iso; + + /// The [CalendarSystem] used for all dates and times. + /// + /// All [LocalDate]s and [LocalDateTime]s you pass to timetable must use this + /// calendar. + /// + /// Defaults to [CalendarSystem.iso]. + final CalendarSystem calendar; + /// The [EventProvider] used for populating [Timetable] with events. final EventProvider eventProvider; @@ -89,7 +107,7 @@ class TimetableController { Curve curve = Curves.easeInOut, Duration duration = const Duration(milliseconds: 200), }) => - animateTo(LocalDate.today(), curve: curve, duration: duration); + animateTo(LocalDate.today(calendar), curve: curve, duration: duration); /// Animates the given [date] into view. /// @@ -99,6 +117,8 @@ class TimetableController { Curve curve = Curves.easeInOut, Duration duration = const Duration(milliseconds: 200), }) async { + assert(date.calendar == calendar); + await scrollControllers.animateTo( visibleRange.getTargetPageForFocusDate(date, firstDayOfWeek), curve: curve, diff --git a/lib/src/date_page_view.dart b/lib/src/date_page_view.dart index 9a1a032..d084fea 100644 --- a/lib/src/date_page_view.dart +++ b/lib/src/date_page_view.dart @@ -6,7 +6,9 @@ import 'event.dart'; import 'scroll_physics.dart'; typedef DateWidgetBuilder = Widget Function( - BuildContext context, LocalDate date); + BuildContext context, + LocalDate date, +); class DatePageView extends StatefulWidget { const DatePageView({ @@ -58,7 +60,10 @@ class _DatePageViewState extends State { delegate: SliverChildBuilderDelegate( (context, index) => widget.builder( context, - LocalDate.fromEpochDay(index + visibleDays ~/ 2), + LocalDate.fromEpochDay( + index + visibleDays ~/ 2, + widget.controller.calendar, + ), ), ), ), diff --git a/lib/src/event.dart b/lib/src/event.dart index eaf38e2..4d81f47 100644 --- a/lib/src/event.dart +++ b/lib/src/event.dart @@ -29,6 +29,12 @@ abstract class Event { // End of the event; exclusive. final LocalDateTime end; + CalendarSystem get calendar { + // TODO(JonasWanke): Check this in the constructor + assert(start.calendar == end.calendar); + return start.calendar; + } + bool get isAllDay => start.periodUntil(end).normalize().days >= 1; bool get isPartDay => !isAllDay; @@ -52,6 +58,8 @@ extension TimetableEvent on Event { intersectsInterval(DateInterval(date, date)); bool intersectsInterval(DateInterval interval) { + assert(calendar == interval.calendar); + return start.calendarDate <= interval.end && endDateInclusive >= interval.start; } diff --git a/lib/src/header/all_day_events.dart b/lib/src/header/all_day_events.dart index 9177e58..bb27990 100644 --- a/lib/src/header/all_day_events.dart +++ b/lib/src/header/all_day_events.dart @@ -263,7 +263,8 @@ class _EventsLayout extends RenderBox double _parallelEventCount() { int parallelEventsFrom(int page) { - final startDate = LocalDate.fromEpochDay(page); + final startDate = + LocalDate.fromEpochDay(page, currentlyVisibleDates.calendar); final interval = DateInterval( startDate, startDate + Period(days: visibleRange.visibleDays - 1), diff --git a/lib/src/header/date_header.dart b/lib/src/header/date_header.dart index 2f650a5..0e99d4e 100644 --- a/lib/src/header/date_header.dart +++ b/lib/src/header/date_header.dart @@ -5,7 +5,9 @@ import 'date_indicator.dart'; import 'weekday_indicator.dart'; class DateHeader extends StatelessWidget { - const DateHeader(this.date, {Key key}) : super(key: key); + const DateHeader(this.date, {Key key}) + : assert(date != null), + super(key: key); final LocalDate date; diff --git a/lib/src/header/date_indicator.dart b/lib/src/header/date_indicator.dart index bc28fdd..a547dd2 100644 --- a/lib/src/header/date_indicator.dart +++ b/lib/src/header/date_indicator.dart @@ -6,7 +6,9 @@ import '../theme.dart'; import '../utils/utils.dart'; class DateIndicator extends StatelessWidget { - const DateIndicator(this.date, {Key key}) : super(key: key); + const DateIndicator(this.date, {Key key}) + : assert(date != null), + super(key: key); final LocalDate date; @@ -44,7 +46,7 @@ class DateIndicator extends StatelessWidget { static Set statesFor(LocalDate date) { return { - if (date < LocalDate.today()) MaterialState.disabled, + if (date < LocalDate.today(date.calendar)) MaterialState.disabled, if (date.isToday) MaterialState.selected, }; } diff --git a/lib/src/header/weekday_indicator.dart b/lib/src/header/weekday_indicator.dart index 3fbb45e..f0bfa43 100644 --- a/lib/src/header/weekday_indicator.dart +++ b/lib/src/header/weekday_indicator.dart @@ -8,7 +8,9 @@ import '../utils/utils.dart'; import 'date_indicator.dart'; class WeekdayIndicator extends StatelessWidget { - const WeekdayIndicator(this.date, {Key key}) : super(key: key); + const WeekdayIndicator(this.date, {Key key}) + : assert(date != null), + super(key: key); static final _pattern = LocalDatePattern.createWithCurrentCulture('ddd'); diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart index b38e3d7..4faa188 100644 --- a/lib/src/utils/utils.dart +++ b/lib/src/utils/utils.dart @@ -2,19 +2,12 @@ import 'package:flutter/foundation.dart'; import 'package:time_machine/time_machine.dart'; extension TimetableLocalDate on LocalDate { - bool get isToday => this == LocalDate.today(); + bool get isToday => this == LocalDate.today(calendar); } final List innerDateHours = List.generate(TimeConstants.hoursPerDay - 1, (i) => i + 1); -extension TimetableLocalDateTime on LocalDateTime { - static LocalDateTime minIsoValue = - LocalDate.minIsoValue.at(LocalTime.minValue); - static LocalDateTime maxIsoValue = - LocalDate.maxIsoValue.at(LocalTime.maxValue); -} - extension TimetableDateInterval on DateInterval { Iterable get dates => Iterable.generate(length, start.addDays); } diff --git a/lib/src/visible_range.dart b/lib/src/visible_range.dart index d62459a..26285ee 100644 --- a/lib/src/visible_range.dart +++ b/lib/src/visible_range.dart @@ -32,8 +32,11 @@ abstract class VisibleRange { /// Convenience method of [getTargetPageForFocus] taking a [LocalDate]. double getTargetPageForFocusDate( - LocalDate focusDate, DayOfWeek firstDayOfWeek) { + LocalDate focusDate, + DayOfWeek firstDayOfWeek, + ) { assert(focusDate != null); + return getTargetPageForFocus(focusDate.epochDay.toDouble(), firstDayOfWeek); } diff --git a/pubspec.yaml b/pubspec.yaml index b2b91de..be29351 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,10 @@ dependencies: meta: ^1.1.8 pedantic: ^1.8.0+1 rxdart: ^0.24.0 - time_machine: ^0.9.12 + time_machine: + git: + url: https://github.com/JonasWanke/time_machine.git + ref: fix/localdate-today-calendar dev_dependencies: flutter_test: