Improved calendar rendering, standartization of some templates and cleanup of old styles.
This commit is contained in:
@@ -63,8 +63,10 @@ namespace Wino.Calendar.ViewModels
|
|||||||
_calendarService = calendarService;
|
_calendarService = calendarService;
|
||||||
_accountCalendarStateService = accountCalendarStateService;
|
_accountCalendarStateService = accountCalendarStateService;
|
||||||
_preferencesService = preferencesService;
|
_preferencesService = preferencesService;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Replace when calendar settings are updated.
|
// TODO: Replace when calendar settings are updated.
|
||||||
// Should be a field ideally.
|
// Should be a field ideally.
|
||||||
private BaseCalendarTypeDrawingStrategy GetDrawingStrategy(CalendarDisplayType displayType)
|
private BaseCalendarTypeDrawingStrategy GetDrawingStrategy(CalendarDisplayType displayType)
|
||||||
@@ -225,7 +227,8 @@ namespace Wino.Calendar.ViewModels
|
|||||||
var range = new DateRange(startDate, endDate);
|
var range = new DateRange(startDate, endDate);
|
||||||
var renderOptions = new CalendarRenderOptions(range, _currentSettings);
|
var renderOptions = new CalendarRenderOptions(range, _currentSettings);
|
||||||
|
|
||||||
renderModels.Add(new DayRangeRenderModel(renderOptions));
|
var dayRangeHeaderModel = new DayRangeRenderModel(renderOptions);
|
||||||
|
renderModels.Add(dayRangeHeaderModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dates are loaded. Now load the events for them.
|
// Dates are loaded. Now load the events for them.
|
||||||
@@ -334,20 +337,24 @@ namespace Wino.Calendar.ViewModels
|
|||||||
dayRangeRenderModel.Period.End)
|
dayRangeRenderModel.Period.End)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
foreach (var calendarItem in events)
|
var groupedEvents = events.GroupBy(a => a.StartTime.Date);
|
||||||
|
|
||||||
|
foreach (var group in groupedEvents)
|
||||||
{
|
{
|
||||||
var calendarDayModel = dayRangeRenderModel.CalendarDays.FirstOrDefault(a => a.RepresentingDate.Date == calendarItem.StartTime.Date);
|
var startDate = group.Key;
|
||||||
|
|
||||||
|
var calendarDayModel = dayRangeRenderModel.CalendarDays.FirstOrDefault(a => a.RepresentingDate.Date == startDate);
|
||||||
|
|
||||||
if (calendarDayModel == null) continue;
|
if (calendarDayModel == null) continue;
|
||||||
|
|
||||||
var calendarItemViewModel = new CalendarItemViewModel(calendarItem);
|
var calendarItemViewModels = group.Select(a => new CalendarItemViewModel(a));
|
||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThread(() =>
|
||||||
{
|
{
|
||||||
// TODO: EventsCollection should not take CalendarItem, but CalendarItemViewModel.
|
// Use range-based add for performance.
|
||||||
// Enforce it later on.
|
// No need to report changes since at this point nothing is rendered on the UI.
|
||||||
|
|
||||||
calendarDayModel.EventsCollection.Add(calendarItemViewModel);
|
calendarDayModel.EventsCollection.AddCalendarItemRange(calendarItemViewModels, reportChange: false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,19 +14,14 @@
|
|||||||
|
|
||||||
<core:CoreGeneric />
|
<core:CoreGeneric />
|
||||||
|
|
||||||
<!-- Calendar Specific -->
|
|
||||||
<styles:WinoCalendarResources />
|
<styles:WinoCalendarResources />
|
||||||
|
|
||||||
<ResourceDictionary Source="Styles/CalendarRenderStyles.xaml" />
|
<ResourceDictionary Source="Styles/CalendarThemeResources.xaml" />
|
||||||
|
|
||||||
<ResourceDictionary Source="Styles/CalendarDayItemsControl.xaml" />
|
|
||||||
<styles:DayColumnControlResources />
|
|
||||||
<ResourceDictionary Source="Styles/WinoDayTimelineCanvas.xaml" />
|
<ResourceDictionary Source="Styles/WinoDayTimelineCanvas.xaml" />
|
||||||
<ResourceDictionary Source="Styles/WinoCalendarView.xaml" />
|
<ResourceDictionary Source="Styles/WinoCalendarView.xaml" />
|
||||||
<ResourceDictionary Source="Styles/WinoCalendarTypeSelectorControl.xaml" />
|
<ResourceDictionary Source="Styles/WinoCalendarTypeSelectorControl.xaml" />
|
||||||
|
|
||||||
<styles:CalendarItemControlResources />
|
|
||||||
|
|
||||||
<!-- Last item must always be the default theme. -->
|
<!-- Last item must always be the default theme. -->
|
||||||
<ResourceDictionary Source="ms-appx:///Wino.Core.UWP/AppThemes/Mica.xaml" />
|
<ResourceDictionary Source="ms-appx:///Wino.Core.UWP/AppThemes/Mica.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<ItemsControl
|
<ItemsControl
|
||||||
x:Name="PART_AllDayItemsList"
|
x:Name="PART_AllDayItemsList"
|
||||||
ItemTemplate="{x:Bind AllDayEventTemplate}"
|
ItemTemplate="{x:Bind AllDayEventTemplate}"
|
||||||
ItemsSource="{x:Bind AllDayEvents, Mode=OneWay}" />
|
ItemsSource="{x:Bind EventCollection.AllDayEvents}" />
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<Button
|
<Button
|
||||||
x:Name="AllDayItemsSummaryButton"
|
x:Name="AllDayItemsSummaryButton"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout Placement="Bottom">
|
<Flyout Placement="Bottom">
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
<ItemsControl ItemTemplate="{x:Bind AllDayEventTemplate}" ItemsSource="{x:Bind AllDayEvents, Mode=OneWay}" />
|
<ItemsControl ItemTemplate="{x:Bind RegularEventItemTemplate}" ItemsSource="{x:Bind EventCollection.AllDayEvents}" />
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Flyout>
|
</Flyout>
|
||||||
</Button.Flyout>
|
</Button.Flyout>
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
<Setter Target="AllDayItemsSummaryButton.Content">
|
<Setter Target="AllDayItemsSummaryButton.Content">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<TextBlock>
|
<TextBlock>
|
||||||
<Run Text="{x:Bind AllDayEvents.Count, Mode=OneWay, TargetNullValue='0'}" /> <Run Text="{x:Bind domain:Translator.CalendarAllDayEventSummary}" />
|
<Run Text="{x:Bind EventCollection.AllDayEvents.Count, Mode=OneWay, TargetNullValue='0'}" /> <Run Text="{x:Bind domain:Translator.CalendarAllDayEventSummary}" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.Generic;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Wino.Core.Domain.Collections;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
|
|
||||||
@@ -13,19 +14,36 @@ namespace Wino.Calendar.Controls
|
|||||||
|
|
||||||
#region Dependency Properties
|
#region Dependency Properties
|
||||||
|
|
||||||
public static readonly DependencyProperty AllDayEventsProperty = DependencyProperty.Register(nameof(AllDayEvents), typeof(ObservableCollection<ICalendarItem>), typeof(AllDayItemsControl), new PropertyMetadata(null, new PropertyChangedCallback(OnAllDayEventsChanged)));
|
public static readonly DependencyProperty EventCollectionProperty = DependencyProperty.Register(nameof(EventCollection), typeof(CalendarEventCollection), typeof(AllDayItemsControl), new PropertyMetadata(null, new PropertyChangedCallback(OnAllDayEventsChanged)));
|
||||||
public static readonly DependencyProperty AllDayEventTemplateProperty = DependencyProperty.Register(nameof(AllDayEventTemplate), typeof(DataTemplate), typeof(AllDayItemsControl), new PropertyMetadata(null));
|
public static readonly DependencyProperty AllDayEventTemplateProperty = DependencyProperty.Register(nameof(AllDayEventTemplate), typeof(DataTemplate), typeof(AllDayItemsControl), new PropertyMetadata(null));
|
||||||
|
public static readonly DependencyProperty RegularEventItemTemplateProperty = DependencyProperty.Register(nameof(RegularEventItemTemplate), typeof(DataTemplate), typeof(AllDayItemsControl), new PropertyMetadata(null));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Item template for all-day events to display in summary view area.
|
||||||
|
/// More than 2 events will be shown in Flyout.
|
||||||
|
/// </summary>
|
||||||
public DataTemplate AllDayEventTemplate
|
public DataTemplate AllDayEventTemplate
|
||||||
{
|
{
|
||||||
get { return (DataTemplate)GetValue(AllDayEventTemplateProperty); }
|
get { return (DataTemplate)GetValue(AllDayEventTemplateProperty); }
|
||||||
set { SetValue(AllDayEventTemplateProperty, value); }
|
set { SetValue(AllDayEventTemplateProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollection<ICalendarItem> AllDayEvents
|
/// <summary>
|
||||||
|
/// Item template for all-day events to display in summary view's Flyout.
|
||||||
|
/// </summary>
|
||||||
|
public DataTemplate RegularEventItemTemplate
|
||||||
{
|
{
|
||||||
get { return (ObservableCollection<ICalendarItem>)GetValue(AllDayEventsProperty); }
|
get { return (DataTemplate)GetValue(RegularEventItemTemplateProperty); }
|
||||||
set { SetValue(AllDayEventsProperty, value); }
|
set { SetValue(RegularEventItemTemplateProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whole collection of events to display.
|
||||||
|
/// </summary>
|
||||||
|
public CalendarEventCollection EventCollection
|
||||||
|
{
|
||||||
|
get { return (CalendarEventCollection)GetValue(EventCollectionProperty); }
|
||||||
|
set { SetValue(EventCollectionProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -39,12 +57,12 @@ namespace Wino.Calendar.Controls
|
|||||||
{
|
{
|
||||||
if (d is AllDayItemsControl control)
|
if (d is AllDayItemsControl control)
|
||||||
{
|
{
|
||||||
if (e.OldValue != null && e.OldValue is ObservableCollection<ICalendarItem> oldCollection)
|
if (e.OldValue != null && e.OldValue is CalendarEventCollection oldCollection)
|
||||||
{
|
{
|
||||||
control.UnregisterEventCollectionChanged(oldCollection);
|
control.UnregisterEventCollectionChanged(oldCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.NewValue != null && e.NewValue is ObservableCollection<ICalendarItem> newCollection)
|
if (e.NewValue != null && e.NewValue is CalendarEventCollection newCollection)
|
||||||
{
|
{
|
||||||
control.RegisterEventCollectionChanged(newCollection);
|
control.RegisterEventCollectionChanged(newCollection);
|
||||||
}
|
}
|
||||||
@@ -53,32 +71,35 @@ namespace Wino.Calendar.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterEventCollectionChanged(ObservableCollection<ICalendarItem> collection)
|
private void RegisterEventCollectionChanged(CalendarEventCollection collection)
|
||||||
{
|
{
|
||||||
collection.CollectionChanged += EventsCollectionUpdated;
|
collection.CalendarItemAdded += SingleEventUpdated;
|
||||||
|
collection.CalendarItemRemoved += SingleEventUpdated;
|
||||||
|
|
||||||
|
collection.CalendarItemRangeAdded += CollectionOfEventsUpdated;
|
||||||
|
collection.CalendarItemRangeRemoved += CollectionOfEventsUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnregisterEventCollectionChanged(ObservableCollection<ICalendarItem> collection)
|
private void UnregisterEventCollectionChanged(CalendarEventCollection collection)
|
||||||
{
|
{
|
||||||
collection.CollectionChanged -= EventsCollectionUpdated;
|
collection.CalendarItemAdded -= SingleEventUpdated;
|
||||||
|
collection.CalendarItemRemoved -= SingleEventUpdated;
|
||||||
|
|
||||||
|
collection.CalendarItemRangeAdded -= CollectionOfEventsUpdated;
|
||||||
|
collection.CalendarItemRangeRemoved -= CollectionOfEventsUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EventsCollectionUpdated(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
private void SingleEventUpdated(object sender, ICalendarItem calendarItem) => UpdateCollectionVisuals();
|
||||||
{
|
private void CollectionOfEventsUpdated(object sender, List<ICalendarItem> calendarItems) => UpdateCollectionVisuals();
|
||||||
UpdateCollectionVisuals();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateCollectionVisuals()
|
private void UpdateCollectionVisuals()
|
||||||
{
|
{
|
||||||
if (AllDayEvents == null) return;
|
if (EventCollection == null) return;
|
||||||
|
|
||||||
if (AllDayEvents.Count > 1)
|
if (EventCollection.AllDayEvents.Count > 1)
|
||||||
{
|
{
|
||||||
// Summarize
|
// Summarize
|
||||||
|
|
||||||
VisualStateManager.GoToState(this, STATE_SummaryView, false);
|
VisualStateManager.GoToState(this, STATE_SummaryView, false);
|
||||||
|
|
||||||
// AllDayItemsSummaryButton.Content = $"{AllDayEvents.Count} {Translator.CalendarAllDayEventSummary}";
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Linq;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
|
||||||
using Wino.Core.Domain.Interfaces;
|
|
||||||
using Wino.Core.Domain.Models.Calendar;
|
|
||||||
|
|
||||||
namespace Wino.Calendar.Controls
|
|
||||||
{
|
|
||||||
public class CalendarDayItemsControl : Control
|
|
||||||
{
|
|
||||||
private const string PART_CalendarPanel = nameof(PART_CalendarPanel);
|
|
||||||
|
|
||||||
private WinoCalendarPanel CalendarPanel;
|
|
||||||
|
|
||||||
public CalendarDayModel DayModel
|
|
||||||
{
|
|
||||||
get { return (CalendarDayModel)GetValue(DayModelProperty); }
|
|
||||||
set { SetValue(DayModelProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static readonly DependencyProperty DayModelProperty = DependencyProperty.Register(nameof(DayModel), typeof(CalendarDayModel), typeof(CalendarDayItemsControl), new PropertyMetadata(null, new PropertyChangedCallback(OnRepresentingDateChanged)));
|
|
||||||
|
|
||||||
private static void OnRepresentingDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (d is CalendarDayItemsControl control)
|
|
||||||
{
|
|
||||||
if (e.OldValue != null && e.OldValue is CalendarDayModel oldCalendarDayModel)
|
|
||||||
{
|
|
||||||
control.DetachCollection(oldCalendarDayModel.EventsCollection);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.NewValue != null && e.NewValue is CalendarDayModel newCalendarDayModel)
|
|
||||||
{
|
|
||||||
control.AttachCollection(newCalendarDayModel.EventsCollection);
|
|
||||||
}
|
|
||||||
|
|
||||||
control.ResetItems();
|
|
||||||
control.RenderEvents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CalendarDayItemsControl()
|
|
||||||
{
|
|
||||||
DefaultStyleKey = typeof(CalendarDayItemsControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnApplyTemplate()
|
|
||||||
{
|
|
||||||
base.OnApplyTemplate();
|
|
||||||
|
|
||||||
CalendarPanel = GetTemplateChild(PART_CalendarPanel) as WinoCalendarPanel;
|
|
||||||
|
|
||||||
RenderEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResetItems()
|
|
||||||
{
|
|
||||||
if (CalendarPanel == null) return;
|
|
||||||
|
|
||||||
CalendarPanel.Children.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderEvents()
|
|
||||||
{
|
|
||||||
if (CalendarPanel == null || CalendarPanel.DayModel == null) return;
|
|
||||||
|
|
||||||
RenderCalendarItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AttachCollection(ObservableCollection<ICalendarItem> newCollection)
|
|
||||||
=> newCollection.CollectionChanged += CalendarItemsChanged;
|
|
||||||
|
|
||||||
private void DetachCollection(ObservableCollection<ICalendarItem> oldCollection)
|
|
||||||
=> oldCollection.CollectionChanged -= CalendarItemsChanged;
|
|
||||||
|
|
||||||
private void CalendarItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
foreach (ICalendarItem item in e.NewItems)
|
|
||||||
{
|
|
||||||
AddItem(item);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
foreach (ICalendarItem item in e.OldItems)
|
|
||||||
{
|
|
||||||
var control = GetCalendarItemControl(item);
|
|
||||||
if (control != null)
|
|
||||||
{
|
|
||||||
CalendarPanel.Children.Remove(control);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
ResetItems();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private CalendarItemControl GetCalendarItemControl(ICalendarItem item)
|
|
||||||
=> CalendarPanel.Children.Where(c => c is CalendarItemControl calendarItemControl && calendarItemControl.Item == item).FirstOrDefault() as CalendarItemControl;
|
|
||||||
|
|
||||||
private void RenderCalendarItems()
|
|
||||||
{
|
|
||||||
if (DayModel == null || DayModel.EventsCollection == null || DayModel.EventsCollection.Count == 0)
|
|
||||||
{
|
|
||||||
ResetItems();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in DayModel.EventsCollection)
|
|
||||||
{
|
|
||||||
AddItem(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddItem(ICalendarItem item)
|
|
||||||
{
|
|
||||||
CalendarPanel.Children.Add(new CalendarItemControl()
|
|
||||||
{
|
|
||||||
Item = item
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
|
||||||
using Wino.Core.Domain.Interfaces;
|
|
||||||
|
|
||||||
namespace Wino.Calendar.Controls
|
|
||||||
{
|
|
||||||
public class CalendarItemControl : Control
|
|
||||||
{
|
|
||||||
public ICalendarItem Item
|
|
||||||
{
|
|
||||||
get { return (ICalendarItem)GetValue(ItemProperty); }
|
|
||||||
set { SetValue(ItemProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly DependencyProperty ItemProperty = DependencyProperty.Register(nameof(Item), typeof(ICalendarItem), typeof(CalendarItemControl), new PropertyMetadata(null, new PropertyChangedCallback(OnItemChanged)));
|
|
||||||
|
|
||||||
public CalendarItemControl()
|
|
||||||
{
|
|
||||||
DefaultStyleKey = typeof(CalendarItemControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (d is CalendarItemControl control)
|
|
||||||
{
|
|
||||||
control.UpdateDateRendering();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateDateRendering()
|
|
||||||
{
|
|
||||||
if (Item == null) return;
|
|
||||||
|
|
||||||
UpdateLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return Item?.Title ?? "NA";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,8 +7,8 @@ using Windows.Foundation;
|
|||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Wino.Calendar.Models;
|
using Wino.Calendar.Models;
|
||||||
|
using Wino.Calendar.ViewModels.Data;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.Calendar;
|
|
||||||
|
|
||||||
namespace Wino.Calendar.Controls
|
namespace Wino.Calendar.Controls
|
||||||
{
|
{
|
||||||
@@ -20,12 +20,13 @@ 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 DayModelProperty = DependencyProperty.Register(nameof(DayModel), typeof(CalendarDayModel), typeof(WinoCalendarPanel), new PropertyMetadata(null, new PropertyChangedCallback(OnDayChanged)));
|
// 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 CalendarDayModel DayModel
|
public double HourHeight
|
||||||
{
|
{
|
||||||
get { return (CalendarDayModel)GetValue(DayModelProperty); }
|
get { return (double)GetValue(HourHeightProperty); }
|
||||||
set { SetValue(DayModelProperty, value); }
|
set { SetValue(HourHeightProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Thickness EventItemMargin
|
public Thickness EventItemMargin
|
||||||
@@ -34,51 +35,55 @@ namespace Wino.Calendar.Controls
|
|||||||
set { SetValue(EventItemMarginProperty, value); }
|
set { SetValue(EventItemMarginProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnDayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
//private static void OnDayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
{
|
//{
|
||||||
if (d is WinoCalendarPanel control)
|
// if (d is WinoCalendarPanel control)
|
||||||
{
|
// {
|
||||||
// We need to listen for new events being added or removed from the collection to reset measurements.
|
// // We need to listen for new events being added or removed from the collection to reset measurements.
|
||||||
if (e.OldValue is CalendarDayModel oldDayModel)
|
// if (e.OldValue is CalendarDayModel oldDayModel)
|
||||||
{
|
// {
|
||||||
control.DetachCollection(oldDayModel.EventsCollection);
|
// control.DetachCollection(oldDayModel.EventsCollection.RegularEvents);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (e.NewValue is CalendarDayModel newDayModel)
|
// if (e.NewValue is CalendarDayModel newDayModel)
|
||||||
{
|
// {
|
||||||
control.AttachCollection(newDayModel.EventsCollection);
|
// control.AttachCollection(newDayModel.EventsCollection.RegularEvents);
|
||||||
}
|
// }
|
||||||
|
|
||||||
control.ResetMeasurements();
|
// control.ResetMeasurements();
|
||||||
control.UpdateLayout();
|
// control.UpdateLayout();
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
private void AttachCollection(IEnumerable<ICalendarItem> events)
|
//private void AttachCollection(IEnumerable<ICalendarItem> events)
|
||||||
{
|
//{
|
||||||
if (events is INotifyCollectionChanged collection)
|
// if (events is INotifyCollectionChanged collection)
|
||||||
{
|
// {
|
||||||
collection.CollectionChanged += EventCollectionChanged;
|
// // var t = new Grid();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DetachCollection(IEnumerable<ICalendarItem> events)
|
// collection.CollectionChanged += EventCollectionChanged;
|
||||||
{
|
// }
|
||||||
if (events is INotifyCollectionChanged collection)
|
//}
|
||||||
{
|
|
||||||
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.
|
||||||
private void EventCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => ResetMeasurements();
|
private void EventCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => ResetMeasurements();
|
||||||
|
|
||||||
private double GetChildTopMargin(DateTimeOffset childStart, double availableHeight)
|
private double GetChildTopMargin(ICalendarItem calendarItemViewModel, double availableHeight)
|
||||||
{
|
{
|
||||||
|
var childStart = calendarItemViewModel.StartTime;
|
||||||
|
|
||||||
double totalMinutes = 1440;
|
double totalMinutes = 1440;
|
||||||
double minutesFromStart = (childStart - DayModel.RepresentingDate).TotalMinutes;
|
double minutesFromStart = (childStart - childStart.DateTime.Date).TotalMinutes;
|
||||||
return (minutesFromStart / totalMinutes) * availableHeight;
|
return (minutesFromStart / totalMinutes) * availableHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +98,7 @@ namespace Wino.Calendar.Controls
|
|||||||
private double GetChildHeight(DateTimeOffset childStart, DateTimeOffset childEnd)
|
private double GetChildHeight(DateTimeOffset childStart, DateTimeOffset childEnd)
|
||||||
{
|
{
|
||||||
double totalMinutes = 1440;
|
double totalMinutes = 1440;
|
||||||
double availableHeight = DayModel.CalendarRenderOptions.CalendarSettings.HourHeight * 24;
|
double availableHeight = HourHeight * 24;
|
||||||
double childDuration = (childEnd - childStart).TotalMinutes;
|
double childDuration = (childEnd - childStart).TotalMinutes;
|
||||||
return (childDuration / totalMinutes) * availableHeight;
|
return (childDuration / totalMinutes) * availableHeight;
|
||||||
}
|
}
|
||||||
@@ -112,31 +117,30 @@ namespace Wino.Calendar.Controls
|
|||||||
double availableHeight = finalSize.Height;
|
double availableHeight = finalSize.Height;
|
||||||
double availableWidth = finalSize.Width;
|
double availableWidth = finalSize.Width;
|
||||||
|
|
||||||
var calendarControls = Children.Cast<CalendarItemControl>();
|
var calendarControls = Children.Cast<ContentPresenter>();
|
||||||
|
|
||||||
// We need to exclude all-day events from the layout algorithm.
|
if (!calendarControls.Any()) return base.ArrangeOverride(finalSize);
|
||||||
// All-day events are displayed in a separate panel.
|
|
||||||
|
|
||||||
calendarControls = calendarControls.Where(x => x.Item.DurationInMinutes != 1440);
|
if (_measurements.Count == 0 && calendarControls.Any())
|
||||||
|
|
||||||
if (_measurements.Count == 0 && DayModel.EventsCollection.Count > 0)
|
|
||||||
{
|
{
|
||||||
// We keep track of this collection when event is added/removed/reset etc.
|
// We keep track of this collection when event is added/removed/reset etc.
|
||||||
// So if the collection is empty, we must fill it up again for proper calculations.
|
// So if the collection is empty, we must fill it up again for proper calculations.
|
||||||
|
|
||||||
LayoutEvents(DayModel.EventsCollection);
|
var events = calendarControls.Select(a => a.Content as CalendarItemViewModel);
|
||||||
|
|
||||||
|
LayoutEvents(events);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var child in calendarControls)
|
foreach (var control in calendarControls)
|
||||||
{
|
{
|
||||||
// We can't arrange this child. It doesn't have a valid ICalendarItem or measurement.
|
// We can't arrange this child. It doesn't have a valid ICalendarItem or measurement.
|
||||||
if (child.Item == null || !_measurements.ContainsKey(child.Item.Id)) continue;
|
if (!(control.Content is ICalendarItem child) || !_measurements.ContainsKey(child.Id)) continue;
|
||||||
|
|
||||||
var childMeasurement = _measurements[child.Item.Id];
|
var childMeasurement = _measurements[child.Id];
|
||||||
|
|
||||||
double childHeight = Math.Max(0, GetChildHeight(child.Item.StartTime, child.Item.StartTime.AddMinutes(child.Item.DurationInMinutes)));
|
double childHeight = Math.Max(0, GetChildHeight(child.StartTime, child.StartTime.AddMinutes(child.DurationInMinutes)));
|
||||||
double childWidth = Math.Max(0, GetChildWidth(childMeasurement, finalSize.Width));
|
double childWidth = Math.Max(0, GetChildWidth(childMeasurement, finalSize.Width));
|
||||||
double childTop = Math.Max(0, GetChildTopMargin(child.Item.StartTime, availableHeight));
|
double childTop = Math.Max(0, GetChildTopMargin(child, availableHeight));
|
||||||
double childLeft = Math.Max(0, GetChildLeftMargin(childMeasurement, availableWidth));
|
double childLeft = Math.Max(0, GetChildLeftMargin(childMeasurement, availableWidth));
|
||||||
|
|
||||||
bool isHorizontallyLastItem = childMeasurement.Right == 1;
|
bool isHorizontallyLastItem = childMeasurement.Right == 1;
|
||||||
@@ -147,11 +151,11 @@ namespace Wino.Calendar.Controls
|
|||||||
|
|
||||||
if (childWidth < 0) childWidth = 1;
|
if (childWidth < 0) childWidth = 1;
|
||||||
|
|
||||||
child.Measure(new Size(childWidth, childHeight));
|
control.Measure(new Size(childWidth, childHeight));
|
||||||
|
|
||||||
var arrangementRect = new Rect(childLeft + EventItemMargin.Left, childTop + EventItemMargin.Top, Math.Max(childWidth - extraRightMargin, 1), childHeight);
|
var arrangementRect = new Rect(childLeft + EventItemMargin.Left, childTop + EventItemMargin.Top, Math.Max(childWidth - extraRightMargin, 1), childHeight);
|
||||||
|
|
||||||
child.Arrange(arrangementRect);
|
control.Arrange(arrangementRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalSize;
|
return finalSize;
|
||||||
@@ -179,8 +183,6 @@ namespace Wino.Calendar.Controls
|
|||||||
|
|
||||||
foreach (var ev in events.OrderBy(ev => ev.Period.Start).ThenBy(ev => ev.Period.End))
|
foreach (var ev in events.OrderBy(ev => ev.Period.Start).ThenBy(ev => ev.Period.End))
|
||||||
{
|
{
|
||||||
if (ev.Period.Duration.TotalMinutes == 1440) continue;
|
|
||||||
|
|
||||||
if (ev.Period.Start >= lastEventEnding)
|
if (ev.Period.Start >= lastEventEnding)
|
||||||
{
|
{
|
||||||
PackEvents(columns);
|
PackEvents(columns);
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
<ResourceDictionary
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:controls="using:Wino.Calendar.Controls">
|
|
||||||
|
|
||||||
<!-- Calendar day items. -->
|
|
||||||
<Style TargetType="controls:CalendarDayItemsControl">
|
|
||||||
<Style.Setters>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="controls:CalendarDayItemsControl">
|
|
||||||
<controls:WinoCalendarPanel
|
|
||||||
x:Name="PART_CalendarPanel"
|
|
||||||
DayModel="{TemplateBinding DayModel}"
|
|
||||||
EventItemMargin="0" />
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style.Setters>
|
|
||||||
</Style>
|
|
||||||
</ResourceDictionary>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<ResourceDictionary
|
|
||||||
x:Class="Wino.Calendar.Styles.CalendarItemControlResources"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:controls="using:Wino.Calendar.Controls">
|
|
||||||
|
|
||||||
<!-- CalendarItemControl -->
|
|
||||||
<Style TargetType="controls:CalendarItemControl">
|
|
||||||
<Style.Setters>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="controls:CalendarItemControl">
|
|
||||||
<Grid
|
|
||||||
Margin="1,1,1,1"
|
|
||||||
Background="#cf2b36"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
CornerRadius="3">
|
|
||||||
<TextBlock
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Bind Item.Title, Mode=OneWay}"
|
|
||||||
TextWrapping="WrapWholeWords" />
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style.Setters>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
</ResourceDictionary>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using Windows.UI.Xaml;
|
|
||||||
|
|
||||||
namespace Wino.Calendar.Styles
|
|
||||||
{
|
|
||||||
public sealed partial class CalendarItemControlResources : ResourceDictionary
|
|
||||||
{
|
|
||||||
public CalendarItemControlResources()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
<ResourceDictionary
|
|
||||||
x:Class="Wino.Calendar.Styles.DayColumnControlResources"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:controls="using:Wino.Calendar.Controls"
|
|
||||||
xmlns:data="using:Wino.Calendar.ViewModels.Data"
|
|
||||||
xmlns:interfaces="using:Wino.Core.Domain.Interfaces"
|
|
||||||
xmlns:local="using:Wino.Calendar.Styles">
|
|
||||||
<!-- Top column header DayColumnControl -->
|
|
||||||
<Style TargetType="controls:DayColumnControl">
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="controls:DayColumnControl">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="25" />
|
|
||||||
<RowDefinition Height="7" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- Name of the day. Monday, Tuesday etc. at the top. -->
|
|
||||||
<TextBlock
|
|
||||||
x:Name="PART_ColumnHeaderText"
|
|
||||||
Margin="8,0,0,0"
|
|
||||||
FontSize="16"
|
|
||||||
TextTrimming="CharacterEllipsis" />
|
|
||||||
|
|
||||||
<Grid
|
|
||||||
Grid.Row="2"
|
|
||||||
Grid.RowSpan="2"
|
|
||||||
BorderBrush="{ThemeResource CalendarSeperatorBrush}"
|
|
||||||
BorderThickness="1,1,0,1" />
|
|
||||||
|
|
||||||
<!-- Border for today indication. -->
|
|
||||||
<Border
|
|
||||||
x:Name="PART_IsTodayBorder"
|
|
||||||
Grid.Row="1"
|
|
||||||
Height="5"
|
|
||||||
Margin="2,0,2,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Background="{ThemeResource SystemAccentColor}"
|
|
||||||
CornerRadius="2"
|
|
||||||
Visibility="Collapsed" />
|
|
||||||
|
|
||||||
<!-- Place where full day events go. -->
|
|
||||||
<Grid
|
|
||||||
x:Name="PART_DayDataAreaGrid"
|
|
||||||
Grid.Row="2"
|
|
||||||
Padding="6"
|
|
||||||
BorderBrush="{ThemeResource CalendarSeperatorBrush}">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- Day number -->
|
|
||||||
<TextBlock x:Name="PART_HeaderDateDayText" FontSize="17" />
|
|
||||||
|
|
||||||
<!-- Extras -->
|
|
||||||
<StackPanel Grid.Column="1" HorizontalAlignment="Right" />
|
|
||||||
|
|
||||||
<!-- All-Day Events -->
|
|
||||||
<controls:AllDayItemsControl
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.ColumnSpan="2"
|
|
||||||
AllDayEvents="{Binding EventsCollection.AllDayEvents}">
|
|
||||||
<controls:AllDayItemsControl.AllDayEventTemplate>
|
|
||||||
<!-- All-Day Event template -->
|
|
||||||
<DataTemplate x:DataType="interfaces:ICalendarItem">
|
|
||||||
<TextBlock Text="{x:Bind Title}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</controls:AllDayItemsControl.AllDayEventTemplate>
|
|
||||||
</controls:AllDayItemsControl>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
|
||||||
<VisualStateGroup x:Name="TodayOrNotStates">
|
|
||||||
<VisualState x:Name="NotTodayState" />
|
|
||||||
<VisualState x:Name="TodayState">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Target="PART_IsTodayBorder.Visibility" Value="Visible" />
|
|
||||||
<Setter Target="PART_HeaderDateDayText.Foreground" Value="{ThemeResource SystemAccentColor}" />
|
|
||||||
<Setter Target="PART_HeaderDateDayText.FontWeight" Value="Semibold" />
|
|
||||||
<Setter Target="PART_ColumnHeaderText.FontWeight" Value="Semibold" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateManager.VisualStateGroups>
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
|
|
||||||
</ResourceDictionary>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using Windows.UI.Xaml;
|
|
||||||
|
|
||||||
namespace Wino.Calendar.Styles
|
|
||||||
{
|
|
||||||
partial class DayColumnControlResources : ResourceDictionary
|
|
||||||
{
|
|
||||||
public DayColumnControlResources()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,11 +4,27 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="using:Wino.Calendar.Controls"
|
xmlns:controls="using:Wino.Calendar.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:data="using:Wino.Calendar.ViewModels.Data"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:models="using:Wino.Core.Domain.Models.Calendar"
|
xmlns:models="using:Wino.Core.Domain.Models.Calendar"
|
||||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||||
xmlns:toolkitControls="using:CommunityToolkit.WinUI.Controls">
|
xmlns:toolkitControls="using:CommunityToolkit.WinUI.Controls">
|
||||||
|
|
||||||
|
<!-- Default Calendar Item View Model Template -->
|
||||||
|
<DataTemplate x:Key="CalendarItemViewModelItemTemplate" x:DataType="data:CalendarItemViewModel">
|
||||||
|
<Grid Background="Red" CornerRadius="4">
|
||||||
|
<TextBlock
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Text="{x:Bind CalendarItem.Title}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
|
<!-- All-Day Event template -->
|
||||||
|
<DataTemplate x:Key="AllDayEventItemTemplate" x:DataType="data:CalendarItemViewModel">
|
||||||
|
<TextBlock Text="{x:Bind Title}" />
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
<!-- 08:00 or 8 AM/PM on the left etc. -->
|
<!-- 08:00 or 8 AM/PM on the left etc. -->
|
||||||
<DataTemplate x:Key="DayCalendarHourHeaderTemplate" x:DataType="models:DayHeaderRenderModel">
|
<DataTemplate x:Key="DayCalendarHourHeaderTemplate" x:DataType="models:DayHeaderRenderModel">
|
||||||
<Grid Height="{x:Bind HourHeight}">
|
<Grid Height="{x:Bind HourHeight}">
|
||||||
@@ -21,7 +37,13 @@
|
|||||||
|
|
||||||
<!-- Vertical panel that renders items on canvas. -->
|
<!-- Vertical panel that renders items on canvas. -->
|
||||||
<DataTemplate x:Key="DayCalendarItemVerticalRenderTemplate" x:DataType="models:CalendarDayModel">
|
<DataTemplate x:Key="DayCalendarItemVerticalRenderTemplate" x:DataType="models:CalendarDayModel">
|
||||||
<controls:CalendarDayItemsControl DayModel="{x:Bind}" />
|
<ItemsControl ItemTemplate="{StaticResource CalendarItemViewModelItemTemplate}" ItemsSource="{x:Bind EventsCollection.RegularEvents}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<controls:WinoCalendarPanel HourHeight="{Binding Path=CalendarRenderOptions.CalendarSettings.HourHeight}" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
</ItemsControl>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<!-- Equally distributed days of week representation in FlipView. -->
|
<!-- Equally distributed days of week representation in FlipView. -->
|
||||||
@@ -103,7 +125,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<!-- Default style for WinoCalendarControl -->
|
<!-- Default style for WinoCalendarControl -->
|
||||||
<Style TargetType="controls:WinoCalendarControl">
|
<Style TargetType="controls:WinoCalendarControl">
|
||||||
<Style.Setters>
|
<Style.Setters>
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
@@ -125,8 +147,94 @@
|
|||||||
</Style.Setters>
|
</Style.Setters>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<!-- Teaching tip dialog sizing. -->
|
<!-- Default style for DayColumnControl -->
|
||||||
|
<Style TargetType="controls:DayColumnControl">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="controls:DayColumnControl">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="25" />
|
||||||
|
<RowDefinition Height="7" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- Name of the day. Monday, Tuesday etc. at the top. -->
|
||||||
|
<TextBlock
|
||||||
|
x:Name="PART_ColumnHeaderText"
|
||||||
|
Margin="8,0,0,0"
|
||||||
|
FontSize="16"
|
||||||
|
TextTrimming="CharacterEllipsis" />
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.RowSpan="2"
|
||||||
|
BorderBrush="{ThemeResource CalendarSeperatorBrush}"
|
||||||
|
BorderThickness="1,1,0,1" />
|
||||||
|
|
||||||
|
<!-- Border for today indication. -->
|
||||||
|
<Border
|
||||||
|
x:Name="PART_IsTodayBorder"
|
||||||
|
Grid.Row="1"
|
||||||
|
Height="5"
|
||||||
|
Margin="2,0,2,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Background="{ThemeResource SystemAccentColor}"
|
||||||
|
CornerRadius="2"
|
||||||
|
Visibility="Collapsed" />
|
||||||
|
|
||||||
|
<!-- Place where full day events go. -->
|
||||||
|
<Grid
|
||||||
|
x:Name="PART_DayDataAreaGrid"
|
||||||
|
Grid.Row="2"
|
||||||
|
Padding="6"
|
||||||
|
BorderBrush="{ThemeResource CalendarSeperatorBrush}">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- Day number -->
|
||||||
|
<TextBlock x:Name="PART_HeaderDateDayText" FontSize="17" />
|
||||||
|
|
||||||
|
<!-- Extras -->
|
||||||
|
<StackPanel Grid.Column="1" HorizontalAlignment="Right" />
|
||||||
|
|
||||||
|
<!-- All-Day Events -->
|
||||||
|
<controls:AllDayItemsControl
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
AllDayEventTemplate="{StaticResource AllDayEventItemTemplate}"
|
||||||
|
EventCollection="{Binding EventsCollection}"
|
||||||
|
RegularEventItemTemplate="{StaticResource CalendarItemViewModelItemTemplate}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<VisualStateManager.VisualStateGroups>
|
||||||
|
<VisualStateGroup x:Name="TodayOrNotStates">
|
||||||
|
<VisualState x:Name="NotTodayState" />
|
||||||
|
<VisualState x:Name="TodayState">
|
||||||
|
<VisualState.Setters>
|
||||||
|
<Setter Target="PART_IsTodayBorder.Visibility" Value="Visible" />
|
||||||
|
<Setter Target="PART_HeaderDateDayText.Foreground" Value="{ThemeResource SystemAccentColor}" />
|
||||||
|
<Setter Target="PART_HeaderDateDayText.FontWeight" Value="Semibold" />
|
||||||
|
<Setter Target="PART_ColumnHeaderText.FontWeight" Value="Semibold" />
|
||||||
|
</VisualState.Setters>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
</VisualStateManager.VisualStateGroups>
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Teaching tip dialog sizing. -->
|
||||||
<x:Double x:Key="TeachingTipMinWidth">1000</x:Double>
|
<x:Double x:Key="TeachingTipMinWidth">1000</x:Double>
|
||||||
<x:Double x:Key="TeachingTipMaxWidth">1000</x:Double>
|
<x:Double x:Key="TeachingTipMaxWidth">1000</x:Double>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
xmlns:controls="using:Wino.Calendar.Controls">
|
xmlns:controls="using:Wino.Calendar.Controls">
|
||||||
|
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="CalendarRenderStyles.xaml" />
|
<ResourceDictionary Source="CalendarThemeResources.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<Style TargetType="controls:WinoCalendarView">
|
<Style TargetType="controls:WinoCalendarView">
|
||||||
|
|||||||
@@ -139,8 +139,6 @@
|
|||||||
<Compile Include="Controls\AllDayItemsControl.xaml.cs">
|
<Compile Include="Controls\AllDayItemsControl.xaml.cs">
|
||||||
<DependentUpon>AllDayItemsControl.xaml</DependentUpon>
|
<DependentUpon>AllDayItemsControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Controls\CalendarDayItemsControl.cs" />
|
|
||||||
<Compile Include="Controls\CalendarItemControl.cs" />
|
|
||||||
<Compile Include="Controls\CustomCalendarFlipView.cs" />
|
<Compile Include="Controls\CustomCalendarFlipView.cs" />
|
||||||
<Compile Include="Controls\DayColumnControl.cs" />
|
<Compile Include="Controls\DayColumnControl.cs" />
|
||||||
<Compile Include="Controls\DayHeaderControl.cs" />
|
<Compile Include="Controls\DayHeaderControl.cs" />
|
||||||
@@ -161,10 +159,6 @@
|
|||||||
<Compile Include="Services\NavigationService.cs" />
|
<Compile Include="Services\NavigationService.cs" />
|
||||||
<Compile Include="Services\ProviderService.cs" />
|
<Compile Include="Services\ProviderService.cs" />
|
||||||
<Compile Include="Services\SettingsBuilderService.cs" />
|
<Compile Include="Services\SettingsBuilderService.cs" />
|
||||||
<Compile Include="Styles\CalendarItemControlResources.xaml.cs" />
|
|
||||||
<Compile Include="Styles\DayColumnControlResources.xaml.cs">
|
|
||||||
<DependentUpon>DayColumnControlResources.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Styles\WinoCalendarResources.xaml.cs" />
|
<Compile Include="Styles\WinoCalendarResources.xaml.cs" />
|
||||||
<Compile Include="Views\Abstract\AccountManagementPageAbstract.cs" />
|
<Compile Include="Views\Abstract\AccountManagementPageAbstract.cs" />
|
||||||
<Compile Include="Views\Abstract\AppShellAbstract.cs" />
|
<Compile Include="Views\Abstract\AppShellAbstract.cs" />
|
||||||
@@ -260,22 +254,10 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Styles\CalendarDayItemsControl.xaml">
|
<Page Include="Styles\CalendarThemeResources.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Styles\CalendarItemControlResources.xaml">
|
|
||||||
<Generator>MSBuild:Compile</Generator>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</Page>
|
|
||||||
<Page Include="Styles\CalendarRenderStyles.xaml">
|
|
||||||
<Generator>MSBuild:Compile</Generator>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</Page>
|
|
||||||
<Page Include="Styles\DayColumnControlResources.xaml">
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
<Generator>MSBuild:Compile</Generator>
|
|
||||||
</Page>
|
|
||||||
<Page Include="Styles\DayHeaderControl.xaml">
|
<Page Include="Styles\DayHeaderControl.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
@@ -368,4 +350,4 @@
|
|||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
</Target>
|
</Target>
|
||||||
-->
|
-->
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,36 +1,87 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Collections
|
namespace Wino.Core.Domain.Collections
|
||||||
{
|
{
|
||||||
// TODO: Could be read-only collection in the MVVM package.
|
public class CalendarEventCollection
|
||||||
public class CalendarEventCollection : ObservableRangeCollection<ICalendarItem>
|
|
||||||
{
|
{
|
||||||
public ObservableCollection<ICalendarItem> AllDayEvents { get; } = new ObservableCollection<ICalendarItem>();
|
public event EventHandler<ICalendarItem> CalendarItemAdded;
|
||||||
public new void Add(ICalendarItem calendarItem)
|
public event EventHandler<ICalendarItem> CalendarItemRemoved;
|
||||||
|
|
||||||
|
public event EventHandler<List<ICalendarItem>> CalendarItemRangeAdded;
|
||||||
|
public event EventHandler<List<ICalendarItem>> CalendarItemRangeRemoved;
|
||||||
|
|
||||||
|
private ObservableRangeCollection<ICalendarItem> _internalRegularEvents = [];
|
||||||
|
private ObservableRangeCollection<ICalendarItem> _internalAllDayEvents = [];
|
||||||
|
|
||||||
|
public ReadOnlyObservableCollection<ICalendarItem> RegularEvents { get; }
|
||||||
|
public ReadOnlyObservableCollection<ICalendarItem> AllDayEvents { get; }
|
||||||
|
|
||||||
|
public CalendarEventCollection()
|
||||||
|
{
|
||||||
|
RegularEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalRegularEvents);
|
||||||
|
AllDayEvents = new ReadOnlyObservableCollection<ICalendarItem>(_internalAllDayEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCalendarItemRange(IEnumerable<ICalendarItem> calendarItems, bool reportChange = true)
|
||||||
|
{
|
||||||
|
foreach (var calendarItem in calendarItems)
|
||||||
|
{
|
||||||
|
AddCalendarItem(calendarItem, reportChange: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CalendarItemRangeAdded?.Invoke(this, new List<ICalendarItem>(calendarItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveCalendarItemRange(IEnumerable<ICalendarItem> calendarItems, bool reportChange = true)
|
||||||
|
{
|
||||||
|
foreach (var calendarItem in calendarItems)
|
||||||
|
{
|
||||||
|
RemoveCalendarItem(calendarItem, reportChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
CalendarItemRangeRemoved?.Invoke(this, new List<ICalendarItem>(calendarItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCalendarItem(ICalendarItem calendarItem, bool reportChange = true)
|
||||||
{
|
{
|
||||||
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));
|
||||||
|
|
||||||
base.Add(calendarItem);
|
|
||||||
|
|
||||||
if (calendarItem.Period.Duration.TotalMinutes == 1440)
|
if (calendarItem.Period.Duration.TotalMinutes == 1440)
|
||||||
{
|
{
|
||||||
AllDayEvents.Add(calendarItem);
|
_internalAllDayEvents.Add(calendarItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_internalRegularEvents.Add(calendarItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reportChange)
|
||||||
|
{
|
||||||
|
CalendarItemAdded?.Invoke(this, calendarItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public new void Remove(ICalendarItem calendarItem)
|
public void RemoveCalendarItem(ICalendarItem calendarItem, bool reportChange = true)
|
||||||
{
|
{
|
||||||
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));
|
||||||
|
|
||||||
base.Remove(calendarItem);
|
|
||||||
|
|
||||||
if (calendarItem.Period.Duration.TotalMinutes == 1440)
|
if (calendarItem.Period.Duration.TotalMinutes == 1440)
|
||||||
{
|
{
|
||||||
AllDayEvents.Remove(calendarItem);
|
_internalAllDayEvents.Remove(calendarItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_internalRegularEvents.Remove(calendarItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reportChange)
|
||||||
|
{
|
||||||
|
CalendarItemRemoved?.Invoke(this, calendarItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
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;
|
||||||
@@ -7,13 +8,15 @@ namespace Wino.Core.Domain.Models.Calendar
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a range of days in the calendar.
|
/// Represents a range of days in the calendar.
|
||||||
/// Usually it's used for day or week, but supports custom ranges.
|
/// Corresponds to 1 view of the FlipView in CalendarPage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DayRangeRenderModel
|
public class DayRangeRenderModel
|
||||||
{
|
{
|
||||||
|
public event EventHandler<CalendarDayModel> CalendarDayEventCollectionUpdated;
|
||||||
|
|
||||||
public ITimePeriod Period { get; }
|
public ITimePeriod Period { get; }
|
||||||
public List<CalendarDayModel> CalendarDays { get; } = new List<CalendarDayModel>();
|
public List<CalendarDayModel> CalendarDays { get; } = [];
|
||||||
public List<DayHeaderRenderModel> DayHeaders { get; } = new List<DayHeaderRenderModel>();
|
public List<DayHeaderRenderModel> DayHeaders { get; } = [];
|
||||||
public CalendarRenderOptions CalendarRenderOptions { get; }
|
public CalendarRenderOptions CalendarRenderOptions { get; }
|
||||||
|
|
||||||
public DayRangeRenderModel(CalendarRenderOptions calendarRenderOptions)
|
public DayRangeRenderModel(CalendarRenderOptions calendarRenderOptions)
|
||||||
@@ -46,5 +49,39 @@ namespace Wino.Core.Domain.Models.Calendar
|
|||||||
DayHeaders.Add(new DayHeaderRenderModel(dayHeader, calendarRenderOptions.CalendarSettings.HourHeight));
|
DayHeaders.Add(new DayHeaderRenderModel(dayHeader, calendarRenderOptions.CalendarSettings.HourHeight));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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);
|
||||||
|
|
||||||
|
//private void CalendarItemRemoved(object sender, ICalendarItem e)
|
||||||
|
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
|
||||||
|
|
||||||
|
//private void CalendarItemAdded(object sender, ICalendarItem e)
|
||||||
|
// => CalendarDayEventCollectionUpdated?.Invoke(this, sender as CalendarDayModel);
|
||||||
|
|
||||||
|
//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;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user