[go: nahoru, domu]

Skip to content

Commit

Permalink
Add default implementation of calendar days with events to XCalendar.…
Browse files Browse the repository at this point in the history
…Core
  • Loading branch information
ME-MarvinE committed Mar 10, 2024
1 parent cad0305 commit 0515fab
Show file tree
Hide file tree
Showing 54 changed files with 492 additions and 623 deletions.
15 changes: 13 additions & 2 deletions XCalendar.Core/Interfaces/ICalendar.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using XCalendar.Core.Collections;
using XCalendar.Core.Enums;
using XCalendar.Core.Models;

namespace XCalendar.Core.Interfaces
{
public interface ICalendar<T> : INotifyPropertyChanged where T : ICalendarDay, new()
/// <summary>
/// An interface representing a calendar.
/// </summary>
/// <typeparam name="T">A model implementing <see cref="ICalendarDay{TEvent}"/> to be used to represent each day in a page.</typeparam>
public interface ICalendar<T> : ICalendar<T, IEvent> where T : ICalendarDay<IEvent>, new()
{
}
/// <summary>
/// An interface representing a calendar.
/// </summary>
/// <typeparam name="T">A model implementing <see cref="ICalendarDay{TEvent}"/> to be used to represent each day in a page.</typeparam>
/// <typeparam name="TEvent">A model implementing <see cref="IEvent"/> to be used to represent calendar events.</typeparam>
public interface ICalendar<T, TEvent> : INotifyPropertyChanged where T : ICalendarDay<TEvent>, new() where TEvent : IEvent
{
#region Properties
ObservableRangeCollection<T> Days { get; }
Expand Down
7 changes: 6 additions & 1 deletion XCalendar.Core/Interfaces/ICalendarDay.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
using System;
using System.ComponentModel;
using XCalendar.Core.Collections;

namespace XCalendar.Core.Interfaces
{
public interface ICalendarDay : INotifyPropertyChanged
public interface ICalendarDay : ICalendarDay<IEvent>
{
}
public interface ICalendarDay<TEvent> : INotifyPropertyChanged where TEvent : IEvent
{
DateTime DateTime { get; set; }
bool IsSelected { get; set; }
bool IsCurrentMonth { get; set; }
bool IsToday { get; set; }
bool IsInvalid { get; set; }
ObservableRangeCollection<TEvent> Events { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
namespace XCalendar.Maui.Interfaces
using System;

namespace XCalendar.Core.Interfaces
{
public interface IEvent
{
string Title { get; set; }
string Description { get; set; }
DateTime DateTime { get; set; }
Color Color { get; set; }
}
}
74 changes: 71 additions & 3 deletions XCalendar.Core/Models/Calendar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,22 @@ namespace XCalendar.Core.Models
/// <summary>
/// A class representing a calendar.
/// </summary>
public class Calendar : Calendar<CalendarDay>
public class Calendar : Calendar<CalendarDay, Event>
{
}
/// <summary>
/// A class representing a calendar.
/// </summary>
/// <typeparam name="T">A model implementing <see cref="ICalendarDay"/> to be used to represent each day in a page.</typeparam>
public class Calendar<T> : ICalendar<T> where T : ICalendarDay, new()
/// <typeparam name="T">A model implementing <see cref="ICalendarDay{TEvent}"/> to be used to represent each day in a page.</typeparam>
public class Calendar<T> : Calendar<T, Event> where T : ICalendarDay<Event>, new()
{
}
/// <summary>
/// A class representing a calendar.
/// </summary>
/// <typeparam name="T">A model implementing <see cref="ICalendarDay{TEvent}"/> to be used to represent each day in a page.</typeparam>
/// <typeparam name="TEvent">A model implementing <see cref="IEvent"/> to be used to represent calendar events.</typeparam>
public class Calendar<T, TEvent> : ICalendar<T, TEvent> where T : ICalendarDay<TEvent>, new() where TEvent : IEvent
{
#region Fields
protected static readonly ReadOnlyCollection<DayOfWeek> DaysOfWeek = DayOfWeekExtensions.DaysOfWeek;
Expand All @@ -46,6 +54,7 @@ public class Calendar<T> : ICalendar<T> where T : ICalendarDay, new()
private DateTime? _rangeSelectionStart;
private DateTime? _rangeSelectionEnd;
private SelectionType _selectionType = SelectionType.None;
private ObservableRangeCollection<TEvent> _events = new ObservableRangeCollection<TEvent>();
#endregion

#region Properties
Expand Down Expand Up @@ -438,6 +447,31 @@ public SelectionType SelectionType
}
}
}
public ObservableRangeCollection<TEvent> Events
{
get
{
return _events;
}
set
{
if (_events != value)
{
if (_events != null)
{
_events.CollectionChanged -= Events_CollectionChanged;
}

if (value != null)
{
value.CollectionChanged += Events_CollectionChanged;
}

_events = value;
OnPropertyChanged();
}
}
}
#endregion

#region Events
Expand Down Expand Up @@ -472,6 +506,8 @@ public Calendar()
SelectedDates.CollectionChanged += SelectedDates_CollectionChanged;
}

Events.CollectionChanged += Events_CollectionChanged;

//Not needed because days are updated in previous lines of code.
UpdateDays(NavigatedDate);
}
Expand Down Expand Up @@ -686,6 +722,7 @@ public virtual void UpdateDay(T day, DateTime newDateTime)
day.IsToday = IsDateTimeToday(day.DateTime);
day.IsSelected = IsDateTimeSelected(day.DateTime);
day.IsInvalid = IsDateTimeInvalid(day.DateTime);
UpdateDayEvents(day);
}
/// <summary>
/// Updates the dates displayed on the calendar.
Expand Down Expand Up @@ -764,6 +801,33 @@ public virtual void UpdateDays(DateTime navigationDate)

