[gnome-shell/4592-calendar-correct-handling-of-recurring-events: 23/23] calendar: Correct handling of recurring events
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/4592-calendar-correct-handling-of-recurring-events: 23/23] calendar: Correct handling of recurring events
- Date: Wed, 31 Aug 2022 10:07:36 +0000 (UTC)
commit 3f2475f21e018f5e82547afcf9aca1125e129ff0
Author: Milan Crha <mcrha redhat com>
Date: Mon Jun 6 17:31:23 2022 +0200
calendar: Correct handling of recurring events
When a recurring event has deleted a single instance, it's received
as an event modification, thus make sure all of the old instances
are removed before adding the event to the list of events.
Closes https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4592
js/ui/calendar.js | 28 +++++++++++-----
src/calendar-server/gnome-shell-calendar-server.c | 41 ++++++++++++++++++++++-
2 files changed, 60 insertions(+), 9 deletions(-)
---
diff --git a/js/ui/calendar.js b/js/ui/calendar.js
index 90ef9cc959..84bdaeea88 100644
--- a/js/ui/calendar.js
+++ b/js/ui/calendar.js
@@ -273,6 +273,15 @@ class DBusEventSource extends EventSourceBase {
this._lastRequestEnd = null;
}
+ _removeMatching(uidPrefix) {
+ let changed = false;
+ for (const id of this._events.keys()) {
+ if (id.startsWith(uidPrefix))
+ changed = this._events.delete(id) || changed;
+ }
+ return changed;
+ }
+
_onNameAppeared() {
this._initialized = true;
this._resetCache();
@@ -287,12 +296,21 @@ class DBusEventSource extends EventSourceBase {
_onEventsAddedOrUpdated(dbusProxy, nameOwner, argArray) {
const [appointments = []] = argArray;
let changed = false;
+ const handledRemovals = new Set();
for (let n = 0; n < appointments.length; n++) {
const [id, summary, startTime, endTime] = appointments[n];
const date = new Date(startTime * 1000);
const end = new Date(endTime * 1000);
let event = new CalendarEvent(id, date, end, summary);
+ /* It's a recurring event */
+ if (!id.endsWith('\n')) {
+ const parentId = id.substr(0, id.lastIndexOf('\n') + 1);
+ if (!handledRemovals.has(parentId)) {
+ handledRemovals.add(parentId);
+ this._removeMatching(parentId);
+ }
+ }
this._events.set(event.id, event);
changed = true;
@@ -307,7 +325,7 @@ class DBusEventSource extends EventSourceBase {
let changed = false;
for (const id of ids)
- changed ||= this._events.delete(id);
+ changed = this._removeMatching(id) || changed;
if (changed)
this.emit('changed');
@@ -317,13 +335,7 @@ class DBusEventSource extends EventSourceBase {
let [sourceUid = ''] = argArray;
sourceUid += '\n';
- let changed = false;
- for (const id of this._events.keys()) {
- if (id.startsWith(sourceUid))
- changed ||= this._events.delete(id);
- }
-
- if (changed)
+ if (this._removeMatching(sourceUid))
this.emit('changed');
}
diff --git a/src/calendar-server/gnome-shell-calendar-server.c
b/src/calendar-server/gnome-shell-calendar-server.c
index f1980c633c..4cd28d1c27 100644
--- a/src/calendar-server/gnome-shell-calendar-server.c
+++ b/src/calendar-server/gnome-shell-calendar-server.c
@@ -438,20 +438,30 @@ app_process_added_modified_objects (App *app,
GSList *objects) /* ICalComponent * */
{
ECalClient *cal_client;
+ g_autoptr(GHashTable) covered_uids = NULL;
GSList *link;
gboolean expand_recurrences;
cal_client = e_cal_client_view_ref_client (view);
+ covered_uids = g_hash_table_new (g_str_hash, g_str_equal);
expand_recurrences = e_cal_client_get_source_type (cal_client) == E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
for (link = objects; link; link = g_slist_next (link))
{
ECalComponent *comp;
ICalComponent *icomp = link->data;
+ const gchar *uid;
+ gboolean fallback = FALSE;
- if (!icomp || !i_cal_component_get_uid (icomp))
+ if (!icomp)
continue;
+ uid = i_cal_component_get_uid (icomp);
+ if (!uid || g_hash_table_contains (covered_uids, uid))
+ continue;
+
+ g_hash_table_add (covered_uids, (gpointer) uid);
+
if (expand_recurrences &&
!e_cal_util_component_is_instance (icomp) &&
e_cal_util_component_has_recurrences (icomp))
@@ -464,7 +474,36 @@ app_process_added_modified_objects (App *app,
e_cal_client_generate_instances_for_object_sync (cal_client, icomp, app->since, app->until, NULL,
generate_instances_cb, &data);
}
+ else if (expand_recurrences &&
+ e_cal_util_component_is_instance (icomp))
+ {
+ ICalComponent *main_comp = NULL;
+
+ /* Always pass whole series of the recurring events, because
+ * the calendar removes events with the same UID first. */
+ if (e_cal_client_get_object_sync (cal_client, uid, NULL, &main_comp, NULL, NULL))
+ {
+ CollectAppointmentsData data;
+
+ data.client = cal_client;
+ data.pappointments = &app->notify_appointments;
+
+ e_cal_client_generate_instances_for_object_sync (cal_client, main_comp, app->since,
app->until, NULL,
+ generate_instances_cb, &data);
+
+ g_clear_object (&main_comp);
+ }
+ else
+ {
+ fallback = TRUE;
+ }
+ }
else
+ {
+ fallback = TRUE;
+ }
+
+ if (fallback)
{
comp = e_cal_component_new_from_icalcomponent (i_cal_component_clone (icomp));
if (!comp)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]