Single isntances and some updates shit.
This commit is contained in:
@@ -906,14 +906,39 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
base.OnCalendarItemUpdated(calendarItem);
|
||||
Debug.WriteLine($"Calendar item updated: {calendarItem.Id}");
|
||||
|
||||
// Updated item might've been from specific time to all-day event, or vice versa.
|
||||
// Remove the event and its occurrences from all visible date ranges first.
|
||||
// Series master events should not be visible on the UI.
|
||||
if (calendarItem.IsRecurringParent)
|
||||
{
|
||||
Debug.WriteLine($"Skipping series master event update: {calendarItem.Title}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (DayRanges.DisplayRange == null) return;
|
||||
|
||||
// Find all days that currently have this item and days that should have it after update
|
||||
var currentDaysWithItem = DayRanges
|
||||
.SelectMany(a => a.CalendarDays)
|
||||
.Where(day => day.EventsCollection.GetCalendarItem(calendarItem.Id) != null)
|
||||
.ToList();
|
||||
|
||||
var targetDaysForItem = DayRanges
|
||||
.SelectMany(a => a.CalendarDays)
|
||||
.Where(a => a.Period.OverlapsWith(calendarItem.Period))
|
||||
.ToList();
|
||||
|
||||
await ExecuteUIThread(() =>
|
||||
{
|
||||
foreach (var dayRange in DayRanges)
|
||||
// Update existing items in-place where the item should remain
|
||||
foreach (var calendarDay in currentDaysWithItem)
|
||||
{
|
||||
foreach (var calendarDay in dayRange.CalendarDays)
|
||||
if (targetDaysForItem.Contains(calendarDay))
|
||||
{
|
||||
// Item should stay in this day - update in-place
|
||||
calendarDay.EventsCollection.UpdateCalendarItem(calendarItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Item should no longer be in this day (time changed) - remove it
|
||||
var existingItem = calendarDay.EventsCollection.GetCalendarItem(calendarItem.Id);
|
||||
if (existingItem != null)
|
||||
{
|
||||
@@ -921,36 +946,17 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Re-add to corresponding day ranges to render properly.
|
||||
// Check if event falls into the current date range.
|
||||
if (DayRanges.DisplayRange == null) return;
|
||||
|
||||
// Get all periods from the visible day ranges
|
||||
var visiblePeriods = DayRanges.Select(dr => dr.Period).ToList();
|
||||
|
||||
// For recurring events, expand them to check if any occurrences fall within visible periods
|
||||
// For regular events, just check if they overlap with any period
|
||||
var matchingItems = await _calendarService.GetExpandedRecurringEventsForPeriodsAsync(calendarItem, visiblePeriods);
|
||||
|
||||
foreach (var item in matchingItems)
|
||||
{
|
||||
// Find the days that the event falls into
|
||||
var allDaysForEvent = DayRanges
|
||||
.SelectMany(a => a.CalendarDays)
|
||||
.Where(a => a.Period.OverlapsWith(item.Period));
|
||||
|
||||
foreach (var calendarDay in allDaysForEvent)
|
||||
// Add to new days where the item wasn't present before
|
||||
foreach (var calendarDay in targetDaysForItem)
|
||||
{
|
||||
var calendarItemViewModel = new CalendarItemViewModel(item);
|
||||
|
||||
await ExecuteUIThread(() =>
|
||||
if (!currentDaysWithItem.Contains(calendarDay))
|
||||
{
|
||||
var calendarItemViewModel = new CalendarItemViewModel(calendarItem);
|
||||
calendarDay.EventsCollection.AddCalendarItem(calendarItemViewModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
FilterActiveCalendars(DayRanges);
|
||||
}
|
||||
@@ -960,6 +966,14 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
base.OnCalendarItemAdded(calendarItem);
|
||||
Debug.WriteLine($"Calendar item added: {calendarItem.Id}");
|
||||
|
||||
// Series master events should not be visible on the UI.
|
||||
// Their instances are already expanded and synced individually.
|
||||
if (calendarItem.IsRecurringParent)
|
||||
{
|
||||
Debug.WriteLine($"Skipping series master event: {calendarItem.Title}");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if event falls into the current date range.
|
||||
if (DayRanges.DisplayRange == null) return;
|
||||
|
||||
@@ -1005,28 +1019,20 @@ public partial class CalendarPageViewModel : CalendarBaseViewModel,
|
||||
}
|
||||
|
||||
// Get all periods from the visible day ranges
|
||||
var visiblePeriods = DayRanges.Select(dr => dr.Period).ToList();
|
||||
// Note: Recurring event occurrences are now synced from server as individual instances
|
||||
// No local expansion needed - just check if this item overlaps with visible periods
|
||||
var allDaysForEvent = DayRanges
|
||||
.SelectMany(a => a.CalendarDays)
|
||||
.Where(a => a.Period.OverlapsWith(calendarItem.Period));
|
||||
|
||||
// For recurring events, expand them to check if any occurrences fall within visible periods
|
||||
// For regular events, just check if they overlap with any period
|
||||
var matchingItems = await _calendarService.GetExpandedRecurringEventsForPeriodsAsync(calendarItem, visiblePeriods);
|
||||
|
||||
foreach (var item in matchingItems)
|
||||
foreach (var calendarDay in allDaysForEvent)
|
||||
{
|
||||
// Find the days that the event falls into
|
||||
var allDaysForEvent = DayRanges
|
||||
.SelectMany(a => a.CalendarDays)
|
||||
.Where(a => a.Period.OverlapsWith(item.Period));
|
||||
var calendarItemViewModel = new CalendarItemViewModel(calendarItem);
|
||||
|
||||
foreach (var calendarDay in allDaysForEvent)
|
||||
await ExecuteUIThread(() =>
|
||||
{
|
||||
var calendarItemViewModel = new CalendarItemViewModel(item);
|
||||
|
||||
await ExecuteUIThread(() =>
|
||||
{
|
||||
calendarDay.EventsCollection.AddCalendarItem(calendarItemViewModel);
|
||||
});
|
||||
}
|
||||
calendarDay.EventsCollection.AddCalendarItem(calendarItemViewModel);
|
||||
});
|
||||
}
|
||||
|
||||
FilterActiveCalendars(DayRanges);
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Itenso.TimePeriod;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Calendar;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Calendar;
|
||||
|
||||
namespace Wino.Calendar.ViewModels.Data;
|
||||
|
||||
@@ -89,6 +91,35 @@ public partial class CalendarItemViewModel : ObservableObject, ICalendarItem, IC
|
||||
[ObservableProperty]
|
||||
public partial bool IsSelected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The period of the day where this item is currently being displayed.
|
||||
/// Used for multi-day event title formatting.
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(DisplayTitle))]
|
||||
public partial ITimePeriod DisplayingPeriod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Calendar settings for time formatting.
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(DisplayTitle))]
|
||||
public partial CalendarSettings CalendarSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display title based on the current displaying period.
|
||||
/// </summary>
|
||||
public string DisplayTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DisplayingPeriod == null || CalendarSettings == null)
|
||||
return Title;
|
||||
|
||||
return GetDisplayTitle(DisplayingPeriod, CalendarSettings);
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<CalendarEventAttendee> Attendees { get; } = new ObservableCollection<CalendarEventAttendee>();
|
||||
|
||||
public CalendarItemViewModel(CalendarItem calendarItem)
|
||||
@@ -96,5 +127,82 @@ public partial class CalendarItemViewModel : ObservableObject, ICalendarItem, IC
|
||||
CalendarItem = calendarItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the underlying CalendarItem with new data and raises property change notifications.
|
||||
/// </summary>
|
||||
/// <param name="calendarItem">The updated calendar item data.</param>
|
||||
public void UpdateFrom(CalendarItem calendarItem)
|
||||
{
|
||||
if (calendarItem == null || calendarItem.Id != CalendarItem.Id)
|
||||
return;
|
||||
|
||||
// Update all mutable properties
|
||||
CalendarItem.Title = calendarItem.Title;
|
||||
CalendarItem.Description = calendarItem.Description;
|
||||
CalendarItem.Location = calendarItem.Location;
|
||||
CalendarItem.StartDate = calendarItem.StartDate;
|
||||
CalendarItem.StartTimeZone = calendarItem.StartTimeZone;
|
||||
CalendarItem.EndTimeZone = calendarItem.EndTimeZone;
|
||||
CalendarItem.DurationInSeconds = calendarItem.DurationInSeconds;
|
||||
CalendarItem.Recurrence = calendarItem.Recurrence;
|
||||
CalendarItem.RecurringCalendarItemId = calendarItem.RecurringCalendarItemId;
|
||||
CalendarItem.OrganizerDisplayName = calendarItem.OrganizerDisplayName;
|
||||
CalendarItem.OrganizerEmail = calendarItem.OrganizerEmail;
|
||||
CalendarItem.IsLocked = calendarItem.IsLocked;
|
||||
CalendarItem.IsHidden = calendarItem.IsHidden;
|
||||
CalendarItem.CustomEventColorHex = calendarItem.CustomEventColorHex;
|
||||
CalendarItem.HtmlLink = calendarItem.HtmlLink;
|
||||
CalendarItem.Status = calendarItem.Status;
|
||||
CalendarItem.Visibility = calendarItem.Visibility;
|
||||
CalendarItem.ShowAs = calendarItem.ShowAs;
|
||||
CalendarItem.UpdatedAt = calendarItem.UpdatedAt;
|
||||
CalendarItem.AssignedCalendar = calendarItem.AssignedCalendar;
|
||||
|
||||
// Raise property changed for all bindable properties
|
||||
OnPropertyChanged(nameof(Title));
|
||||
OnPropertyChanged(nameof(StartDate));
|
||||
OnPropertyChanged(nameof(EndDate));
|
||||
OnPropertyChanged(nameof(DurationInSeconds));
|
||||
OnPropertyChanged(nameof(Period));
|
||||
OnPropertyChanged(nameof(IsAllDayEvent));
|
||||
OnPropertyChanged(nameof(IsMultiDayEvent));
|
||||
OnPropertyChanged(nameof(IsRecurringEvent));
|
||||
OnPropertyChanged(nameof(IsRecurringChild));
|
||||
OnPropertyChanged(nameof(IsRecurringParent));
|
||||
OnPropertyChanged(nameof(AssignedCalendar));
|
||||
OnPropertyChanged(nameof(DisplayTitle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display title for this calendar item when rendered in a specific day.
|
||||
/// </summary>
|
||||
public string GetDisplayTitle(ITimePeriod displayingPeriod, CalendarSettings calendarSettings)
|
||||
{
|
||||
if (!IsMultiDayEvent)
|
||||
return Title;
|
||||
|
||||
var periodRelation = Period.GetRelation(displayingPeriod);
|
||||
|
||||
if (periodRelation == PeriodRelation.StartInside || periodRelation == PeriodRelation.EnclosingStartTouching)
|
||||
{
|
||||
// Event starts within this day: "HH:mm -> Title"
|
||||
return $"{calendarSettings.GetTimeString(StartDate.TimeOfDay)} -> {Title}";
|
||||
}
|
||||
else if (periodRelation == PeriodRelation.EndInside || periodRelation == PeriodRelation.EnclosingEndTouching)
|
||||
{
|
||||
// Event ends within this day: "Title <- HH:mm"
|
||||
return $"{Title} <- {calendarSettings.GetTimeString(EndDate.TimeOfDay)}";
|
||||
}
|
||||
else if (periodRelation == PeriodRelation.Enclosing)
|
||||
{
|
||||
// Event spans the entire day
|
||||
return $"{Translator.CalendarItemAllDay} {Title}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Title;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => CalendarItem.Title;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user