Event details page improvements, calendar item update source.
This commit is contained in:
@@ -141,6 +141,7 @@ public static class GoogleIntegratorExtensions
|
||||
Id = Guid.NewGuid(),
|
||||
TimeZone = calendarListEntry.TimeZone,
|
||||
IsPrimary = calendarListEntry.Primary.GetValueOrDefault(),
|
||||
IsSynchronizationEnabled = true,
|
||||
};
|
||||
|
||||
// Bg color must present. Generate one if doesnt exists.
|
||||
|
||||
@@ -183,6 +183,7 @@ public static class OutlookIntegratorExtensions
|
||||
RemoteCalendarId = outlookCalendar.Id,
|
||||
IsPrimary = outlookCalendar.IsDefaultCalendar.GetValueOrDefault(),
|
||||
Name = outlookCalendar.Name,
|
||||
IsSynchronizationEnabled = true,
|
||||
IsExtended = true,
|
||||
};
|
||||
|
||||
|
||||
@@ -27,13 +27,13 @@ public record AcceptEventRequest(CalendarItem Item, string ResponseMessage = nul
|
||||
Item.Status = CalendarItemStatus.Accepted;
|
||||
|
||||
// Notify UI that the event status was updated
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item));
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item, CalendarItemUpdateSource.ClientUpdated));
|
||||
}
|
||||
|
||||
public override void RevertUIChanges()
|
||||
{
|
||||
// If acceptance fails, revert to the previous status
|
||||
Item.Status = _previousStatus;
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item));
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item, CalendarItemUpdateSource.ClientReverted));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ public record DeclineEventRequest(CalendarItem Item, string ResponseMessage = nu
|
||||
Item.Status = CalendarItemStatus.Cancelled;
|
||||
|
||||
// Notify UI that the event status was updated
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item));
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item, CalendarItemUpdateSource.ClientUpdated));
|
||||
}
|
||||
|
||||
public override void RevertUIChanges()
|
||||
{
|
||||
// If decline fails, revert to the previous status
|
||||
Item.Status = _previousStatus;
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item));
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item, CalendarItemUpdateSource.ClientReverted));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ public record TentativeEventRequest(CalendarItem Item, string ResponseMessage =
|
||||
Item.Status = CalendarItemStatus.Tentative;
|
||||
|
||||
// Notify UI that the event status was updated
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item));
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item, CalendarItemUpdateSource.ClientUpdated));
|
||||
}
|
||||
|
||||
public override void RevertUIChanges()
|
||||
{
|
||||
// If tentative acceptance fails, revert to the previous status
|
||||
Item.Status = _previousStatus;
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item));
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item, CalendarItemUpdateSource.ClientReverted));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public record UpdateCalendarEventRequest(CalendarItem Item, List<CalendarEventAt
|
||||
public override void ApplyUIChanges()
|
||||
{
|
||||
// Notify UI that the event was updated locally
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item));
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item, CalendarItemUpdateSource.ClientUpdated));
|
||||
}
|
||||
|
||||
public override void RevertUIChanges()
|
||||
@@ -42,12 +42,12 @@ public record UpdateCalendarEventRequest(CalendarItem Item, List<CalendarEventAt
|
||||
if (OriginalItem != null && OriginalAttendees != null)
|
||||
{
|
||||
// Send the original item back to restore UI state
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(OriginalItem));
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(OriginalItem, CalendarItemUpdateSource.ClientReverted));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: just notify with current item to trigger refresh
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item));
|
||||
WeakReferenceMessenger.Default.Send(new CalendarItemUpdated(Item, CalendarItemUpdateSource.ClientReverted));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,7 +484,9 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
||||
|
||||
_logger.Debug("Is initial synchronization: {IsInitialSync}", isInitialSync);
|
||||
|
||||
var localCalendars = await _gmailChangeProcessor.GetAccountCalendarsAsync(Account.Id).ConfigureAwait(false);
|
||||
var localCalendars = (await _gmailChangeProcessor.GetAccountCalendarsAsync(Account.Id).ConfigureAwait(false))
|
||||
.Where(c => c.IsSynchronizationEnabled)
|
||||
.ToList();
|
||||
|
||||
// TODO: Better logging and exception handling.
|
||||
foreach (var calendar in localCalendars)
|
||||
@@ -566,6 +568,7 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
||||
}
|
||||
|
||||
var localCalendars = await _gmailChangeProcessor.GetAccountCalendarsAsync(Account.Id).ConfigureAwait(false);
|
||||
var remotePrimaryCalendarId = GetPrimaryCalendarId(calendarListResponse.Items);
|
||||
|
||||
List<AccountCalendar> insertedCalendars = new();
|
||||
List<AccountCalendar> updatedCalendars = new();
|
||||
@@ -596,14 +599,21 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
||||
{
|
||||
// Insert new calendar.
|
||||
var localCalendar = calendar.AsCalendar(Account.Id);
|
||||
localCalendar.IsPrimary = string.Equals(localCalendar.RemoteCalendarId, remotePrimaryCalendarId, StringComparison.OrdinalIgnoreCase);
|
||||
insertedCalendars.Add(localCalendar);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update existing calendar. Right now we only update the name.
|
||||
if (ShouldUpdateCalendar(calendar, existingLocalCalendar))
|
||||
if (ShouldUpdateCalendar(calendar, existingLocalCalendar, remotePrimaryCalendarId))
|
||||
{
|
||||
existingLocalCalendar.Name = calendar.Summary;
|
||||
existingLocalCalendar.TimeZone = calendar.TimeZone;
|
||||
if (!string.IsNullOrEmpty(calendar.BackgroundColor))
|
||||
existingLocalCalendar.BackgroundColorHex = calendar.BackgroundColor;
|
||||
if (!string.IsNullOrEmpty(calendar.ForegroundColor))
|
||||
existingLocalCalendar.TextColorHex = calendar.ForegroundColor;
|
||||
existingLocalCalendar.IsPrimary = string.Equals(existingLocalCalendar.RemoteCalendarId, remotePrimaryCalendarId, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
updatedCalendars.Add(existingLocalCalendar);
|
||||
}
|
||||
@@ -770,14 +780,41 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldUpdateCalendar(CalendarListEntry calendarListEntry, AccountCalendar accountCalendar)
|
||||
private bool ShouldUpdateCalendar(CalendarListEntry calendarListEntry, AccountCalendar accountCalendar, string remotePrimaryCalendarId)
|
||||
{
|
||||
// TODO: Only calendar name is updated for now. We can add more checks here.
|
||||
|
||||
var remoteCalendarName = calendarListEntry.Summary;
|
||||
var localCalendarName = accountCalendar.Name;
|
||||
var remoteTimeZone = calendarListEntry.TimeZone;
|
||||
var remoteBackgroundColor = string.IsNullOrEmpty(calendarListEntry.BackgroundColor) ? accountCalendar.BackgroundColorHex : calendarListEntry.BackgroundColor;
|
||||
var remoteTextColor = string.IsNullOrEmpty(calendarListEntry.ForegroundColor) ? accountCalendar.TextColorHex : calendarListEntry.ForegroundColor;
|
||||
var remoteIsPrimary = string.Equals(calendarListEntry.Id, remotePrimaryCalendarId, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return !localCalendarName.Equals(remoteCalendarName, StringComparison.OrdinalIgnoreCase);
|
||||
bool isNameChanged = !string.Equals(accountCalendar.Name, remoteCalendarName, StringComparison.OrdinalIgnoreCase);
|
||||
bool isTimeZoneChanged = !string.Equals(accountCalendar.TimeZone, remoteTimeZone, StringComparison.OrdinalIgnoreCase);
|
||||
bool isBackgroundColorChanged = !string.Equals(accountCalendar.BackgroundColorHex, remoteBackgroundColor, StringComparison.OrdinalIgnoreCase);
|
||||
bool isTextColorChanged = !string.Equals(accountCalendar.TextColorHex, remoteTextColor, StringComparison.OrdinalIgnoreCase);
|
||||
bool isPrimaryChanged = accountCalendar.IsPrimary != remoteIsPrimary;
|
||||
|
||||
return isNameChanged || isTimeZoneChanged || isBackgroundColorChanged || isTextColorChanged || isPrimaryChanged;
|
||||
}
|
||||
|
||||
private string GetPrimaryCalendarId(IList<CalendarListEntry> remoteCalendars)
|
||||
{
|
||||
if (remoteCalendars == null || remoteCalendars.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
var explicitPrimary = remoteCalendars.FirstOrDefault(c => c.Primary.GetValueOrDefault());
|
||||
if (explicitPrimary != null)
|
||||
return explicitPrimary.Id;
|
||||
|
||||
var byPrimaryKeyword = remoteCalendars.FirstOrDefault(c => string.Equals(c.Id, "primary", StringComparison.OrdinalIgnoreCase));
|
||||
if (byPrimaryKeyword != null)
|
||||
return byPrimaryKeyword.Id;
|
||||
|
||||
var byAccountAddress = remoteCalendars.FirstOrDefault(c => string.Equals(c.Id, Account.Address, StringComparison.OrdinalIgnoreCase));
|
||||
if (byAccountAddress != null)
|
||||
return byAccountAddress.Id;
|
||||
|
||||
return remoteCalendars.First().Id;
|
||||
}
|
||||
|
||||
private bool ShouldUpdateFolder(Label remoteFolder, MailItemFolder existingLocalFolder)
|
||||
|
||||
@@ -1961,7 +1961,9 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
||||
|
||||
await SynchronizeCalendarsAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var localCalendars = await _outlookChangeProcessor.GetAccountCalendarsAsync(Account.Id).ConfigureAwait(false);
|
||||
var localCalendars = (await _outlookChangeProcessor.GetAccountCalendarsAsync(Account.Id).ConfigureAwait(false))
|
||||
.Where(c => c.IsSynchronizationEnabled)
|
||||
.ToList();
|
||||
|
||||
Microsoft.Graph.Me.Calendars.Item.CalendarView.Delta.DeltaGetResponse eventsDeltaResponse = null;
|
||||
|
||||
@@ -2078,6 +2080,7 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
||||
private async Task SynchronizeCalendarsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var calendars = await _graphClient.Me.Calendars.GetAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
var remotePrimaryCalendarId = await GetPrimaryCalendarIdAsync(calendars.Value, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var localCalendars = await _outlookChangeProcessor.GetAccountCalendarsAsync(Account.Id).ConfigureAwait(false);
|
||||
|
||||
@@ -2110,14 +2113,18 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
||||
{
|
||||
// Insert new calendar.
|
||||
var localCalendar = calendar.AsCalendar(Account);
|
||||
localCalendar.IsPrimary = string.Equals(localCalendar.RemoteCalendarId, remotePrimaryCalendarId, StringComparison.OrdinalIgnoreCase);
|
||||
insertedCalendars.Add(localCalendar);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update existing calendar. Right now we only update the name.
|
||||
if (ShouldUpdateCalendar(calendar, existingLocalCalendar))
|
||||
if (ShouldUpdateCalendar(calendar, existingLocalCalendar, remotePrimaryCalendarId))
|
||||
{
|
||||
existingLocalCalendar.Name = calendar.Name;
|
||||
existingLocalCalendar.IsPrimary = string.Equals(existingLocalCalendar.RemoteCalendarId, remotePrimaryCalendarId, StringComparison.OrdinalIgnoreCase);
|
||||
if (!string.IsNullOrEmpty(calendar.HexColor))
|
||||
existingLocalCalendar.BackgroundColorHex = calendar.HexColor;
|
||||
|
||||
updatedCalendars.Add(existingLocalCalendar);
|
||||
}
|
||||
@@ -2147,14 +2154,40 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldUpdateCalendar(Calendar calendar, AccountCalendar accountCalendar)
|
||||
private bool ShouldUpdateCalendar(Calendar calendar, AccountCalendar accountCalendar, string remotePrimaryCalendarId)
|
||||
{
|
||||
// TODO: Only calendar name is updated for now. We can add more checks here.
|
||||
|
||||
var remoteCalendarName = calendar.Name;
|
||||
var localCalendarName = accountCalendar.Name;
|
||||
var remoteBackgroundColor = string.IsNullOrEmpty(calendar.HexColor) ? accountCalendar.BackgroundColorHex : calendar.HexColor;
|
||||
var remoteIsPrimary = string.Equals(calendar.Id, remotePrimaryCalendarId, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return !localCalendarName.Equals(remoteCalendarName, StringComparison.OrdinalIgnoreCase);
|
||||
bool isNameChanged = !string.Equals(accountCalendar.Name, remoteCalendarName, StringComparison.OrdinalIgnoreCase);
|
||||
bool isBackgroundColorChanged = !string.Equals(accountCalendar.BackgroundColorHex, remoteBackgroundColor, StringComparison.OrdinalIgnoreCase);
|
||||
bool isPrimaryChanged = accountCalendar.IsPrimary != remoteIsPrimary;
|
||||
|
||||
return isNameChanged || isBackgroundColorChanged || isPrimaryChanged;
|
||||
}
|
||||
|
||||
private async Task<string> GetPrimaryCalendarIdAsync(IList<Calendar> remoteCalendars, CancellationToken cancellationToken)
|
||||
{
|
||||
if (remoteCalendars == null || remoteCalendars.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
var explicitPrimary = remoteCalendars.FirstOrDefault(c => c.IsDefaultCalendar.GetValueOrDefault());
|
||||
if (explicitPrimary != null)
|
||||
return explicitPrimary.Id;
|
||||
|
||||
try
|
||||
{
|
||||
var meCalendar = await _graphClient.Me.Calendar.GetAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
if (!string.IsNullOrEmpty(meCalendar?.Id))
|
||||
return meCalendar.Id;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warning(ex, "Failed to fetch default Outlook calendar for {Name}. Falling back to first available calendar.", Account.Name);
|
||||
}
|
||||
|
||||
return remoteCalendars.First().Id;
|
||||
}
|
||||
|
||||
#region Calendar Operations
|
||||
|
||||
Reference in New Issue
Block a user