[gnome-calendar/fix-shifting-events: 5/5] manager: Fix bug where recurring events shift after being edited




commit 18947772e574889fa8f38e270c5de4c3f5b2006a
Author: Ray Strode <rstrode redhat com>
Date:   Tue Oct 11 15:33:36 2022 -0400

    manager: Fix bug where recurring events shift after being edited
    
    Right now if a user edits say event 3 in a set of 5 events, the
    whole event set gets shifted over by 3. It's as if the middle
    instance event is treated as the new first event.
    
    This is because of a bit of the code that clears the recurrence
    id of the event, to get at the "main event", and edit the whole
    set. The code retains the start time from the instance, though,
    rather than use the start time of the main event it's trying to
    update.
    
    This commit queries for the main event from the instance event,
    and sets the new main event start time to match the old main
    event start time, before doing an update.

 src/core/gcal-event.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 77 insertions(+), 7 deletions(-)
---
diff --git a/src/core/gcal-event.c b/src/core/gcal-event.c
index 6afc044c..632d3eb3 100644
--- a/src/core/gcal-event.c
+++ b/src/core/gcal-event.c
@@ -832,13 +832,45 @@ gcal_event_new_from_event (GcalEvent *self)
   return gcal_event_new (self->calendar, component, NULL);
 }
 
+static void
+gcal_event_get_time_offsets (GcalEvent *self,
+                             GTimeSpan *start_offset,
+                             GTimeSpan *end_offset)
+{
+  GDateTime *start_time = NULL;
+  GDateTime *end_time = NULL;
+  g_autoptr (GDateTime) start_day = NULL;
+  g_autoptr (GDateTime) end_day = NULL;
+
+  start_time = gcal_event_get_date_start (self);
+  end_time = gcal_event_get_date_end (self);
+
+  start_day = g_date_time_new (g_date_time_get_timezone (start_time),
+                               g_date_time_get_year (start_time),
+                               g_date_time_get_month (start_time),
+                               g_date_time_get_day_of_month (start_time),
+                               0, 0, 0);
+  end_day = g_date_time_new (g_date_time_get_timezone (end_time),
+                             g_date_time_get_year (end_time),
+                             g_date_time_get_month (end_time),
+                             g_date_time_get_day_of_month (end_time),
+                             0, 0, 0);
+
+  *start_offset = g_date_time_difference (start_time, start_day);
+  *end_offset = g_date_time_difference (end_time, end_day);
+}
+
 /**
  * gcal_event_new_main_event_from_instance_event:
  * @self: a #GcalEvent
  *
  * Creates a main @event from an instance event. This is useful
  * for updating all recurring events at the same time to match
- * the contence of one instance in the set.
+ * the content of one instance in the set.
+ *
+ * Note, if the instance start time has been changed, the generated
+ * main event will be updated to reflect that new start time as
+ * well.
  *
  * Returns: (transfer full)(nullable): a #GcalEvent
  */
@@ -849,7 +881,7 @@ gcal_event_new_main_event_from_instance_event (GcalEvent *self)
 
   g_autoptr (ECalComponent) new_main_ecal_component = NULL;
   g_autoptr (ECalComponent) old_main_ecal_component = NULL;
-  ECalComponentDateTime *start_date = NULL;
+  ECalComponentDateTime *instance_start_date = NULL;
   ECalComponentDateTime *end_date = NULL;
   g_autoptr (GError) error = NULL;
   ECalClient *client;
@@ -890,13 +922,17 @@ gcal_event_new_main_event_from_instance_event (GcalEvent *self)
   /* Copy the start time and end time from the old main event to the new one
    * and clear the recurrence id.
    */
-  start_date = e_cal_component_get_dtstart (old_main_ecal_component);
-  e_cal_component_set_dtstart (new_main_ecal_component, start_date);
-  g_clear_pointer (&start_date, e_cal_component_datetime_free);
+  instance_start_date = e_cal_component_get_dtstart (old_main_ecal_component);
+  e_cal_component_set_dtstart (new_main_ecal_component, instance_start_date);
+  g_clear_pointer (&instance_start_date, e_cal_component_datetime_free);
 
   end_date = e_cal_component_get_dtend (old_main_ecal_component);
-  e_cal_component_set_dtend (new_main_ecal_component, end_date);
-  g_clear_pointer (&end_date, e_cal_component_datetime_free);
+
+  if (end_date != NULL)
+    {
+      e_cal_component_set_dtend (new_main_ecal_component, end_date);
+      g_clear_pointer (&end_date, e_cal_component_datetime_free);
+    }
 
   e_cal_component_set_recurid (new_main_ecal_component, NULL);
   e_cal_component_commit_sequence (new_main_ecal_component);
@@ -909,6 +945,40 @@ gcal_event_new_main_event_from_instance_event (GcalEvent *self)
       return NULL;
     }
 
+  if (!self->all_day)
+    {
+      GTimeSpan instance_event_start_offset = 0, main_event_start_offset = 0;
+      GTimeSpan instance_event_end_offset = 0, main_event_end_offset = 0;
+      g_autoptr (GDateTime) main_event_instance_start_date = NULL;
+      g_autoptr (GDateTime) main_event_end_date = NULL;
+
+      gcal_event_set_all_day (main_event, FALSE);
+
+      gcal_event_get_time_offsets (self,
+                                   &instance_event_start_offset,
+                                   &instance_event_end_offset);
+
+      if (end_date != NULL)
+        gcal_event_get_time_offsets (main_event,
+                                     &main_event_start_offset,
+                                     &main_event_end_offset);
+
+      if (instance_event_start_offset != main_event_start_offset)
+        {
+          main_event_instance_start_date = g_date_time_add (main_event->dt_start,
+                                                            instance_event_start_offset - 
main_event_start_offset);
+          gcal_event_set_date_start (main_event, main_event_instance_start_date);
+        }
+
+      if (instance_event_end_offset != main_event_end_offset)
+        {
+          main_event_end_date = g_date_time_add (main_event->dt_end,
+                                                 instance_event_end_offset - main_event_end_offset);
+
+          gcal_event_set_date_end (main_event, main_event_end_date);
+        }
+    }
+
   return main_event;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]