Ignore local calendar applying changes to prevent duplicate operations.

This commit is contained in:
Burak Kaan Köse
2026-02-15 19:44:07 +01:00
parent ff25db3fea
commit d428a6ce7a
2 changed files with 36 additions and 3 deletions
@@ -963,6 +963,15 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
base.OnCalendarItemUpdated(calendarItem, source);
Debug.WriteLine($"Calendar item updated: {calendarItem.Id}");
// Local-only calendar operations are persisted immediately without real network I/O.
// Ignore optimistic client updates to prevent applying the same mutation twice.
var isLocalCalendarUpdate = string.IsNullOrWhiteSpace(calendarItem.RemoteEventId) ||
calendarItem.RemoteEventId.StartsWith("local-", StringComparison.OrdinalIgnoreCase);
if (isLocalCalendarUpdate && source == CalendarItemUpdateSource.ClientUpdated)
{
return;
}
// Series master events should not be visible on the UI.
if (calendarItem.IsRecurringParent)
{
@@ -704,9 +704,12 @@ public class ImapSynchronizer : WinoSynchronizer<ImapRequest, ImapMessageCreatio
// This is important to reflect changes to the UI before the network call is done.
foreach (var item in batchedRequests)
{
if (ShouldApplyOptimisticUIChanges(item.Request))
{
item.Request.ApplyUIChanges();
}
}
// All task bundles will execute on the same client.
// Tasks themselves don't pull the client from the pool
@@ -734,7 +737,10 @@ public class ImapSynchronizer : WinoSynchronizer<ImapRequest, ImapMessageCreatio
// Client pool failed to get a client.
// Requests may not be executed at this point.
if (ShouldApplyOptimisticUIChanges(item.Request))
{
item.Request.RevertUIChanges();
}
isCrashed = true;
throw;
@@ -767,8 +773,11 @@ public class ImapSynchronizer : WinoSynchronizer<ImapRequest, ImapMessageCreatio
var handled = await _errorHandlerFactory.HandleErrorAsync(errorContext).ConfigureAwait(false);
if (!handled)
{
if (ShouldApplyOptimisticUIChanges(item.Request))
{
item.Request.RevertUIChanges();
}
throw;
}
}
@@ -782,6 +791,21 @@ public class ImapSynchronizer : WinoSynchronizer<ImapRequest, ImapMessageCreatio
}
}
private bool ShouldApplyOptimisticUIChanges(IRequestBase request)
{
// Mail changes are always applied.
// Calendar changes are applied only if calendar is not in local mode.
// Database updates are immidiate and will be reflected in the UI right after the request is processed, so no need for optimistic changes.
if (request is not ICalendarActionRequest)
{
return true;
}
var mode = Account.ServerInformation?.CalendarSupportMode ?? ImapCalendarSupportMode.Disabled;
return mode != ImapCalendarSupportMode.LocalOnly;
}
/// <summary>
/// Assigns special folder type for the given local folder.
/// If server doesn't support special folders, we can't determine the type. MailKit will throw for GetFolder.