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.Diagnostics;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using Serilog;
using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Data;
using Wino.Calendar.ViewModels.Interfaces; using Wino.Calendar.ViewModels.Interfaces;
using Wino.Core.Domain.Collections; using Wino.Core.Domain.Collections;
@@ -64,8 +65,26 @@ namespace Wino.Calendar.ViewModels
_accountCalendarStateService = accountCalendarStateService; _accountCalendarStateService = accountCalendarStateService;
_preferencesService = preferencesService; _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. // TODO: Replace when calendar settings are updated.
// Should be a field ideally. // Should be a field ideally.
@@ -125,9 +144,8 @@ namespace Wino.Calendar.ViewModels
if (ShouldResetDayRanges(message)) if (ShouldResetDayRanges(message))
{ {
DayRanges.Clear();
Debug.WriteLine("Will reset day ranges."); Debug.WriteLine("Will reset day ranges.");
await ClearDayRangeModelsAsync();
} }
else if (ShouldScrollToItem(message)) else if (ShouldScrollToItem(message))
{ {
@@ -145,6 +163,7 @@ namespace Wino.Calendar.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex, "Error while loading calendar.");
Debugger.Break(); Debugger.Break();
} }
finally finally
@@ -165,6 +184,47 @@ namespace Wino.Calendar.ViewModels
return new DateRange(minimumLoadedDate, maximumLoadedDate); 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, private async Task RenderDatesAsync(CalendarInitInitiative calendarInitInitiative,
DateTime? loadingDisplayDate = null, DateTime? loadingDisplayDate = null,
CalendarLoadDirection calendarLoadDirection = CalendarLoadDirection.Replace) CalendarLoadDirection calendarLoadDirection = CalendarLoadDirection.Replace)
@@ -232,10 +292,9 @@ namespace Wino.Calendar.ViewModels
} }
// Dates are loaded. Now load the events for them. // Dates are loaded. Now load the events for them.
foreach (var renderModel in renderModels) foreach (var renderModel in renderModels)
{ {
await InitializeCalendarEventsAsync(renderModel).ConfigureAwait(false); await InitializeCalendarEventsForDayRangeAsync(renderModel).ConfigureAwait(false);
} }
CalendarLoadDirection animationDirection = calendarLoadDirection; CalendarLoadDirection animationDirection = calendarLoadDirection;
@@ -251,25 +310,23 @@ namespace Wino.Calendar.ViewModels
isLoadMoreBlocked = true; isLoadMoreBlocked = true;
// Remove all other dates except this one. // 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 ? animationDirection = displayDate <= SelectedDayRange?.CalendarRenderOptions.DateRange.StartDate ?
CalendarLoadDirection.Previous : CalendarLoadDirection.Next; CalendarLoadDirection.Previous : CalendarLoadDirection.Next;
} }
if (animationDirection == CalendarLoadDirection.Next) 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) else if (animationDirection == CalendarLoadDirection.Previous)
{ {
@@ -281,10 +338,7 @@ namespace Wino.Calendar.ViewModels
// Insert each render model in reverse order. // Insert each render model in reverse order.
for (int i = renderModels.Count - 1; i >= 0; i--) for (int i = renderModels.Count - 1; i >= 0; i--)
{ {
await ExecuteUIThread(() => await InsertDayRangeModelAsync(renderModels[i], 0);
{
DayRanges.Insert(0, renderModels[i]);
});
} }
} }
@@ -297,10 +351,7 @@ namespace Wino.Calendar.ViewModels
if (removeCurrent) if (removeCurrent)
{ {
await ExecuteUIThread(() => await RemoveDayRangeModelAsync(SelectedDayRange);
{
DayRanges.Remove(SelectedDayRange);
});
} }
// TODO... // 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. // Load for each selected calendar from the state.
var checkedCalendarViewModels = _accountCalendarStateService.GroupedAccountCalendars var checkedCalendarViewModels = _accountCalendarStateService.GroupedAccountCalendars
.SelectMany(a => a.AccountCalendars) .SelectMany(a => a.AccountCalendars)
@@ -352,9 +431,7 @@ namespace Wino.Calendar.ViewModels
await ExecuteUIThread(() => await ExecuteUIThread(() =>
{ {
// Use range-based add for performance. // 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);
calendarDayModel.EventsCollection.AddCalendarItemRange(calendarItemViewModels, reportChange: false);
}); });
} }
} }

View File

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

View File

@@ -20,7 +20,6 @@ namespace Wino.Calendar.Controls
private readonly Dictionary<Guid, CalendarItemMeasurement> _measurements = new Dictionary<Guid, CalendarItemMeasurement>(); 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 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 static readonly DependencyProperty HourHeightProperty = DependencyProperty.Register(nameof(HourHeight), typeof(double), typeof(WinoCalendarPanel), new PropertyMetadata(0d));
public double HourHeight public double HourHeight
@@ -35,44 +34,6 @@ namespace Wino.Calendar.Controls
set { SetValue(EventItemMarginProperty, value); } 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(); private void ResetMeasurements() => _measurements.Clear();
// No need to handle actions. Each action requires a full measurement update. // No need to handle actions. Each action requires a full measurement update.

View File

