Skip to content

Commit

Permalink
Merge pull request #324 from FCView/develop
Browse files Browse the repository at this point in the history
Enable multiple-day allDay events on Android
  • Loading branch information
thomassth authored Dec 23, 2021
2 parents 33f97e7 + 198735a commit bfbc843
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -468,25 +468,10 @@ class CalendarDelegate : PluginRegistry.RequestPermissionsResultListener {
val values = ContentValues()
val duration: String? = null
values.put(Events.ALL_DAY, event.eventAllDay)

if (event.eventAllDay) {
val calendar = java.util.Calendar.getInstance()
calendar.timeInMillis = event.eventStartDate!!
calendar.set(java.util.Calendar.HOUR, 0)
calendar.set(java.util.Calendar.MINUTE, 0)
calendar.set(java.util.Calendar.SECOND, 0)
calendar.set(java.util.Calendar.MILLISECOND, 0)

values.put(Events.DTSTART, calendar.timeInMillis)
values.put(Events.DTEND, calendar.timeInMillis)
values.put(Events.EVENT_TIMEZONE, getTimeZone(event.eventStartTimeZone).id)
} else {
values.put(Events.DTSTART, event.eventStartDate!!)
values.put(Events.EVENT_TIMEZONE, getTimeZone(event.eventStartTimeZone).id)

values.put(Events.DTEND, event.eventEndDate!!)
values.put(Events.EVENT_END_TIMEZONE, getTimeZone(event.eventEndTimeZone).id)
}
values.put(Events.DTSTART, event.eventStartDate!!)
values.put(Events.EVENT_TIMEZONE, getTimeZone(event.eventStartTimeZone).id)
values.put(Events.DTEND, event.eventEndDate!!)
values.put(Events.EVENT_END_TIMEZONE, getTimeZone(event.eventEndTimeZone).id)
values.put(Events.TITLE, event.eventTitle)
values.put(Events.DESCRIPTION, event.eventDescription)
values.put(Events.EVENT_LOCATION, event.eventLocation)
Expand Down
32 changes: 25 additions & 7 deletions example/lib/presentation/event_item.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:io';
import 'package:device_calendar/device_calendar.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
Expand Down Expand Up @@ -76,10 +77,9 @@ class _EventItemState extends State<EventItem> {
Text(
widget._calendarEvent == null
? ''
: DateFormat('yyyy-MM-dd HH:mm:ss').format(
TZDateTime.from(
widget._calendarEvent!.start!,
_currentLocation!)),
: _formatDateTime(
dateTime: widget._calendarEvent!.start!,
),
)
],
),
Expand All @@ -99,9 +99,9 @@ class _EventItemState extends State<EventItem> {
Text(
widget._calendarEvent?.end == null
? ''
: DateFormat('yyyy-MM-dd HH:mm:ss').format(
TZDateTime.from(widget._calendarEvent!.end!,
_currentLocation!)),
: _formatDateTime(
dateTime: widget._calendarEvent!.end!,
),
),
],
),
Expand Down Expand Up @@ -301,4 +301,22 @@ class _EventItemState extends State<EventItem> {
_currentLocation = timeZoneDatabase.locations[timezone];
setState(() {});
}

