Calendar invitations for Mail part of the app.

This commit is contained in:
Burak Kaan Köse
2026-01-05 00:21:07 +01:00
parent 0b0f6b8d8e
commit 3d07328f47
24 changed files with 679 additions and 66 deletions
@@ -27,17 +27,13 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
IRecipient<VisibleDateRangeChangedMessage>,
IRecipient<CalendarEnableStatusChangedMessage>,
IRecipient<NavigateManageAccountsRequested>,
IRecipient<CalendarDisplayTypeChangedMessage>,
IRecipient<DetailsPageStateChangedMessage>
IRecipient<CalendarDisplayTypeChangedMessage>
{
public IPreferencesService PreferencesService { get; }
public IStatePersistanceService StatePersistenceService { get; }
public IAccountCalendarStateService AccountCalendarStateService { get; }
public INavigationService NavigationService { get; }
[ObservableProperty]
private bool _isEventDetailsPageActive;
[ObservableProperty]
private int _selectedMenuItemIndex = -1;
@@ -303,7 +299,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
Messenger.Register<CalendarEnableStatusChangedMessage>(this);
Messenger.Register<NavigateManageAccountsRequested>(this);
Messenger.Register<CalendarDisplayTypeChangedMessage>(this);
Messenger.Register<DetailsPageStateChangedMessage>(this);
}
protected override void UnregisterRecipients()
@@ -314,7 +309,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
Messenger.Unregister<CalendarEnableStatusChangedMessage>(this);
Messenger.Unregister<NavigateManageAccountsRequested>(this);
Messenger.Unregister<CalendarDisplayTypeChangedMessage>(this);
Messenger.Unregister<DetailsPageStateChangedMessage>(this);
}
public void Receive(VisibleDateRangeChangedMessage message) => HighlightedDateRange = message.DateRange;
@@ -369,16 +363,4 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItemIndex = 1;
public void Receive(CalendarDisplayTypeChangedMessage message) => OnPropertyChanged(nameof(IsVerticalCalendar));
public async void Receive(DetailsPageStateChangedMessage message)
{
await ExecuteUIThread(() =>
{
IsEventDetailsPageActive = message.IsActivated;
// TODO: This is for Wino Mail. Generalize this later on.
StatePersistenceService.IsReaderNarrowed = message.IsActivated;
StatePersistenceService.IsReadingMail = message.IsActivated;
});
}
}
@@ -173,14 +173,29 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
{
base.OnNavigatedTo(mode, parameters);
Messenger.Send(new DetailsPageStateChangedMessage(true));
if (parameters == null || parameters is not CalendarItemTarget args)
return;
await LoadCalendarItemTargetAsync(args);
}
protected override async void OnCalendarItemUpdated(CalendarItem calendarItem)
{
base.OnCalendarItemUpdated(calendarItem);
// If the current event was updated, reload it
if (CurrentEvent?.CalendarItem?.Id == calendarItem.Id || CurrentEvent?.CalendarItem.RecurringCalendarItemId == calendarItem.Id)
{
// Refresh the current event data by reloading from service
var refreshedEvent = await _calendarService.GetCalendarItemAsync(calendarItem.Id);
if (refreshedEvent != null)
{
CurrentEvent = new CalendarItemViewModel(refreshedEvent);
await LoadAttendeesAsync(refreshedEvent.EventTrackingId, refreshedEvent);
}
}
}
protected override void OnCalendarItemDeleted(CalendarItem calendarItem)
{
base.OnCalendarItemDeleted(calendarItem);
@@ -205,6 +220,9 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
await LoadAttendeesAsync(currentEventItem.EventTrackingId, currentEventItem);
// Initialize SelectedShowAsOption based on current event's ShowAs
SelectedShowAsOption = ShowAsOptions.FirstOrDefault(o => o.ShowAs == currentEventItem.ShowAs) ?? ShowAsOptions[2];
// Load reminders for this calendar item
Reminders = await _calendarService.GetRemindersAsync(currentEventItem.EventTrackingId);
InitializeReminderOptions();
@@ -221,15 +239,21 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
private async Task LoadAttendeesAsync(Guid eventTrackingId, CalendarItem calendarItem)
{
CurrentEvent.Attendees.Clear();
var attendees = await _calendarService.GetAttendeesAsync(eventTrackingId);
// Check if organizer is in the attendees list
var hasOrganizerInList = attendees.Any(a => a.IsOrganizer);
// Separate organizer from other attendees to ensure organizer is always first
var organizer = attendees.FirstOrDefault(a => a.IsOrganizer);
var nonOrganizerAttendees = attendees.Where(a => !a.IsOrganizer).ToList();
// If the user is the organizer but not in attendees list, add them
if (!hasOrganizerInList && !string.IsNullOrEmpty(calendarItem.OrganizerEmail))
// If the organizer is in the list, add them first
if (organizer != null)
{
CurrentEvent.Attendees.Add(organizer);
}
else if (!string.IsNullOrEmpty(calendarItem.OrganizerEmail))
{
// If the organizer is not in the attendees list, create and add them first
var organizerAttendee = new CalendarEventAttendee
{
Id = Guid.NewGuid(),
@@ -242,7 +266,8 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
CurrentEvent.Attendees.Add(organizerAttendee);
}
foreach (var item in attendees)
// Add all other attendees after the organizer
foreach (var item in nonOrganizerAttendees)
{
CurrentEvent.Attendees.Add(item);
}
@@ -321,6 +346,10 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
try
{
// Capture original state BEFORE making any changes for potential revert
var originalItem = await _calendarService.GetCalendarItemAsync(CurrentEvent.CalendarItem.Id);
var originalAttendees = await _calendarService.GetAttendeesAsync(CurrentEvent.CalendarItem.EventTrackingId);
// Get selected reminder options
var selectedOptions = ReminderOptions.Where(o => o.IsSelected).ToList();
@@ -344,12 +373,35 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
await _calendarService.SaveRemindersAsync(CurrentEvent.CalendarItem.EventTrackingId, newReminders);
Reminders = newReminders;
// Update ShowAs if changed
if (SelectedShowAsOption != null)
{
CurrentEvent.CalendarItem.ShowAs = SelectedShowAsOption.ShowAs;
}
// Update the calendar item and attendees in database
await _calendarService.UpdateCalendarItemAsync(CurrentEvent.CalendarItem, CurrentEvent.Attendees.ToList());
// Queue the update request to synchronizer with original state for revert capability
var preparationRequest = new CalendarOperationPreparationRequest(
CalendarSynchronizerOperation.UpdateEvent,
CurrentEvent.CalendarItem,
CurrentEvent.Attendees.ToList(),
ResponseMessage: null,
OriginalItem: originalItem,
OriginalAttendees: originalAttendees);
await _winoRequestDelegator.ExecuteAsync(preparationRequest);
_navigationService.GoBack();
// TODO: Implement saving other event details
}
catch (Exception ex)
{
Debug.WriteLine($"Error saving event: {ex.Message}");
_dialogService.InfoBarMessage(
Translator.Info_AttachmentSaveFailedTitle,
ex.Message,
InfoBarMessageType.Error);
}
}