@@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
namespace Wino.Core.Domain.Collections 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>> CalendarItemRangeAdded;
public event EventHandler<List<ICalendarItem>> CalendarItemRangeRemoved; public event EventHandler<List<ICalendarItem>> CalendarItemRangeRemoved;
public event EventHandler CalendarItemsCleared;
private ObservableRangeCollection<ICalendarItem> _internalRegularEvents = []; private ObservableRangeCollection<ICalendarItem> _internalRegularEvents = [];
private ObservableRangeCollection<ICalendarItem> _internalAllDayEvents = []; private ObservableRangeCollection<ICalendarItem> _internalAllDayEvents = [];
@@ -25,27 +29,33 @@ namespace Wino.Core.Domain.Collections
AllDayEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalAllDayEvents); 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) foreach (var calendarItem in calendarItems)
{ {
AddCalendarItem(calendarItem, reportChange: false); AddCalendarItem(calendarItem);
} }
CalendarItemRangeAdded?.Invoke(this, new List<ICalendarItem>(calendarItems)); 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) foreach (var calendarItem in calendarItems)
{ {
RemoveCalendarItem(calendarItem, reportChange); RemoveCalendarItem(calendarItem);
} }
CalendarItemRangeRemoved?.Invoke(this, new List<ICalendarItem>(calendarItems)); 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) if (calendarItem is not ICalendarItemViewModel)
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem)); throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
@@ -59,13 +69,18 @@ namespace Wino.Core.Domain.Collections
_internalRegularEvents.Add(calendarItem); _internalRegularEvents.Add(calendarItem);
} }
if (reportChange)
{
CalendarItemAdded?.Invoke(this, calendarItem); CalendarItemAdded?.Invoke(this, calendarItem);
} }
public void Clear()
{
_internalAllDayEvents.Clear();
_internalRegularEvents.Clear();
CalendarItemsCleared?.Invoke(this, EventArgs.Empty);
} }
public void RemoveCalendarItem(ICalendarItem calendarItem, bool reportChange = true) public void RemoveCalendarItem(ICalendarItem calendarItem)
{ {
if (calendarItem is not ICalendarItemViewModel) if (calendarItem is not ICalendarItemViewModel)
throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem)); throw new ArgumentException("CalendarItem must be of type ICalendarItemViewModel", nameof(calendarItem));
@@ -79,10 +94,7 @@ namespace Wino.Core.Domain.Collections
_internalRegularEvents.Remove(calendarItem); _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 System.Linq;
using Itenso.TimePeriod; using Itenso.TimePeriod;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
namespace Wino.Core.Domain.Models.Calendar namespace Wino.Core.Domain.Models.Calendar
{ {
@@ -28,6 +29,8 @@ namespace Wino.Core.Domain.Models.Calendar
var representingDate = calendarRenderOptions.DateRange.StartDate.AddDays(i); var representingDate = calendarRenderOptions.DateRange.StartDate.AddDays(i);
var calendarDayModel = new CalendarDayModel(representingDate, calendarRenderOptions); var calendarDayModel = new CalendarDayModel(representingDate, calendarRenderOptions);
RegisterCalendarDayEvents(calendarDayModel);
CalendarDays.Add(calendarDayModel); CalendarDays.Add(calendarDayModel);
} }
@@ -50,38 +53,40 @@ namespace Wino.Core.Domain.Models.Calendar
} }
} }
//private void RegisterCalendarDayEvents(CalendarDayModel calendarDayModel) private void RegisterCalendarDayEvents(CalendarDayModel calendarDayModel)
//{ {
// calendarDayModel.EventsCollection.CalendarItemAdded += CalendarItemAdded; calendarDayModel.EventsCollection.CalendarItemAdded += CalendarItemAdded;
// calendarDayModel.EventsCollection.CalendarItemRangeRemoved += CalendarItemRangeRemoved; calendarDayModel.EventsCollection.CalendarItemRangeRemoved += CalendarItemRangeRemoved;
// calendarDayModel.EventsCollection.CalendarItemRemoved += CalendarItemRemoved; calendarDayModel.EventsCollection.CalendarItemRemoved += CalendarItemRemoved;
// calendarDayModel.EventsCollection.CalendarItemRangeAdded += CalendarItemRangeAdded; calendarDayModel.EventsCollection.CalendarItemRangeAdded += CalendarItemRangeAdded;
//} }
//private void CalendarItemRangeAdded(object sender, List<ICalendarItem> e) // TODO: These handlers have incorrect senders. They should be the CalendarDayModel.
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
//private void CalendarItemRemoved(object sender, ICalendarItem e) private void CalendarItemRangeAdded(object sender, List<ICalendarItem> e)
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel); => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
//private void CalendarItemAdded(object sender, ICalendarItem e) private void CalendarItemRemoved(object sender, ICalendarItem e)
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel); => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
//private void CalendarItemRangeRemoved(object sender, List<ICalendarItem> e) private void CalendarItemAdded(object sender, ICalendarItem e)
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel); => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
///// <summary> private void CalendarItemRangeRemoved(object sender, List<ICalendarItem> e)
///// Unregisters all calendar item change listeners to draw the UI for calendar events. => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
///// </summary>
//public void UnregisterAll() /// <summary>
//{ /// Unregisters all calendar item change listeners to draw the UI for calendar events.
// foreach (var day in CalendarDays) /// </summary>
// { public void UnregisterAll()
// day.EventsCollection.CalendarItemRangeRemoved -= CalendarItemRangeRemoved; {
// day.EventsCollection.CalendarItemRemoved -= CalendarItemRemoved; foreach (var day in CalendarDays)
// day.EventsCollection.CalendarItemRangeAdded -= CalendarItemRangeAdded; {
// day.EventsCollection.CalendarItemAdded -= CalendarItemAdded; day.EventsCollection.CalendarItemRangeRemoved -= CalendarItemRangeRemoved;
// } day.EventsCollection.CalendarItemRemoved -= CalendarItemRemoved;
//} day.EventsCollection.CalendarItemRangeAdded -= CalendarItemRangeAdded;
day.EventsCollection.CalendarItemAdded -= CalendarItemAdded;
}
}
} }
} }