Updating visibilities on calendar events on calendar activation/deactivation.

This commit is contained in:
Burak Kaan Köse
2024-12-30 01:15:31 +01:00
parent bb56815210
commit 8cc7d46d7b
5 changed files with 166 additions and 106 deletions

View File

@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using CommunityToolkit.Diagnostics;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Serilog;
using Wino.Calendar.ViewModels.Data;
using Wino.Calendar.ViewModels.Interfaces;
using Wino.Core.Domain.Collections;
@@ -64,8 +65,26 @@ namespace Wino.Calendar.ViewModels
_accountCalendarStateService = accountCalendarStateService;
_preferencesService = preferencesService;
_accountCalendarStateService.AccountCalendarSelectionStateChanged += UpdateAccountCalendarRequested;
_accountCalendarStateService.CollectiveAccountGroupSelectionStateChanged += AccountCalendarStateCollectivelyChanged;
}
private void AccountCalendarStateCollectivelyChanged(object sender, GroupedAccountCalendarViewModel e)
{
// For all date ranges, update the events.
foreach (var dayRange in DayRanges)
{
_ = InitializeCalendarEventsForDayRangeAsync(dayRange);
}
}
private void UpdateAccountCalendarRequested(object sender, AccountCalendarViewModel e)
{
foreach (var range in DayRanges)
{
_ = InitializeCalendarEventsForDayRangeAsync(range);
}
}
// TODO: Replace when calendar settings are updated.
// Should be a field ideally.
@@ -125,9 +144,8 @@ namespace Wino.Calendar.ViewModels
if (ShouldResetDayRanges(message))
{
DayRanges.Clear();
Debug.WriteLine("Will reset day ranges.");
await ClearDayRangeModelsAsync();
}
else if (ShouldScrollToItem(message))
{
@@ -145,6 +163,7 @@ namespace Wino.Calendar.ViewModels
}
catch (Exception ex)
{
Log.Error(ex, "Error while loading calendar.");
Debugger.Break();
}
finally
@@ -165,6 +184,47 @@ namespace Wino.Calendar.ViewModels
return new DateRange(minimumLoadedDate, maximumLoadedDate);
}
private async Task AddDayRangeModelAsync(DayRangeRenderModel dayRangeRenderModel)
{
dayRangeRenderModel.CalendarDayEventCollectionUpdated -= EventsUpdatedInDayHeader;
dayRangeRenderModel.CalendarDayEventCollectionUpdated += EventsUpdatedInDayHeader;
await ExecuteUIThread(() =>
{
DayRanges.Add(dayRangeRenderModel);
});
}
private async Task InsertDayRangeModelAsync(DayRangeRenderModel dayRangeRenderModel, int index)
{
dayRangeRenderModel.CalendarDayEventCollectionUpdated -= EventsUpdatedInDayHeader;
dayRangeRenderModel.CalendarDayEventCollectionUpdated += EventsUpdatedInDayHeader;
await ExecuteUIThread(() =>
{
DayRanges.Insert(index, dayRangeRenderModel);
});
}
private async Task RemoveDayRangeModelAsync(DayRangeRenderModel dayRangeRenderModel)
{
dayRangeRenderModel.CalendarDayEventCollectionUpdated -= EventsUpdatedInDayHeader;
dayRangeRenderModel.UnregisterAll();
await ExecuteUIThread(() =>
{
DayRanges.Remove(dayRangeRenderModel);
});
}
private async Task ClearDayRangeModelsAsync()
{
while (DayRanges.Count > 0)
{
await RemoveDayRangeModelAsync(DayRanges[0]);
}
}
private async Task RenderDatesAsync(CalendarInitInitiative calendarInitInitiative,
DateTime? loadingDisplayDate = null,
CalendarLoadDirection calendarLoadDirection = CalendarLoadDirection.Replace)
@@ -232,10 +292,9 @@ namespace Wino.Calendar.ViewModels
}
// Dates are loaded. Now load the events for them.
foreach (var renderModel in renderModels)
{
await InitializeCalendarEventsAsync(renderModel).ConfigureAwait(false);
await InitializeCalendarEventsForDayRangeAsync(renderModel).ConfigureAwait(false);
}
CalendarLoadDirection animationDirection = calendarLoadDirection;
@@ -251,11 +310,12 @@ namespace Wino.Calendar.ViewModels
isLoadMoreBlocked = true;
// Remove all other dates except this one.
var rangesToRemove = DayRanges.Where(a => a != SelectedDayRange).ToList();
await ExecuteUIThread(() =>
foreach (var range in rangesToRemove)
{
DayRanges.RemoveRange(DayRanges.Where(a => a != SelectedDayRange).ToList());
});
await RemoveDayRangeModelAsync(range);
}
animationDirection = displayDate <= SelectedDayRange?.CalendarRenderOptions.DateRange.StartDate ?
CalendarLoadDirection.Previous : CalendarLoadDirection.Next;
@@ -263,13 +323,10 @@ namespace Wino.Calendar.ViewModels
if (animationDirection == CalendarLoadDirection.Next)
{
await ExecuteUIThread(() =>
foreach (var item in renderModels)
{
foreach (var item in renderModels)
{
DayRanges.Add(item);
}
});
await AddDayRangeModelAsync(item);
}
}
else if (animationDirection == CalendarLoadDirection.Previous)
{
@@ -281,10 +338,7 @@ namespace Wino.Calendar.ViewModels
// Insert each render model in reverse order.
for (int i = renderModels.Count - 1; i >= 0; i--)
{
await ExecuteUIThread(() =>
{
DayRanges.Insert(0, renderModels[i]);
});
await InsertDayRangeModelAsync(renderModels[i], 0);
}
}
@@ -297,10 +351,7 @@ namespace Wino.Calendar.ViewModels
if (removeCurrent)
{
await ExecuteUIThread(() =>
{
DayRanges.Remove(SelectedDayRange);
});
await RemoveDayRangeModelAsync(SelectedDayRange);
}
// TODO...
@@ -320,8 +371,36 @@ namespace Wino.Calendar.ViewModels
}
}
private async Task InitializeCalendarEventsAsync(DayRangeRenderModel dayRangeRenderModel)
// TODO...
private async void EventsUpdatedInDayHeader(object sender, CalendarDayModel e)
{
// Find the day range model that contains the day model.
// TODO: Maybe optimize by just updating the day?
if (sender is DayRangeRenderModel dayRangeRenderModel)
{
await InitializeCalendarEventsForDayRangeAsync(dayRangeRenderModel);
}
//var dayRange = DayRanges.FirstOrDefault(a => a.CalendarDays.Contains(e));
//if (dayRange == null) return;
//await InitializeCalendarEventsForDayRangeAsync(dayRange);
}
private async Task InitializeCalendarEventsForDayRangeAsync(DayRangeRenderModel dayRangeRenderModel)
{
// Clear all events first for all days.
foreach (var day in dayRangeRenderModel.CalendarDays)
{
await ExecuteUIThread(() =>
{
day.EventsCollection.Clear();
});
}
// Load for each selected calendar from the state.
var checkedCalendarViewModels = _accountCalendarStateService.GroupedAccountCalendars
.SelectMany(a => a.AccountCalendars)
@@ -352,9 +431,7 @@ namespace Wino.Calendar.ViewModels
await ExecuteUIThread(() =>
{
// Use range-based add for performance.
// No need to report changes since at this point nothing is rendered on the UI.
calendarDayModel.EventsCollection.AddCalendarItemRange(calendarItemViewModels, reportChange: false);
calendarDayModel.EventsCollection.AddCalendarItemRange(calendarItemViewModels);
});
}
}

