Event details page improvements, calendar item update source.
This commit is contained in:
@@ -60,29 +60,30 @@ public partial class CalendarAccountSettingsPageViewModel : CalendarBaseViewMode
|
||||
{
|
||||
base.OnNavigatedTo(mode, parameters);
|
||||
|
||||
if (parameters is not Guid accountId)
|
||||
if (parameters is AccountCalendar selectedCalendar)
|
||||
{
|
||||
Account = await _accountService.GetAccountAsync(selectedCalendar.AccountId);
|
||||
AccountCalendar = await _calendarService.GetAccountCalendarAsync(selectedCalendar.Id) ?? selectedCalendar;
|
||||
}
|
||||
else if (parameters is Guid accountId)
|
||||
{
|
||||
Account = await _accountService.GetAccountAsync(accountId);
|
||||
var calendars = await _calendarService.GetAccountCalendarsAsync(accountId);
|
||||
AccountCalendar = calendars.FirstOrDefault(c => c.IsPrimary) ?? calendars.FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Load account
|
||||
Account = await _accountService.GetAccountAsync(accountId);
|
||||
|
||||
if (Account == null)
|
||||
return;
|
||||
|
||||
// Load first primary calendar for this account
|
||||
var calendars = await _calendarService.GetAccountCalendarsAsync(accountId);
|
||||
AccountCalendar = calendars.FirstOrDefault(c => c.IsPrimary) ?? calendars.FirstOrDefault();
|
||||
|
||||
if (AccountCalendar == null)
|
||||
if (Account == null || AccountCalendar == null)
|
||||
return;
|
||||
|
||||
// Initialize properties from AccountCalendar
|
||||
AccountColorHex = AccountCalendar.BackgroundColorHex ?? "#0078D4";
|
||||
IsSyncEnabled = AccountCalendar.IsExtended;
|
||||
IsSyncEnabled = AccountCalendar.IsSynchronizationEnabled;
|
||||
IsPrimaryCalendar = AccountCalendar.IsPrimary;
|
||||
|
||||
// TODO: Default ShowAs is not stored in AccountCalendar yet, defaulting to Busy
|
||||
SelectedDefaultShowAsOption = ShowAsOptions[2]; // Busy
|
||||
SelectedDefaultShowAsOption = ShowAsOptions.FirstOrDefault(o => o.ShowAs == AccountCalendar.DefaultShowAs) ?? ShowAsOptions[2];
|
||||
}
|
||||
|
||||
partial void OnAccountColorHexChanged(string value)
|
||||
@@ -98,7 +99,7 @@ public partial class CalendarAccountSettingsPageViewModel : CalendarBaseViewMode
|
||||
{
|
||||
if (AccountCalendar != null)
|
||||
{
|
||||
AccountCalendar.IsExtended = value;
|
||||
AccountCalendar.IsSynchronizationEnabled = value;
|
||||
SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
@@ -114,11 +115,10 @@ public partial class CalendarAccountSettingsPageViewModel : CalendarBaseViewMode
|
||||
|
||||
partial void OnSelectedDefaultShowAsOptionChanged(ShowAsOption value)
|
||||
{
|
||||
// TODO: Default ShowAs should be stored in AccountCalendar or account preferences
|
||||
// For now, this is just a placeholder as the property doesn't exist yet
|
||||
if (value != null)
|
||||
if (AccountCalendar != null && value != null)
|
||||
{
|
||||
// Future: Store value.ShowAs somewhere
|
||||
AccountCalendar.DefaultShowAs = value.ShowAs;
|
||||
SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -286,6 +286,7 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
Description = string.Empty,
|
||||
Location = Location ?? string.Empty,
|
||||
Title = EventName,
|
||||
ShowAs = SelectedQuickEventAccountCalendar.DefaultShowAs,
|
||||
IsHidden = false,
|
||||
AssignedCalendar = SelectedQuickEventAccountCalendar
|
||||
};
|
||||
@@ -907,9 +908,9 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
});
|
||||
}
|
||||
|
||||
protected override async void OnCalendarItemUpdated(CalendarItem calendarItem)
|
||||
protected override async void OnCalendarItemUpdated(CalendarItem calendarItem, CalendarItemUpdateSource source)
|
||||
{
|
||||
base.OnCalendarItemUpdated(calendarItem);
|
||||
base.OnCalendarItemUpdated(calendarItem, source);
|
||||
Debug.WriteLine($"Calendar item updated: {calendarItem.Id}");
|
||||
|
||||
// Series master events should not be visible on the UI.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Wino.Core.Domain.Entities.Calendar;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
|
||||
namespace Wino.Calendar.ViewModels.Data;
|
||||
@@ -54,6 +55,12 @@ public partial class AccountCalendarViewModel : ObservableObject, IAccountCalend
|
||||
set => SetProperty(AccountCalendar.IsPrimary, value, AccountCalendar, (u, i) => u.IsPrimary = i);
|
||||
}
|
||||
|
||||
public bool IsSynchronizationEnabled
|
||||
{
|
||||
get => AccountCalendar.IsSynchronizationEnabled;
|
||||
set => SetProperty(AccountCalendar.IsSynchronizationEnabled, value, AccountCalendar, (u, i) => u.IsSynchronizationEnabled = i);
|
||||
}
|
||||
|
||||
public Guid AccountId
|
||||
{
|
||||
get => AccountCalendar.AccountId;
|
||||
@@ -65,6 +72,12 @@ public partial class AccountCalendarViewModel : ObservableObject, IAccountCalend
|
||||
get => AccountCalendar.RemoteCalendarId;
|
||||
set => SetProperty(AccountCalendar.RemoteCalendarId, value, AccountCalendar, (u, r) => u.RemoteCalendarId = r);
|
||||
}
|
||||
|
||||
public CalendarItemShowAs DefaultShowAs
|
||||
{
|
||||
get => AccountCalendar.DefaultShowAs;
|
||||
set => SetProperty(AccountCalendar.DefaultShowAs, value, AccountCalendar, (u, s) => u.DefaultShowAs = s);
|
||||
}
|
||||
public Guid Id { get => ((IAccountCalendar)AccountCalendar).Id; set => ((IAccountCalendar)AccountCalendar).Id = value; }
|
||||
public MailAccount MailAccount { get => MailAccount; set => MailAccount = value; }
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
||||
public bool IncludeRsvpMessage => !string.IsNullOrEmpty(RsvpMessage);
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(IncludeRsvpMessage))]
|
||||
public partial string RsvpMessage { get; set; } = string.Empty;
|
||||
|
||||
public ObservableCollection<RsvpStatusOption> RsvpStatusOptions { get; } = new ObservableCollection<RsvpStatusOption>();
|
||||
@@ -129,7 +130,7 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
||||
CalendarItemStatus.Tentative => Translator.CalendarEventResponse_TentativeResponse,
|
||||
CalendarItemStatus.Cancelled => Translator.CalendarEventResponse_DeclinedResponse,
|
||||
CalendarItemStatus.NotResponded => Translator.CalendarEventResponse_NotResponded,
|
||||
_ => throw new NotImplementedException()
|
||||
_ => Translator.CalendarEventResponse_NotResponded
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -179,19 +180,33 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
||||
await LoadCalendarItemTargetAsync(args);
|
||||
}
|
||||
|
||||
protected override async void OnCalendarItemUpdated(CalendarItem calendarItem)
|
||||
protected override async void OnCalendarItemUpdated(CalendarItem calendarItem, CalendarItemUpdateSource source)
|
||||
{
|
||||
base.OnCalendarItemUpdated(calendarItem);
|
||||
base.OnCalendarItemUpdated(calendarItem, source);
|
||||
|
||||
// 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
|
||||
// Reflect client-side optimistic changes immediately; fallback to DB for server updates.
|
||||
if (source == CalendarItemUpdateSource.ClientUpdated || source == CalendarItemUpdateSource.ClientReverted)
|
||||
{
|
||||
var previousAttendees = CurrentEvent?.Attendees?.ToList() ?? [];
|
||||
CurrentEvent = new CalendarItemViewModel(calendarItem);
|
||||
|
||||
foreach (var attendee in previousAttendees)
|
||||
{
|
||||
CurrentEvent.Attendees.Add(attendee);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Refresh from DB when update comes from server sync.
|
||||
var refreshedEvent = await _calendarService.GetCalendarItemAsync(calendarItem.Id);
|
||||
if (refreshedEvent != null)
|
||||
{
|
||||
CurrentEvent = new CalendarItemViewModel(refreshedEvent);
|
||||
await LoadAttendeesAsync(refreshedEvent.EventTrackingId, refreshedEvent);
|
||||
await LoadAttendeesAsync(refreshedEvent.Id, refreshedEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,17 +233,17 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
||||
|
||||
CurrentEvent = new CalendarItemViewModel(currentEventItem);
|
||||
|
||||
await LoadAttendeesAsync(currentEventItem.EventTrackingId, currentEventItem);
|
||||
await LoadAttendeesAsync(currentEventItem.Id, 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);
|
||||
Reminders = await _calendarService.GetRemindersAsync(currentEventItem.Id);
|
||||
InitializeReminderOptions();
|
||||
|
||||
// Load attachments
|
||||
await LoadAttachmentsAsync(currentEventItem.EventTrackingId);
|
||||
await LoadAttachmentsAsync(currentEventItem.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -236,11 +251,11 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadAttendeesAsync(Guid eventTrackingId, CalendarItem calendarItem)
|
||||
private async Task LoadAttendeesAsync(Guid calendarItemId, CalendarItem calendarItem)
|
||||
{
|
||||
CurrentEvent.Attendees.Clear();
|
||||
|
||||
var attendees = await _calendarService.GetAttendeesAsync(eventTrackingId);
|
||||
var attendees = await _calendarService.GetAttendeesAsync(calendarItemId);
|
||||
|
||||
// Separate organizer from other attendees to ensure organizer is always first
|
||||
var organizer = attendees.FirstOrDefault(a => a.IsOrganizer);
|
||||
@@ -348,7 +363,7 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
||||
{
|
||||
// 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);
|
||||
var originalAttendees = await _calendarService.GetAttendeesAsync(CurrentEvent.CalendarItem.Id);
|
||||
|
||||
// Get selected reminder options
|
||||
var selectedOptions = ReminderOptions.Where(o => o.IsSelected).ToList();
|
||||
@@ -370,7 +385,7 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
||||
}
|
||||
|
||||
// Save reminders to database
|
||||
await _calendarService.SaveRemindersAsync(CurrentEvent.CalendarItem.EventTrackingId, newReminders);
|
||||
await _calendarService.SaveRemindersAsync(CurrentEvent.CalendarItem.Id, newReminders);
|
||||
Reminders = newReminders;
|
||||
|
||||
// Update ShowAs if changed
|
||||
@@ -499,7 +514,7 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
|
||||
await _winoRequestDelegator.ExecuteAsync(preparationRequest);
|
||||
|
||||
// Reload attendees to get the updated status from the server
|
||||
await LoadAttendeesAsync(CurrentEvent.CalendarItem.EventTrackingId, CurrentEvent.CalendarItem);
|
||||
await LoadAttendeesAsync(CurrentEvent.CalendarItem.Id, CurrentEvent.CalendarItem);
|
||||
|
||||
OnPropertyChanged(nameof(CurrentRsvpText));
|
||||
OnPropertyChanged(nameof(CurrentRsvpStatus));
|
||||
|
||||
Reference in New Issue
Block a user