Skip to content

Commit

Permalink
Add default implementation of events to calendar (#183)
Browse files Browse the repository at this point in the history
  • Loading branch information
ME-MarvinE authored Mar 10, 2024
2 parents 08d6e79 + fa3ea4a commit a5a0c96
Show file tree
Hide file tree
Showing 55 changed files with 1,250 additions and 434 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; }
}
}
12 changes: 12 additions & 0 deletions XCalendar.Core/Interfaces/IEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace XCalendar.Core.Interfaces
{
public interface IEvent
{
string Title { get; set; }
string Description { get; set; }
DateTime StartDate { get; set; }
DateTime? EndDate { get; set; }
}
}
68 changes: 64 additions & 4 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 : Calendar<CalendarDay>
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,12 +722,13 @@ 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.
/// </summary>
/// <param name="navigationDate">The <see cref="DateTime"/> who's month will be used to update the dates.</param>
public void UpdateDays(DateTime navigationDate)
public virtual void UpdateDays(DateTime navigationDate)
{
OnDaysUpdating();

Expand Down Expand Up @@ -764,6 +801,25 @@ public void UpdateDays(DateTime navigationDate)

OnDaysUpdated();
}
public virtual void UpdateDayEvents(T day)
{
IEnumerable<TEvent> events = Events.Where(x => day.DateTime.Date >= x.StartDate && (x.EndDate == null || day.DateTime.Date < x.EndDate));

//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.
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 +1024,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
91 changes: 91 additions & 0 deletions XCalendar.Core/Models/Event.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using XCalendar.Core.Interfaces;

namespace XCalendar.Core.Models
{
public class Event : IEvent, INotifyPropertyChanged
{
#region Fields
private string _title;
private string _description;
private DateTime _startDate = DateTime.Today;
private DateTime? _endDate = DateTime.Today;
#endregion

#region Properties
public string Title
{
get
{
return _title;
}
set
{
if (_title != value)
{
_title = value;
OnPropertyChanged();
}
}
}
public string Description
{
get
{
return _description;
}
set
{
if (_description != value)
{
_description = value;
OnPropertyChanged();
}
}
}
public DateTime StartDate
{
get
{
return _startDate;
}
set
{
if (_startDate != value)
{
_startDate = value;
OnPropertyChanged();
}
}
}
public DateTime? EndDate
{
get
{
return _endDate;
}
set
{
if (_endDate != value)
{
_endDate = value;
OnPropertyChanged();
}
}
}
#endregion

#region Events
public event PropertyChangedEventHandler PropertyChanged;
#endregion

#region Methods
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
30 changes: 30 additions & 0 deletions XCalendar.Forms/Models/ColoredEvent.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
}
}
8 changes: 4 additions & 4 deletions XCalendar.Forms/Views/CalendarView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ public DateTime NavigatedDate
get { return (DateTime)GetValue(NavigatedDateProperty); }
set { SetValue(NavigatedDateProperty, value); }
}
public IEnumerable<ICalendarDay> Days
public IEnumerable<object> Days
{
get { return (IEnumerable<ICalendarDay>)GetValue(DaysProperty); }
get { return (IEnumerable<object>)GetValue(DaysProperty); }
set { SetValue(DaysProperty, value); }
}
public IList<DayOfWeek> DaysOfWeek
Expand Down Expand Up @@ -114,7 +114,7 @@ public DataTemplate DayTemplate

#region Bindable Properties Initialisers
public static readonly BindableProperty NavigatedDateProperty = BindableProperty.Create(nameof(NavigatedDate), typeof(DateTime), typeof(CalendarView), DateTime.Today);
public static readonly BindableProperty DaysProperty = BindableProperty.Create(nameof(DaysProperty), typeof(IEnumerable<ICalendarDay>), typeof(CalendarView), propertyChanged: DaysPropertyChanged);
public static readonly BindableProperty DaysProperty = BindableProperty.Create(nameof(DaysProperty), typeof(IEnumerable<object>), typeof(CalendarView), propertyChanged: DaysPropertyChanged);
public static readonly BindableProperty DaysOfWeekProperty = BindableProperty.Create(nameof(DaysOfWeek), typeof(IList<DayOfWeek>), typeof(CalendarView), propertyChanged: DaysOfWeekPropertyChanged);
public static readonly BindableProperty RightArrowCommandProperty = BindableProperty.Create(nameof(RightArrowCommand), typeof(object), typeof(CalendarView));
public static readonly BindableProperty RightArrowCommandParameterProperty = BindableProperty.Create(nameof(RightArrowCommandParameter), typeof(object), typeof(CalendarView));
Expand Down Expand Up @@ -148,7 +148,7 @@ public CalendarView()
private static void DaysPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
CalendarView control = (CalendarView)bindable;
IEnumerable<ICalendarDay> newDays = (IEnumerable<ICalendarDay>)newValue;
IEnumerable<object> newDays = (IEnumerable<object>)newValue;

control.MainDaysView.Days = newDays;
}
Expand Down
Loading

0 comments on commit a5a0c96

Please sign in to comment.