OnDaysUpdated();
}
public virtual void UpdateDayEvents(T day)
{
//It is known that the only thing that the events of the day depend on is the DateTime of the day, and that all events will have the same date.
//So, only update the events if the existing ones' DateTime does not match the day's DateTime.
//If the day has no events, there is no way to tell if it's because the day hasn't been updated before or if there are no events with that date, so update it either way.
if (day.Events.Count > 0 && day.DateTime.Date == day.Events[0].DateTime.Date)
{
return;
}

IEnumerable<TEvent> events = Events.Where(x => x.DateTime.Date == day.DateTime.Date);

//No use in replacing the collection if the source and target are both empty.
if (day.Events.Count == 0 && !events.Any())
{
return;
}

//SequenceEqual could be omitted to improve performance but in the vast majority of cases there won't even be more than 5 events in one day, so impact on performance should be negligible
//compared to always changing the collection and updating the binding.
if (day.Events.SequenceEqual(events))
{
return;
}

day.Events.ReplaceRange(events);
}
/// <summary>
/// Navigates the calendar by the specified <see cref="TimeSpan"/> using the navigation rule properties set in the calendar (<see cref="NavigationLowerBound"/>, <see cref="NavigationUpperBound"/> <see cref="NavigationLoopMode"/>).
/// </summary>
Expand Down Expand Up @@ -968,6 +1032,10 @@ private int CoerceRows(int value)
{
return AutoRows ? GetMonthRows(NavigatedDate, AutoRowsIsConsistent, StartOfWeek) : value;
}
private void Events_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateDays(NavigatedDate);
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Expand Down
23 changes: 22 additions & 1 deletion XCalendar.Core/Models/CalendarDay.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using XCalendar.Core.Collections;
using XCalendar.Core.Interfaces;

namespace XCalendar.Core.Models
{
public class CalendarDay : ICalendarDay
public class CalendarDay : CalendarDay<Event>
{
}

public class CalendarDay<TEvent> : ICalendarDay<TEvent> where TEvent : IEvent
{
#region Fields
private DateTime _dateTime = DateTime.Today;
private bool _isSelected;
private bool _isCurrentMonth;
private bool _isToday;
private bool _isInvalid;
private ObservableRangeCollection<TEvent> _events = new ObservableRangeCollection<TEvent>();
#endregion

#region Properties
Expand Down Expand Up @@ -91,6 +97,21 @@ public bool IsInvalid
}
}
}
public ObservableRangeCollection<TEvent> Events
{
get
{
return _events;
}
set
{
if (_events != value)
{
_events = value;
OnPropertyChanged();
}
}
}
#endregion

#region Events
Expand Down
25 changes: 4 additions & 21 deletions XCalendar.Forms/Models/Event.cs → XCalendar.Core/Models/Event.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
using XCalendar.Forms.Interfaces;
using XCalendar.Core.Interfaces;

namespace XCalendar.Forms.Models
namespace XCalendar.Core.Models
{
public class Event : IEvent, INotifyPropertyChanged
{
#region Fields
private string _title;
private string _description;
private DateTime _dateTime = DateTime.Today;
private Color _color;
#endregion

#region Properties
Expand All @@ -31,7 +29,8 @@ public string Title
}
}
}
public string Description {
public string Description
{
get
{
return _description;
Expand Down Expand Up @@ -60,22 +59,6 @@ public DateTime DateTime
}
}
}
public Color Color
{
get
{
return _color;
}
set
{
if (_color != value)
{
_color = value;
OnPropertyChanged();
}
}
}

#endregion

#region Events
Expand Down
10 changes: 0 additions & 10 deletions XCalendar.Forms/Interfaces/IComplexCalendarDay.cs

This file was deleted.

13 changes: 0 additions & 13 deletions XCalendar.Forms/Interfaces/IEvent.cs

This file was deleted.

30 changes: 30 additions & 0 deletions XCalendar.Forms/Models/ColouredEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Xamarin.Forms;
using XCalendar.Core.Models;

namespace XCalendar.Forms.Models
{
public class ColoredEvent : Event
{
#region Fields
private Color _color;
#endregion

#region Properties
public Color Color
{
get
{
return _color;
}
set
{
if (_color != value)
{
_color = value;
OnPropertyChanged();
}
}
}
#endregion
}
}
Loading

0 comments on commit 0515fab

Please sign in to comment.