RSVP options.

This commit is contained in:
Burak Kaan Köse
2026-01-03 19:33:36 +01:00
parent a64627e7d6
commit 9877656eea
28 changed files with 968 additions and 115 deletions
@@ -66,4 +66,5 @@ public partial class AccountCalendarViewModel : ObservableObject, IAccountCalend
set => SetProperty(AccountCalendar.RemoteCalendarId, value, AccountCalendar, (u, r) => u.RemoteCalendarId = r);
}
public Guid Id { get => ((IAccountCalendar)AccountCalendar).Id; set => ((IAccountCalendar)AccountCalendar).Id = value; }
public MailAccount MailAccount { get => MailAccount; set => MailAccount = value; }
}
@@ -36,7 +36,10 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
[NotifyPropertyChangedFor(nameof(CanViewSeries))]
[NotifyPropertyChangedFor(nameof(CanEditSeries))]
[NotifyPropertyChangedFor(nameof(IsCurrentUserOrganizer))]
[NotifyPropertyChangedFor(nameof(CurrentRsvpText))]
[NotifyPropertyChangedFor(nameof(CurrentRsvpStatus))]
public partial CalendarItemViewModel CurrentEvent { get; set; }
[ObservableProperty]
public partial CalendarItemViewModel SeriesParent { get; set; }
[ObservableProperty]
@@ -80,6 +83,45 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
#endregion
#region RSVP Panel
[ObservableProperty]
public partial bool IsRsvpPanelVisible { get; set; }
public bool IncludeRsvpMessage => !string.IsNullOrEmpty(RsvpMessage);
[ObservableProperty]
public partial string RsvpMessage { get; set; } = string.Empty;
public ObservableCollection<RsvpStatusOption> RsvpStatusOptions { get; } = new ObservableCollection<RsvpStatusOption>();
public CalendarItemStatus CurrentRsvpStatus
{
get
{
return CurrentEvent?.CalendarItem?.Status ?? CalendarItemStatus.NotResponded;
}
}
public string CurrentRsvpText
{
get
{
if (CurrentEvent?.CalendarItem == null) return Translator.CalendarEventResponse_Accept;
return CurrentEvent.CalendarItem.Status switch
{
CalendarItemStatus.Accepted => Translator.CalendarEventResponse_AcceptedResponse,
CalendarItemStatus.Tentative => Translator.CalendarEventResponse_TentativeResponse,
CalendarItemStatus.Cancelled => Translator.CalendarEventResponse_DeclinedResponse,
CalendarItemStatus.NotResponded => Translator.CalendarEventResponse_NotResponded,
_ => throw new NotImplementedException()
};
}
}
#endregion
public EventDetailsPageViewModel(ICalendarService calendarService,
INativeAppService nativeAppService,
IPreferencesService preferencesService,
@@ -95,6 +137,11 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
_navigationService = navigationService;
CurrentSettings = _preferencesService.GetCurrentCalendarSettings();
// Initialize RSVP status options
RsvpStatusOptions.Add(new RsvpStatusOption(CalendarItemStatus.Accepted));
RsvpStatusOptions.Add(new RsvpStatusOption(CalendarItemStatus.Tentative));
RsvpStatusOptions.Add(new RsvpStatusOption(CalendarItemStatus.Cancelled));
}
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
@@ -109,6 +156,17 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
await LoadCalendarItemTargetAsync(args);
}
protected override void OnCalendarItemDeleted(CalendarItem calendarItem)
{
base.OnCalendarItemDeleted(calendarItem);
// If the current event was deleted, navigate back
if (CurrentEvent?.CalendarItem?.Id == calendarItem.Id || CurrentEvent?.CalendarItem.RecurringCalendarItemId == calendarItem.Id)
{
_navigationService.GoBack();
}
}
private async Task LoadCalendarItemTargetAsync(CalendarItemTarget target)
{
try
@@ -265,11 +323,68 @@ public partial class EventDetailsPageViewModel : CalendarBaseViewModel
}
[RelayCommand]
private async Task RespondAsync(CalendarItemStatus status)
private void ToggleRsvpPanel()
{
IsRsvpPanelVisible = !IsRsvpPanelVisible;
if (IsRsvpPanelVisible && CurrentEvent?.CalendarItem != null)
{
// Initialize selection based on current status
foreach (var item in RsvpStatusOptions)
{
item.IsSelected = CurrentEvent?.CalendarItem?.Status == item.Status;
}
}
}
[RelayCommand]
private void CloseRsvpPanel()
{
IsRsvpPanelVisible = false;
RsvpMessage = string.Empty;
}
[RelayCommand]
private async Task SendRsvpResponse(AttendeeStatus status)
{
if (CurrentEvent == null) return;
// TODO: Implement response
try
{
// Get the optional response message if user wants to include it
var responseMessage = IncludeRsvpMessage ? RsvpMessage : null;
// Map status to operation
CalendarSynchronizerOperation operation = status switch
{
AttendeeStatus.Accepted => CalendarSynchronizerOperation.AcceptEvent,
AttendeeStatus.Tentative => CalendarSynchronizerOperation.TentativeEvent,
AttendeeStatus.Declined => CalendarSynchronizerOperation.DeclineEvent,
_ => throw new InvalidOperationException($"Invalid RSVP status: {status}")
};
// Create preparation request with the optional message
var preparationRequest = new CalendarOperationPreparationRequest(
operation,
CurrentEvent.CalendarItem,
null,
responseMessage);
await _winoRequestDelegator.ExecuteAsync(preparationRequest);
OnPropertyChanged(nameof(CurrentRsvpText));
OnPropertyChanged(nameof(CurrentRsvpStatus));
CloseRsvpPanel();
}
catch (Exception ex)
{
Debug.WriteLine($"Error sending RSVP response: {ex.Message}");
_dialogService.InfoBarMessage(
Translator.Info_AttachmentSaveFailedTitle,
ex.Message,
InfoBarMessageType.Error);
}
}
[RelayCommand]
@@ -323,3 +438,30 @@ public partial class ReminderOption : ObservableObject
IsCustom = isCustom;
}
}
public partial class RsvpStatusOption : ObservableObject
{
public CalendarItemStatus Status { get; }
public string StatusText
{
get
{
return Status switch
{
CalendarItemStatus.Accepted => Translator.CalendarEventResponse_Accept,
CalendarItemStatus.Tentative => Translator.CalendarEventResponse_Tentative,
CalendarItemStatus.Cancelled => Translator.CalendarEventResponse_Decline,
_ => Translator.CalendarEventResponse_Accept
};
}
}
[ObservableProperty]
public partial bool IsSelected { get; set; }
public RsvpStatusOption(CalendarItemStatus status)
{
Status = status;
}
}