View File

@@ -78,6 +78,8 @@ namespace Wino.Calendar.Controls
collection.CalendarItemRangeAdded += CollectionOfEventsUpdated;
collection.CalendarItemRangeRemoved += CollectionOfEventsUpdated;
collection.CalendarItemsCleared += EventsCleared;
}
private void UnregisterEventCollectionChanged(CalendarEventCollection collection)
@@ -87,10 +89,13 @@ namespace Wino.Calendar.Controls
collection.CalendarItemRangeAdded -= CollectionOfEventsUpdated;
collection.CalendarItemRangeRemoved -= CollectionOfEventsUpdated;
collection.CalendarItemsCleared -= EventsCleared;
}
private void SingleEventUpdated(object sender, ICalendarItem calendarItem) => UpdateCollectionVisuals();
private void CollectionOfEventsUpdated(object sender, List<ICalendarItem> calendarItems) => UpdateCollectionVisuals();
private void EventsCleared(object sender, System.EventArgs e) => UpdateCollectionVisuals();
private void UpdateCollectionVisuals()
{

View File

@@ -20,7 +20,6 @@ namespace Wino.Calendar.Controls
private readonly Dictionary<Guid, CalendarItemMeasurement> _measurements = new Dictionary<Guid, CalendarItemMeasurement>();
public static readonly DependencyProperty EventItemMarginProperty = DependencyProperty.Register(nameof(EventItemMargin), typeof(Thickness), typeof(WinoCalendarPanel), new PropertyMetadata(new Thickness(0, 0, 0, 0)));
// public static readonly DependencyProperty RepresentingDateProperty = DependencyProperty.Register(nameof(RepresentingDate), typeof(DateTime), typeof(WinoCalendarControl), new PropertyMetadata(DateTime.MinValue));
public static readonly DependencyProperty HourHeightProperty = DependencyProperty.Register(nameof(HourHeight), typeof(double), typeof(WinoCalendarPanel), new PropertyMetadata(0d));
public double HourHeight
@@ -35,44 +34,6 @@ namespace Wino.Calendar.Controls
set { SetValue(EventItemMarginProperty, value); }
}
//private static void OnDayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
//{
// if (d is WinoCalendarPanel control)
// {
// // We need to listen for new events being added or removed from the collection to reset measurements.
// if (e.OldValue is CalendarDayModel oldDayModel)
// {
// control.DetachCollection(oldDayModel.EventsCollection.RegularEvents);
// }
// if (e.NewValue is CalendarDayModel newDayModel)
// {
// control.AttachCollection(newDayModel.EventsCollection.RegularEvents);
// }
// control.ResetMeasurements();
// control.UpdateLayout();
// }
//}
//private void AttachCollection(IEnumerable<ICalendarItem> events)
//{
// if (events is INotifyCollectionChanged collection)
// {
// // var t = new Grid();
// collection.CollectionChanged += EventCollectionChanged;
// }
//}
//private void DetachCollection(IEnumerable<ICalendarItem> events)
//{
// if (events is INotifyCollectionChanged collection)
// {
// collection.CollectionChanged -= EventCollectionChanged;
// }
//}
private void ResetMeasurements() => _measurements.Clear();
// No need to handle actions. Each action requires a full measurement update.

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Interfaces;
namespace Wino.Core.Domain.Collections
@@ -13,6 +15,8 @@ namespace Wino.Core.Domain.Collections
public event EventHandler<List<ICalendarItem>> CalendarItemRangeAdded;
public event EventHandler<List<ICalendarItem>> CalendarItemRangeRemoved;
public event EventHandler CalendarItemsCleared;
private ObservableRangeCollection<ICalendarItem> _internalRegularEvents = [];
private ObservableRangeCollection<ICalendarItem> _internalAllDayEvents = [];
@@ -25,27 +29,33 @@ namespace Wino.Core.Domain.Collections
AllDayEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalAllDayEvents);
}
public void AddCalendarItemRange(IEnumerable<ICalendarItem> calendarItems, bool reportChange = true)
public bool HasCalendarEvent(AccountCalendar accountCalendar)
{
return _internalAllDayEvents.Any(x => x.AssignedCalendar.Id == accountCalendar.Id) ||
_internalRegularEvents.Any(x => x.AssignedCalendar.Id == accountCalendar.Id);
}
public void AddCalendarItemRange(IEnumerable<ICalendarItem> calendarItems)
{
foreach (var calendarItem in calendarItems)
{
AddCalendarItem(calendarItem, reportChange: false);
AddCalendarItem(calendarItem);
}
CalendarItemRangeAdded?.Invoke(this, new List<ICalendarItem>(calendarItems));
}
public void RemoveCalendarItemRange(IEnumerable<ICalendarItem> calendarItems, bool reportChange = true)
public void RemoveCalendarItemRange(IEnumerable<ICalendarItem> calendarItems)
{
foreach (var calendarItem in calendarItems)
{
RemoveCalendarItem(calendarItem, reportChange);
RemoveCalendarItem(calendarItem);
}
CalendarItemRangeRemoved?.Invoke(this, new List<ICalendarItem>(calendarItems));
}
public void AddCalendarItem(ICalendarItem calendarItem, bool reportChange = true)
public void AddCalendarItem(ICalendarItem calendarItem)
{
if (calendarItem is not ICalendarItemViewModel)
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
@@ -59,13 +69,18 @@ namespace Wino.Core.Domain.Collections
_internalRegularEvents.Add(calendarItem);
}
if (reportChange)
{
CalendarItemAdded?.Invoke(this, calendarItem);
}
CalendarItemAdded?.Invoke(this, calendarItem);
}
public void RemoveCalendarItem(ICalendarItem calendarItem, bool reportChange = true)
public void Clear()
{
_internalAllDayEvents.Clear();
_internalRegularEvents.Clear();
CalendarItemsCleared?.Invoke(this, EventArgs.Empty);
}
public void RemoveCalendarItem(ICalendarItem calendarItem)
{
if (calendarItem is not ICalendarItemViewModel)
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
@@ -79,10 +94,7 @@ namespace Wino.Core.Domain.Collections
_internalRegularEvents.Remove(calendarItem);
}
if (reportChange)
{
CalendarItemRemoved?.Invoke(this, calendarItem);
}
CalendarItemRemoved?.Invoke(this, calendarItem);
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Itenso.TimePeriod;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
namespace Wino.Core.Domain.Models.Calendar
{
@@ -28,6 +29,8 @@ namespace Wino.Core.Domain.Models.Calendar
var representingDate = calendarRenderOptions.DateRange.StartDate.AddDays(i);
var calendarDayModel = new CalendarDayModel(representingDate, calendarRenderOptions);
RegisterCalendarDayEvents(calendarDayModel);
CalendarDays.Add(calendarDayModel);
}
@@ -50,38 +53,40 @@ namespace Wino.Core.Domain.Models.Calendar
}
}
//private void RegisterCalendarDayEvents(CalendarDayModel calendarDayModel)
//{
// calendarDayModel.EventsCollection.CalendarItemAdded += CalendarItemAdded;
// calendarDayModel.EventsCollection.CalendarItemRangeRemoved += CalendarItemRangeRemoved;
// calendarDayModel.EventsCollection.CalendarItemRemoved += CalendarItemRemoved;
// calendarDayModel.EventsCollection.CalendarItemRangeAdded += CalendarItemRangeAdded;
//}
private void RegisterCalendarDayEvents(CalendarDayModel calendarDayModel)
{
calendarDayModel.EventsCollection.CalendarItemAdded += CalendarItemAdded;
calendarDayModel.EventsCollection.CalendarItemRangeRemoved += CalendarItemRangeRemoved;
calendarDayModel.EventsCollection.CalendarItemRemoved += CalendarItemRemoved;
calendarDayModel.EventsCollection.CalendarItemRangeAdded += CalendarItemRangeAdded;
}
//private void CalendarItemRangeAdded(object sender, List<ICalendarItem> e)
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
// TODO: These handlers have incorrect senders. They should be the CalendarDayModel.
//private void CalendarItemRemoved(object sender, ICalendarItem e)
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
private void CalendarItemRangeAdded(object sender, List<ICalendarItem> e)
=> CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
//private void CalendarItemAdded(object sender, ICalendarItem e)
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
private void CalendarItemRemoved(object sender, ICalendarItem e)
=> CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
//private void CalendarItemRangeRemoved(object sender, List<ICalendarItem> e)
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
private void CalendarItemAdded(object sender, ICalendarItem e)
=> CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
///// <summary>
///// Unregisters all calendar item change listeners to draw the UI for calendar events.
///// </summary>
//public void UnregisterAll()
//{
// foreach (var day in CalendarDays)
// {
// day.EventsCollection.CalendarItemRangeRemoved -= CalendarItemRangeRemoved;
// day.EventsCollection.CalendarItemRemoved -= CalendarItemRemoved;
// day.EventsCollection.CalendarItemRangeAdded -= CalendarItemRangeAdded;
// day.EventsCollection.CalendarItemAdded -= CalendarItemAdded;
// }
//}
private void CalendarItemRangeRemoved(object sender, List<ICalendarItem> e)
=> CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
/// <summary>
/// Unregisters all calendar item change listeners to draw the UI for calendar events.
/// </summary>
public void UnregisterAll()
{
foreach (var day in CalendarDays)
{
day.EventsCollection.CalendarItemRangeRemoved -= CalendarItemRangeRemoved;
day.EventsCollection.CalendarItemRemoved -= CalendarItemRemoved;
day.EventsCollection.CalendarItemRangeAdded -= CalendarItemRangeAdded;
day.EventsCollection.CalendarItemAdded -= CalendarItemAdded;
}
}
}
}