Files
Wino-Mail/Wino.Core.Domain/Collections/CalendarEventCollection.cs
T

220 lines
7.2 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Itenso.TimePeriod;
using Wino.Core.Domain.Entities.Calendar;
2024-12-28 23:17:16 +01:00
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Calendar;
2024-12-28 23:17:16 +01:00
2025-02-16 11:54:23 +01:00
namespace Wino.Core.Domain.Collections;
public class CalendarEventCollection
2024-12-28 23:17:16 +01:00
{
2025-02-16 11:54:23 +01:00
public event EventHandler<ICalendarItem> CalendarItemAdded;
public event EventHandler<ICalendarItem> CalendarItemRemoved;
2026-01-06 11:11:37 +01:00
public event EventHandler<ICalendarItem> CalendarItemUpdated;
2025-02-16 11:54:23 +01:00
public event EventHandler CalendarItemsCleared;
2025-02-16 11:54:23 +01:00
private ObservableRangeCollection<ICalendarItem> _internalRegularEvents = [];
private ObservableRangeCollection<ICalendarItem> _internalAllDayEvents = [];
2025-02-16 11:54:23 +01:00
public ReadOnlyObservableCollection<ICalendarItem> RegularEvents { get; }
public ReadOnlyObservableCollection<ICalendarItem> AllDayEvents { get; } // TODO: Rename this to include multi-day events.
public ITimePeriod Period { get; }
public CalendarSettings Settings { get; }
2025-02-16 11:54:23 +01:00
private readonly List<ICalendarItem> _allItems = new List<ICalendarItem>();
2025-02-16 11:54:23 +01:00
public CalendarEventCollection(ITimePeriod period, CalendarSettings settings)
{
Period = period;
Settings = settings;
2025-02-16 11:54:23 +01:00
RegularEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalRegularEvents);
AllDayEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalAllDayEvents);
}
2025-02-16 11:54:23 +01:00
public bool HasCalendarEvent(AccountCalendar accountCalendar)
=> _allItems.Any(x => x.AssignedCalendar.Id == accountCalendar.Id);
2025-02-16 11:54:23 +01:00
public ICalendarItem GetCalendarItem(Guid calendarItemId)
{
return _allItems.FirstOrDefault(x => x.Id == calendarItemId);
}
2025-02-16 11:54:23 +01:00
public void ClearSelectionStates()
{
foreach (var item in _allItems)
{
2025-02-16 11:54:23 +01:00
if (item is ICalendarItemViewModel calendarItemViewModel)
{
2025-02-16 11:54:23 +01:00
calendarItemViewModel.IsSelected = false;
}
}
2025-02-16 11:54:23 +01:00
}
2025-02-16 11:54:23 +01:00
public void FilterByCalendars(IEnumerable<Guid> visibleCalendarIds)
{
foreach (var item in _allItems)
{
2025-02-16 11:54:23 +01:00
var collections = GetProperCollectionsForCalendarItem(item);
2025-02-16 11:43:30 +01:00
2025-02-16 11:54:23 +01:00
foreach (var collection in collections)
{
if (!visibleCalendarIds.Contains(item.AssignedCalendar.Id) && collection.Contains(item))
{
RemoveCalendarItemInternal(collection, item, false);
}
else if (visibleCalendarIds.Contains(item.AssignedCalendar.Id) && !collection.Contains(item))
{
2025-02-16 11:54:23 +01:00
AddCalendarItemInternal(collection, item, false);
}
}
}
2025-02-16 11:54:23 +01:00
}
2025-02-16 11:54:23 +01:00
private IEnumerable<ObservableRangeCollection<ICalendarItem>> GetProperCollectionsForCalendarItem(ICalendarItem calendarItem)
{
// All-day events go to all days.
// Multi-day events go to both.
// Anything else goes to regular.
2025-02-16 11:43:30 +01:00
2025-02-16 11:54:23 +01:00
if (calendarItem.IsAllDayEvent)
{
return [_internalAllDayEvents];
}
2025-02-16 11:54:23 +01:00
else if (calendarItem.IsMultiDayEvent)
{
2025-02-16 11:54:23 +01:00
return [_internalRegularEvents, _internalAllDayEvents];
2025-02-16 11:43:30 +01:00
}
2025-02-16 11:54:23 +01:00
else
2025-02-16 11:35:43 +01:00
{
2025-02-16 11:54:23 +01:00
return [_internalRegularEvents];
}
}
2025-02-16 11:35:43 +01:00
2025-02-16 11:54:23 +01:00
public void AddCalendarItem(ICalendarItem calendarItem)
{
var collections = GetProperCollectionsForCalendarItem(calendarItem);
foreach (var collection in collections)
{
AddCalendarItemInternal(collection, calendarItem);
2025-02-16 11:43:30 +01:00
}
2025-02-16 11:54:23 +01:00
}
public void RemoveCalendarItem(ICalendarItem calendarItem)
{
var collections = GetProperCollectionsForCalendarItem(calendarItem);
2025-02-16 11:54:23 +01:00
foreach (var collection in collections)
2024-12-28 23:17:16 +01:00
{
2025-02-16 11:54:23 +01:00
RemoveCalendarItemInternal(collection, calendarItem);
}
}
public void RemoveCalendarItems(Func<ICalendarItem, bool> predicate)
{
if (predicate == null) return;
var itemsToRemove = _allItems.Where(predicate).ToList();
foreach (var item in itemsToRemove)
{
RemoveCalendarItem(item);
}
}
2025-02-16 11:54:23 +01:00
private void AddCalendarItemInternal(ObservableRangeCollection<ICalendarItem> collection, ICalendarItem calendarItem, bool create = true)
{
2026-01-06 11:11:37 +01:00
if (calendarItem is not ICalendarItemViewModel viewModel)
2025-02-16 11:54:23 +01:00
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
2026-01-06 11:11:37 +01:00
// Set the displaying context for proper title calculation
viewModel.DisplayingPeriod = Period;
viewModel.CalendarSettings = Settings;
2025-02-16 11:54:23 +01:00
collection.Add(calendarItem);
2025-02-16 11:54:23 +01:00
if (create)
{
_allItems.Add(calendarItem);
2024-12-28 23:17:16 +01:00
}
2025-02-16 11:54:23 +01:00
CalendarItemAdded?.Invoke(this, calendarItem);
}
2025-02-16 11:54:23 +01:00
private void RemoveCalendarItemInternal(ObservableRangeCollection<ICalendarItem> collection, ICalendarItem calendarItem, bool destroy = true)
{
if (calendarItem is not ICalendarItemViewModel)
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
2025-02-16 11:54:23 +01:00
collection.Remove(calendarItem);
2025-02-16 11:54:23 +01:00
if (destroy)
{
_allItems.Remove(calendarItem);
2024-12-28 23:17:16 +01:00
}
2025-02-16 11:54:23 +01:00
CalendarItemRemoved?.Invoke(this, calendarItem);
}
2025-02-16 11:35:43 +01:00
2026-01-06 11:11:37 +01:00
/// <summary>
/// Updates an existing calendar item in-place. If the item's type changed (all-day vs regular),
/// it will be moved to the appropriate collection.
/// </summary>
/// <param name="calendarItem">The updated calendar item data.</param>
/// <returns>True if the item was found and updated; false otherwise.</returns>
public bool UpdateCalendarItem(CalendarItem calendarItem)
{
var existingItem = _allItems.FirstOrDefault(x => x.Id == calendarItem.Id);
if (existingItem == null)
return false;
// Get the collections this item is currently in (before update)
var oldCollections = GetProperCollectionsForCalendarItem(existingItem).ToList();
// Update the underlying data
if (existingItem is ICalendarItemViewModel viewModel)
{
viewModel.UpdateFrom(calendarItem);
}
// Get the collections this item should be in (after update)
var newCollections = GetProperCollectionsForCalendarItem(existingItem).ToList();
// Check if the collections changed
var collectionsToRemoveFrom = oldCollections.Except(newCollections).ToList();
var collectionsToAddTo = newCollections.Except(oldCollections).ToList();
// Remove from old collections that are no longer applicable
foreach (var collection in collectionsToRemoveFrom)
{
collection.Remove(existingItem);
}
// Add to new collections that are now applicable
foreach (var collection in collectionsToAddTo)
{
if (!collection.Contains(existingItem))
{
collection.Add(existingItem);
}
}
CalendarItemUpdated?.Invoke(this, existingItem);
return true;
}
2025-02-16 11:54:23 +01:00
public void Clear()
{
_internalAllDayEvents.Clear();
_internalRegularEvents.Clear();
_allItems.Clear();
CalendarItemsCleared?.Invoke(this, EventArgs.Empty);
2024-12-28 23:17:16 +01:00
}
}