/// Formats [dateTime] into a human-readable string.
/// If [_calendarEvent] is an Android allDay event, then the output will
/// omit the time.
String _formatDateTime({DateTime? dateTime}) {
if (dateTime == null) {
return 'Error';
}
var output = '';
if (Platform.isAndroid && widget._calendarEvent?.allDay == true) {
// just the dates, no times
output = DateFormat.yMd().format(dateTime);
} else {
output = DateFormat('yyyy-MM-dd HH:mm:ss')
.format(TZDateTime.from(dateTime, _currentLocation!));
}
return output;
}
}
32 changes: 18 additions & 14 deletions example/lib/presentation/pages/calendar_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -299,26 +299,29 @@ class _CalendarEventPageState extends State<CalendarEventPage> {
},
),
),
if (_event?.allDay == false) ...[
if (Platform.isAndroid)
Padding(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
initialValue: _event?.start?.location.name,
decoration: const InputDecoration(
labelText: 'Start date time zone',
hintText: 'Australia/Sydney'),
onSaved: (String? value) {
_event?.updateStartLocation(value);
},
),
if ((_event?.allDay == false) && Platform.isAndroid)
Padding(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
initialValue: _event?.start?.location.name,
decoration: const InputDecoration(
labelText: 'Start date time zone',
hintText: 'Australia/Sydney'),
onSaved: (String? value) {
_event?.updateStartLocation(value);
},
),
),
// Only add the 'To' Date for non-allDay events on all
// platforms except Android (which allows multiple-day allDay events)
if (_event?.allDay == false || Platform.isAndroid)
Padding(
padding: const EdgeInsets.all(10.0),
child: DateTimePicker(
labelText: 'To',
selectedDate: _endDate,
selectedTime: _endTime,
enableTime: _event?.allDay == false,
selectDate: (DateTime date) {
setState(
() {
Expand All @@ -344,6 +347,7 @@ class _CalendarEventPageState extends State<CalendarEventPage> {
},
),
),
if (_event?.allDay == false && Platform.isAndroid)
Padding(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
Expand All @@ -355,7 +359,6 @@ class _CalendarEventPageState extends State<CalendarEventPage> {
_event?.updateEndLocation(value),
),
),
],
GestureDetector(
onTap: () async {
var result = await Navigator.push(
Expand Down Expand Up @@ -1007,6 +1010,7 @@ class _CalendarEventPageState extends State<CalendarEventPage> {
currentLocation!);

if (time == null) return dateWithoutTime;
if (Platform.isAndroid && _event?.allDay == true) return dateWithoutTime;

return dateWithoutTime
.add(Duration(hours: time.hour, minutes: time.minute));
Expand Down
18 changes: 15 additions & 3 deletions lib/src/device_calendar.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:collection';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Expand Down Expand Up @@ -211,14 +212,25 @@ class DeviceCalendarPlugin {
if (event.start != null) {
var dateStart = DateTime(event.start!.year, event.start!.month,
event.start!.day, 0, 0, 0);
event.start = TZDateTime.from(dateStart,
// allDay events on Android need to be at midnight UTC
event.start = Platform.isAndroid
? TZDateTime.utc(event.start!.year, event.start!.month,
event.start!.day, 0, 0, 0)
: TZDateTime.from(dateStart,
timeZoneDatabase.locations[event.start!.location.name]!);
}
if (event.end != null) {
var dateEnd = DateTime(
event.end!.year, event.end!.month, event.end!.day, 0, 0, 0);
event.end = TZDateTime.from(
dateEnd, timeZoneDatabase.locations[event.end!.location.name]!);
// allDay events on Android need to be at midnight UTC on the
// day after the last day. For example, a 2-day allDay event on
// Jan 1 and 2, should be from Jan 1 00:00:00 to Jan 3 00:00:00
event.end = Platform.isAndroid
? TZDateTime.utc(event.end!.year, event.end!.month,
event.end!.day, 0, 0, 0)
.add(Duration(days: 1))
: TZDateTime.from(dateEnd,
timeZoneDatabase.locations[event.end!.location.name]!);
}
}

Expand Down
18 changes: 16 additions & 2 deletions lib/src/models/event.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:io';

import '../../device_calendar.dart';
import '../common/error_messages.dart';
import 'package:timezone/timezone.dart';
Expand Down Expand Up @@ -79,12 +81,24 @@ class Event {
final int? endTimestamp = json['eventEndDate'];
final String? endLocationName = json['eventEndTimeZone'];
var endLocation = timeZoneDatabase.locations[endLocationName];
endLocation ??= local;
endLocation ??= startTimeZone;
end = endTimestamp != null
? TZDateTime.fromMillisecondsSinceEpoch(endLocation, endTimestamp)
: TZDateTime.now(local);

allDay = json['eventAllDay'] ?? false;
if (Platform.isAndroid && (allDay ?? false)){
// On Android, the datetime in an allDay event is adjusted to local
// timezone, which can result in the wrong day, so we need to bring the
// date back to midnight UTC to get the correct date
var startOffset = start?.timeZoneOffset.inMilliseconds ?? 0;
var endOffset = end?.timeZoneOffset.inMilliseconds ?? 0;
// subtract the offset to get back to midnight on the correct date
start = start?.subtract(Duration(milliseconds: startOffset));
end = end?.subtract(Duration(milliseconds: endOffset));
// The Event End Date for allDay events is midnight of the next day, so
// subtract one day
end = end?.subtract(Duration(days: 1));
}
location = json['eventLocation'];
availability = parseStringToAvailability(json['availability']);

Expand Down

0 comments on commit bfbc843

Please sign in to comment.