Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'jb33108' into 'master'
[buteo-sync-plugins-social] Upsync calendar event alarms. Contributes to JB#33108

See merge request mer-core/buteo-sync-plugins-social!35
  • Loading branch information
chriadam committed Jan 14, 2019
2 parents 4084024 + d8c1691 commit 827833f
Showing 1 changed file with 47 additions and 49 deletions.
96 changes: 47 additions & 49 deletions src/google/google-calendars/googlecalendarsyncadaptor.cpp
Expand Up @@ -31,6 +31,7 @@
#include <QtCore/QJsonObject>
#include <QtCore/QJsonDocument>
#include <QtCore/QSettings>
#include <QtCore/QSet>

#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
Expand Down Expand Up @@ -400,7 +401,7 @@ KDateTime parseRecurrenceId(const QJsonObject &originalStartTime)
QJsonObject kCalToJson(KCalCore::Event::Ptr event, KCalCore::ICalFormat &icalFormat, bool setUidProperty = false)
{
QString eventId = gCalEventId(event);
QJsonObject start, end, reminders;
QJsonObject start, end;

QJsonArray attendees;
const KCalCore::Attendee::List attendeesList = event->attendees();
Expand Down Expand Up @@ -458,11 +459,30 @@ QJsonObject kCalToJson(KCalCore::Event::Ptr event, KCalCore::ICalFormat &icalFor
//retn.insert(QLatin1String("locked"), event->readOnly()); // only allow locking server-side.
// we may wish to support locking/readonly from local side also, in the future.

// if the event has no alarms associated with it, don't let Google add one automatically.
if (event->alarms().count() == 0) {
// if the event has no alarms associated with it, don't let Google add one automatically
// otherwise, attempt to upsync the alarms as popup reminders.
QJsonObject reminders;
if (event->alarms().count()) {
QJsonArray overrides;
KCalCore::Alarm::List alarms = event->alarms();
for (int i = 0; i < alarms.count(); ++i) {
// only upsync non-procedure alarms as popup reminders.
QSet<int> seenMinutes;
if (alarms.at(i)->type() != KCalCore::Alarm::Procedure) {
const int minutes = (alarms.at(i)->startOffset().asSeconds() / 60) * -1;
if (!seenMinutes.contains(minutes)) {
QJsonObject override;
override.insert(QLatin1String("method"), QLatin1String("popup"));
override.insert(QLatin1String("minutes"), minutes);
overrides.append(override);
seenMinutes.insert(minutes);
}
}
}
reminders.insert(QLatin1String("overrides"), overrides);
}
reminders.insert(QLatin1String("useDefault"), false);
retn.insert(QLatin1String("reminders"), reminders);
}

if (setUidProperty) {
// now we store private extended properties: local uid.
Expand Down Expand Up @@ -700,34 +720,6 @@ void extractAttendees(const QJsonArray &attendees, KCalCore::Event::Ptr event)
}
}

int nearestNemoReminderStartOffset(int googleStartOffset)
{
// Google supports arbitrary start offsets, whereas in Nemo's UI
// we only allow specific reminder offsets.
// See nemo-qml-plugin-calendar::NemoCalendarEvent::Reminder for
// those offset definitions.
// Also, Nemo reminder offsets are negative and in seconds,
// whereas Google start offsets are positive and in minutes.
if (googleStartOffset >= 0 && googleStartOffset <= 5) {
return -5 * 60; // 5 minutes before event start
} else if (googleStartOffset > 5 && googleStartOffset <= 15) {
return -15 * 60; // 15 minutes before event start
} else if (googleStartOffset > 15 && googleStartOffset <= 30) {
return -30 * 60; // 30 minutes before event start
} else if (googleStartOffset > 30 && googleStartOffset <= 60) {
return -60 * 60; // 1 hour before event start
} else if (googleStartOffset > 60 && googleStartOffset <= 120) {
return -120 * 60; // 2 hours before event start
} else if (googleStartOffset > 120 && googleStartOffset <= 1440) {
return -1440 * 60; // 1 day before event start (24 hours)
} else if (googleStartOffset > 1440) {
return -2880 * 60; // 2 days before event start (48 hours)
}

// default reminder: 15 minutes before event start.
return -15 * 60;
}

#define START_EVENT_UPDATES_IF_REQUIRED(event, changed) \
if (*changed == false) { \
event->startUpdates(); \
Expand All @@ -750,12 +742,12 @@ int nearestNemoReminderStartOffset(int googleStartOffset)

void extractAlarms(const QJsonObject &json, KCalCore::Event::Ptr event, int defaultReminderStartOffset, bool *changed)
{
int startOffset = -1;
QSet<int> startOffsets;
if (json.contains(QStringLiteral("reminders"))) {
QJsonObject reminders = json.value(QStringLiteral("reminders")).toObject();
if (reminders.value(QStringLiteral("useDefault")).toBool()) {
if (defaultReminderStartOffset > 0) {
startOffset = defaultReminderStartOffset;
startOffsets.insert(defaultReminderStartOffset);
} else {
SOCIALD_LOG_DEBUG("not adding default reminder even though requested: not popup or invalid start offset.");
}
Expand All @@ -764,46 +756,52 @@ void extractAlarms(const QJsonObject &json, KCalCore::Event::Ptr event, int defa
for (int i = 0; i < overrides.size(); ++i) {
QJsonObject override = overrides.at(i).toObject();
if (override.value(QStringLiteral("method")).toString() == QStringLiteral("popup")) {
startOffset = override.value(QStringLiteral("minutes")).toInt();
startOffsets.insert(override.value(QStringLiteral("minutes")).toInt());
}
}
}
if (startOffset > -1) {
startOffset = nearestNemoReminderStartOffset(startOffset);
// search for all reminders to see if they are represented by an alarm.
bool needRemoveAndRecreate = false;
for (QSet<int>::const_iterator it = startOffsets.constBegin(); it != startOffsets.constEnd(); it++) {
const int startOffset = (*it) * -60; // convert minutes to seconds (before event)
SOCIALD_LOG_DEBUG("event needs reminder with start offset (seconds):" << startOffset);
KCalCore::Alarm::List alarms = event->alarms();
int alarmCount = 0;
// check that we have only one non-procedure alarm,
// and then check to see if its start offset is correct.
int alarmsCount = 0;
for (int i = 0; i < alarms.count(); ++i) {
// we don't count Procedure type alarms.
if (alarms.at(i)->type() != KCalCore::Alarm::Procedure) {
alarmCount += 1;
alarmsCount += 1;
if (alarms.at(i)->startOffset().asSeconds() == startOffset) {
// no change required to this alarm.
SOCIALD_LOG_DEBUG("event already has reminder with start offset (seconds):" << startOffset);
} else {
alarmCount += 1; // this will cause alarm modification.
SOCIALD_LOG_DEBUG("event is missing reminder with start offset (seconds):" << startOffset);
needRemoveAndRecreate = true;
}
}
}
if (alarmCount == 1) {
// no need to modify alarms for this event
SOCIALD_LOG_DEBUG("event already has reminder with start offset (seconds):" << startOffset);
} else {
SOCIALD_LOG_DEBUG("setting event reminder with start offset (seconds):" << startOffset);
if (alarmsCount != startOffsets.count()) {
SOCIALD_LOG_DEBUG("event has too many reminders, recreating alarms.");
needRemoveAndRecreate = true;
}
}
if (needRemoveAndRecreate) {
START_EVENT_UPDATES_IF_REQUIRED(event, changed);
KCalCore::Alarm::List alarms = event->alarms();
for (int i = 0; i < alarms.count(); ++i) {
if (alarms.at(i)->type() != KCalCore::Alarm::Procedure) {
event->removeAlarm(alarms.at(i));
}
}
for (QSet<int>::const_iterator it = startOffsets.constBegin(); it != startOffsets.constEnd(); it++) {
const int startOffset = (*it) * -60; // convert minutes to seconds (before event)
SOCIALD_LOG_DEBUG("setting event reminder with start offset (seconds):" << startOffset);
KCalCore::Alarm::Ptr alarm = event->newAlarm();
alarm->setEnabled(true);
alarm->setStartOffset(KCalCore::Duration(startOffset));
}
}
}
if (startOffset == -1) {
if (startOffsets.isEmpty()) {
// no reminders were defined in the json received from Google.
// remove any alarms as required from the local event.
KCalCore::Alarm::List alarms = event->alarms();
Expand Down

0 comments on commit 827833f

Please sign in to comment.