Handling of multi-day events, new rendering etc.
This commit is contained in:
@@ -9,12 +9,47 @@
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:selectors="using:Wino.Calendar.Selectors"
|
||||
x:Name="AllDayControl"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<controls:CalendarItemControl
|
||||
<ItemsControl x:Name="EventItemsControl" ItemsSource="{x:Bind CalendarDayModel.EventsCollection.AllDayEvents, Mode=OneWay}">
|
||||
<ItemsControl.ItemTemplateSelector>
|
||||
<selectors:CustomAreaCalendarItemSelector>
|
||||
<selectors:CustomAreaCalendarItemSelector.AllDayTemplate>
|
||||
<DataTemplate x:DataType="data:CalendarItemViewModel">
|
||||
<controls:CalendarItemControl
|
||||
CalendarItem="{x:Bind}"
|
||||
DisplayingDate="{Binding CalendarDayModel, ElementName=AllDayControl}"
|
||||
IsCustomEventArea="True" />
|
||||
</DataTemplate>
|
||||
</selectors:CustomAreaCalendarItemSelector.AllDayTemplate>
|
||||
<selectors:CustomAreaCalendarItemSelector.MultiDayTemplate>
|
||||
<DataTemplate x:DataType="data:CalendarItemViewModel">
|
||||
<controls:CalendarItemControl
|
||||
CalendarItem="{x:Bind}"
|
||||
DisplayingDate="{Binding CalendarDayModel, ElementName=AllDayControl}"
|
||||
IsCustomEventArea="True" />
|
||||
</DataTemplate>
|
||||
</selectors:CustomAreaCalendarItemSelector.MultiDayTemplate>
|
||||
</selectors:CustomAreaCalendarItemSelector>
|
||||
</ItemsControl.ItemTemplateSelector>
|
||||
<ItemsControl.ItemContainerTransitions>
|
||||
<TransitionCollection>
|
||||
<AddDeleteThemeTransition />
|
||||
</TransitionCollection>
|
||||
</ItemsControl.ItemContainerTransitions>
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical" Spacing="2" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
|
||||
<!--<controls:CalendarItemControl
|
||||
x:Name="SingleAllDayEventHolder"
|
||||
CalendarItem="{x:Bind calendarHelpers:CalendarXamlHelpers.GetFirstAllDayEvent(EventCollection), Mode=OneWay}"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(EventCollection.AllDayEvents.Count), Mode=OneWay}" />
|
||||
@@ -53,6 +88,6 @@
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</VisualStateManager.VisualStateGroups>-->
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Wino.Core.Domain.Collections;
|
||||
using Wino.Core.Domain.Models.Calendar;
|
||||
|
||||
|
||||
namespace Wino.Calendar.Controls
|
||||
@@ -9,36 +9,12 @@ namespace Wino.Calendar.Controls
|
||||
{
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty EventCollectionProperty = DependencyProperty.Register(nameof(EventCollection), typeof(CalendarEventCollection), 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));
|
||||
public static readonly DependencyProperty CalendarDayModelProperty = DependencyProperty.Register(nameof(CalendarDayModel), typeof(CalendarDayModel), 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 CalendarDayModel CalendarDayModel
|
||||
{
|
||||
get { return (DataTemplate)GetValue(AllDayEventTemplateProperty); }
|
||||
set { SetValue(AllDayEventTemplateProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Item template for all-day events to display in summary view's Flyout.
|
||||
/// </summary>
|
||||
public DataTemplate RegularEventItemTemplate
|
||||
{
|
||||
get { return (DataTemplate)GetValue(RegularEventItemTemplateProperty); }
|
||||
set { SetValue(RegularEventItemTemplateProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whole collection of events to display.
|
||||
/// </summary>
|
||||
public CalendarEventCollection EventCollection
|
||||
{
|
||||
get { return (CalendarEventCollection)GetValue(EventCollectionProperty); }
|
||||
set { SetValue(EventCollectionProperty, value); }
|
||||
get { return (CalendarDayModel)GetValue(CalendarDayModelProperty); }
|
||||
set { SetValue(CalendarDayModelProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="Wino.Calendar.Controls.CalendarItemControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Wino.Core.UWP.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:local="using:Wino.Calendar.Controls"
|
||||
@@ -18,7 +19,13 @@
|
||||
CornerRadius="4"
|
||||
DoubleTapped="ControlDoubleTapped"
|
||||
RightTapped="ControlRightTapped"
|
||||
Tapped="ControlTapped">
|
||||
Tapped="ControlTapped"
|
||||
ToolTipService.ToolTip="{x:Bind CalendarItemTitle, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.ContextFlyout>
|
||||
<MenuFlyout Opened="ContextFlyoutOpened">
|
||||
<MenuFlyoutItem Text="as" />
|
||||
@@ -26,33 +33,49 @@
|
||||
<MenuFlyoutItem Text="as" />
|
||||
</MenuFlyout>
|
||||
</Grid.ContextFlyout>
|
||||
<Grid x:Name="MainBackground" Background="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(CalendarItem.AssignedCalendar.BackgroundColorHex), Mode=OneWay}" />
|
||||
|
||||
<Grid
|
||||
x:Name="MainBackground"
|
||||
Grid.ColumnSpan="2"
|
||||
Background="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(CalendarItem.AssignedCalendar.BackgroundColorHex), Mode=OneWay}" />
|
||||
|
||||
<Rectangle
|
||||
x:Name="MainBorder"
|
||||
Grid.ColumnSpan="2"
|
||||
Stroke="{ThemeResource CalendarItemBorderBrush}"
|
||||
StrokeThickness="0" />
|
||||
|
||||
<TextBlock
|
||||
x:Name="EventTitleTextblock"
|
||||
Margin="2,0"
|
||||
HorizontalAlignment="Center"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
CharacterSpacing="8"
|
||||
FontSize="13"
|
||||
Foreground="{x:Bind helpers:XamlHelpers.GetReadableTextColor(CalendarItem.AssignedCalendar.BackgroundColorHex), Mode=OneWay}"
|
||||
Text="{x:Bind CalendarItem.Title}"
|
||||
TextWrapping="Wrap" />
|
||||
HorizontalTextAlignment="Center"
|
||||
Text="{x:Bind CalendarItemTitle, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
|
||||
<!-- TODO: Event attributes -->
|
||||
<StackPanel
|
||||
x:Name="AttributeStack"
|
||||
Grid.Column="1"
|
||||
Margin="0,4,4,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Orientation="Horizontal">
|
||||
<PathIcon
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="F1 M 7.5 3.75 C 6.634114 3.75 5.82194 3.912762 5.063477 4.238281 C 4.305013 4.563803 3.642578 5.009766 3.076172 5.576172 C 2.509766 6.142578 2.063802 6.805014 1.738281 7.563477 C 1.41276 8.32194 1.25 9.134115 1.25 10 C 1.25 10.527344 1.318359 11.056315 1.455078 11.586914 C 1.591797 12.117514 1.79362 12.613933 2.060547 13.076172 C 2.099609 13.147787 2.150065 13.225912 2.211914 13.310547 C 2.273763 13.395183 2.333984 13.483073 2.392578 13.574219 C 2.451172 13.665365 2.501627 13.756511 2.543945 13.847656 C 2.586263 13.938803 2.607422 14.023438 2.607422 14.101562 C 2.607422 14.270834 2.545573 14.417318 2.421875 14.541016 C 2.298177 14.664714 2.151693 14.726562 1.982422 14.726562 C 1.871745 14.726562 1.778971 14.703776 1.704102 14.658203 C 1.629232 14.612631 1.55599 14.550781 1.484375 14.472656 C 1.24349 14.192709 1.030273 13.870443 0.844727 13.505859 C 0.65918 13.141276 0.504557 12.760417 0.380859 12.363281 C 0.257161 11.966146 0.16276 11.564128 0.097656 11.157227 C 0.032552 10.750326 0 10.364584 0 10 C 0 9.316406 0.089518 8.6556 0.268555 8.017578 C 0.447591 7.379558 0.69987 6.782227 1.025391 6.225586 C 1.350911 5.668945 1.741536 5.162761 2.197266 4.707031 C 2.652995 4.251303 3.157552 3.859051 3.710938 3.530273 C 4.264323 3.201498 4.861653 2.947592 5.50293 2.768555 C 6.144206 2.58952 6.809896 2.5 7.5 2.5 L 14.121094 2.5 L 12.685547 1.064453 C 12.561849 0.940756 12.5 0.794271 12.5 0.625 C 12.5 0.45573 12.561849 0.309246 12.685547 0.185547 C 12.809244 0.06185 12.955729 0 13.125 0 C 13.294271 0 13.440755 0.06185 13.564453 0.185547 L 16.064453 2.685547 C 16.18815 2.809246 16.25 2.95573 16.25 3.125 C 16.25 3.294271 16.18815 3.440756 16.064453 3.564453 L 13.564453 6.064453 C 13.440755 6.188151 13.294271 6.25 13.125 6.25 C 12.955729 6.25 12.809244 6.188151 12.685547 6.064453 C 12.561849 5.940756 12.5 5.794271 12.5 5.625 C 12.5 5.455729 12.561849 5.309245 12.685547 5.185547 L 14.121094 3.75 Z M 20 10 C 20 10.690104 19.91048 11.352539 19.731445 11.987305 C 19.552408 12.62207 19.300129 13.217773 18.974609 13.774414 C 18.649088 14.331055 18.258463 14.83724 17.802734 15.292969 C 17.347004 15.748698 16.842447 16.140951 16.289062 16.469727 C 15.735677 16.798502 15.138346 17.052408 14.49707 17.231445 C 13.855793 17.410482 13.190104 17.5 12.5 17.5 L 5.888672 17.5 L 7.314453 18.935547 C 7.43815 19.059244 7.5 19.205729 7.5 19.375 C 7.5 19.544271 7.43815 19.690756 7.314453 19.814453 C 7.190755 19.93815 7.044271 20 6.875 20 C 6.705729 20 6.559244 19.93815 6.435547 19.814453 L 3.935547 17.314453 C 3.811849 17.190756 3.75 17.044271 3.75 16.875 C 3.75 16.705729 3.811849 16.559244 3.935547 16.435547 L 6.435547 13.935547 C 6.559244 13.81185 6.705729 13.75 6.875 13.75 C 7.044271 13.75 7.190755 13.81185 7.314453 13.935547 C 7.43815 14.059245 7.5 14.205729 7.5 14.375 C 7.5 14.544271 7.43815 14.690756 7.314453 14.814453 L 5.888672 16.25 L 12.5 16.25 C 13.365885 16.25 14.178059 16.08724 14.936523 15.761719 C 15.694986 15.436198 16.357422 14.990234 16.923828 14.423828 C 17.490234 13.857422 17.936197 13.194987 18.261719 12.436523 C 18.587238 11.678061 18.75 10.865886 18.75 10 C 18.75 9.628906 18.723957 9.283854 18.671875 8.964844 C 18.619791 8.645834 18.541666 8.336589 18.4375 8.037109 C 18.333332 7.737631 18.204752 7.444662 18.051758 7.158203 C 17.898762 6.871746 17.721354 6.575521 17.519531 6.269531 C 17.473957 6.197917 17.441406 6.139323 17.421875 6.09375 C 17.402344 6.048178 17.392578 5.983074 17.392578 5.898438 C 17.392578 5.729168 17.452799 5.581056 17.573242 5.454102 C 17.693684 5.327149 17.841797 5.263673 18.017578 5.263672 C 18.128254 5.263673 18.221027 5.286459 18.295898 5.332031 C 18.370768 5.377604 18.44401 5.439453 18.515625 5.517578 C 18.75651 5.797527 18.969727 6.119793 19.155273 6.484375 C 19.34082 6.848959 19.495441 7.231445 19.619141 7.631836 C 19.742838 8.032227 19.837238 8.435873 19.902344 8.842773 C 19.967447 9.249675 20 9.635417 20 10 Z "
|
||||
Visibility="{x:Bind CalendarItem.IsRecurringEvent}" />
|
||||
<controls:WinoFontIcon
|
||||
FontSize="10"
|
||||
Foreground="{x:Bind helpers:XamlHelpers.GetReadableTextColor(CalendarItem.AssignedCalendar.BackgroundColorHex), Mode=OneWay}"
|
||||
Icon="CalendarEventRepeat"
|
||||
Visibility="{x:Bind CalendarItem.IsRecurringEvent, Mode=OneWay}" />
|
||||
|
||||
<controls:WinoFontIcon
|
||||
FontSize="16"
|
||||
Foreground="{x:Bind helpers:XamlHelpers.GetReadableTextColor(CalendarItem.AssignedCalendar.BackgroundColorHex), Mode=OneWay}"
|
||||
Icon="CalendarEventMuiltiDay"
|
||||
Visibility="{x:Bind CalendarItem.IsMultiDayEvent, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
@@ -78,7 +101,6 @@
|
||||
<Setter Target="MainBorder.StrokeThickness" Value="2" />
|
||||
<Setter Target="MainBorder.Stroke" Value="{ThemeResource CalendarItemDraggingBorderBrush}" />
|
||||
<Setter Target="MainBorder.StrokeDashArray" Value="2.5" />
|
||||
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
@@ -86,19 +108,35 @@
|
||||
<VisualState x:Name="RegularEvent" />
|
||||
<VisualState x:Name="AllDayEvent">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="MainGrid.MinHeight" Value="25" />
|
||||
<Setter Target="AttributeStack.VerticalAlignment" Value="Center" />
|
||||
<Setter Target="MainGrid.MinHeight" Value="30" />
|
||||
<Setter Target="MainBorder.StrokeThickness" Value="0.5" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="CustomAreaMultiDayEvent">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="MainBackground.Opacity" Value="1" />
|
||||
<Setter Target="MainBorder.StrokeThickness" Value="0.5" />
|
||||
<Setter Target="AttributeStack.Visibility" Value="Collapsed" />
|
||||
<Setter Target="MainGrid.MinHeight" Value="30" />
|
||||
<Setter Target="EventTitleTextblock.HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Target="EventTitleTextblock.HorizontalTextAlignment" Value="Left" />
|
||||
<Setter Target="EventTitleTextblock.Margin" Value="6,0" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="MultiDayEvent">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="MainBackground.Opacity" Value="0.6" />
|
||||
<Setter Target="MainGrid.CornerRadius" Value="0" />
|
||||
<Setter Target="MainBackground.Opacity" Value="0.2" />
|
||||
<Setter Target="MainGrid.IsHitTestVisible" Value="False" />
|
||||
<Setter Target="MainBorder.StrokeThickness" Value="0.5" />
|
||||
<Setter Target="AttributeStack.Visibility" Value="Collapsed" />
|
||||
<Setter Target="EventTitleTextblock.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
|
||||
@@ -1,15 +1,49 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using System.Diagnostics;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Itenso.TimePeriod;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Wino.Calendar.ViewModels.Data;
|
||||
using Wino.Calendar.ViewModels.Messages;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Models.Calendar;
|
||||
|
||||
namespace Wino.Calendar.Controls
|
||||
{
|
||||
public sealed partial class CalendarItemControl : UserControl
|
||||
{
|
||||
public bool IsAllDayMultiDayEvent { get; set; }
|
||||
|
||||
public static readonly DependencyProperty CalendarItemProperty = DependencyProperty.Register(nameof(CalendarItem), typeof(CalendarItemViewModel), typeof(CalendarItemControl), new PropertyMetadata(null, new PropertyChangedCallback(OnCalendarItemChanged)));
|
||||
public static readonly DependencyProperty IsDraggingProperty = DependencyProperty.Register(nameof(IsDragging), typeof(bool), typeof(CalendarItemControl), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsCustomEventAreaProperty = DependencyProperty.Register(nameof(IsCustomEventArea), typeof(bool), typeof(CalendarItemControl), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty CalendarItemTitleProperty = DependencyProperty.Register(nameof(CalendarItemTitle), typeof(string), typeof(CalendarItemControl), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty DisplayingDateProperty = DependencyProperty.Register(nameof(DisplayingDate), typeof(CalendarDayModel), typeof(CalendarItemControl), new PropertyMetadata(null, new PropertyChangedCallback(OnDisplayDateChanged)));
|
||||
|
||||
/// <summary>
|
||||
/// Whether the control is displaying as regular event or all-multi day area in the day control.
|
||||
/// </summary>
|
||||
public bool IsCustomEventArea
|
||||
{
|
||||
get { return (bool)GetValue(IsCustomEventAreaProperty); }
|
||||
set { SetValue(IsCustomEventAreaProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Day that the calendar item is rendered at.
|
||||
/// It's needed for title manipulation and some other adjustments later on.
|
||||
/// </summary>
|
||||
public CalendarDayModel DisplayingDate
|
||||
{
|
||||
get { return (CalendarDayModel)GetValue(DisplayingDateProperty); }
|
||||
set { SetValue(DisplayingDateProperty, value); }
|
||||
}
|
||||
|
||||
public string CalendarItemTitle
|
||||
{
|
||||
get { return (string)GetValue(CalendarItemTitleProperty); }
|
||||
set { SetValue(CalendarItemTitleProperty, value); }
|
||||
}
|
||||
|
||||
public CalendarItemViewModel CalendarItem
|
||||
{
|
||||
@@ -28,14 +62,77 @@ namespace Wino.Calendar.Controls
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private static void OnDisplayDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is CalendarItemControl control)
|
||||
{
|
||||
control.UpdateControlVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnCalendarItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is CalendarItemControl control)
|
||||
{
|
||||
control.UpdateVisualStates();
|
||||
control.UpdateControlVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateControlVisuals()
|
||||
{
|
||||
// Depending on the calendar item's duration and attributes, we might need to change the display title.
|
||||
// 1. Multi-Day events should display the start date and end date.
|
||||
// 2. Multi-Day events that occupy the whole day just shows 'all day'.
|
||||
// 3. Other events should display the title.
|
||||
|
||||
if (CalendarItem == null) return;
|
||||
if (DisplayingDate == null) return;
|
||||
|
||||
if (CalendarItem.IsMultiDayEvent)
|
||||
{
|
||||
// Multi day events are divided into 3 categories:
|
||||
// 1. All day events
|
||||
// 2. Events that started after the period.
|
||||
// 3. Events that started before the period and finishes within the period.
|
||||
|
||||
var periodRelation = CalendarItem.Period.GetRelation(DisplayingDate.Period);
|
||||
|
||||
if (periodRelation == Itenso.TimePeriod.PeriodRelation.StartInside ||
|
||||
periodRelation == PeriodRelation.EnclosingStartTouching)
|
||||
{
|
||||
// hour -> title
|
||||
CalendarItemTitle = $"{DisplayingDate.CalendarRenderOptions.CalendarSettings.GetTimeString(CalendarItem.StartDate.TimeOfDay)} -> {CalendarItem.Title}";
|
||||
}
|
||||
else if (
|
||||
periodRelation == PeriodRelation.EndInside ||
|
||||
periodRelation == PeriodRelation.EnclosingEndTouching)
|
||||
{
|
||||
// title <- hour
|
||||
CalendarItemTitle = $"{CalendarItem.Title} <- {DisplayingDate.CalendarRenderOptions.CalendarSettings.GetTimeString(CalendarItem.EndDate.TimeOfDay)}";
|
||||
}
|
||||
else if (periodRelation == PeriodRelation.Enclosing)
|
||||
{
|
||||
// This event goes all day and it's multi-day.
|
||||
// Item must be hidden in the calendar but displayed on the custom area at the top.
|
||||
|
||||
CalendarItemTitle = $"{Translator.CalendarItemAllDay} {CalendarItem.Title}";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not expected, but there it is.
|
||||
CalendarItemTitle = CalendarItem.Title;
|
||||
}
|
||||
|
||||
Debug.WriteLine($"{CalendarItem.Title} Period relation with {DisplayingDate.Period.ToString()}: {periodRelation}");
|
||||
}
|
||||
else
|
||||
{
|
||||
CalendarItemTitle = CalendarItem.Title;
|
||||
}
|
||||
|
||||
UpdateVisualStates();
|
||||
}
|
||||
|
||||
private void UpdateVisualStates()
|
||||
{
|
||||
if (CalendarItem == null) return;
|
||||
@@ -46,7 +143,15 @@ namespace Wino.Calendar.Controls
|
||||
}
|
||||
else if (CalendarItem.IsMultiDayEvent)
|
||||
{
|
||||
VisualStateManager.GoToState(this, "MultiDayEvent", true);
|
||||
if (IsCustomEventArea)
|
||||
{
|
||||
VisualStateManager.GoToState(this, "CustomAreaMultiDayEvent", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide it.
|
||||
VisualStateManager.GoToState(this, "MultiDayEvent", true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -11,12 +11,15 @@ namespace Wino.Calendar.Controls
|
||||
private const string PART_IsTodayBorder = nameof(PART_IsTodayBorder);
|
||||
private const string PART_ColumnHeaderText = nameof(PART_ColumnHeaderText);
|
||||
|
||||
private const string PART_AllDayItemsControl = nameof(PART_AllDayItemsControl);
|
||||
|
||||
private const string TodayState = nameof(TodayState);
|
||||
private const string NotTodayState = nameof(NotTodayState);
|
||||
|
||||
private TextBlock HeaderDateDayText;
|
||||
private TextBlock ColumnHeaderText;
|
||||
private Border IsTodayBorder;
|
||||
private AllDayItemsControl AllDayItemsControl;
|
||||
|
||||
public CalendarDayModel DayModel
|
||||
{
|
||||
@@ -38,6 +41,7 @@ namespace Wino.Calendar.Controls
|
||||
HeaderDateDayText = GetTemplateChild(PART_HeaderDateDayText) as TextBlock;
|
||||
ColumnHeaderText = GetTemplateChild(PART_ColumnHeaderText) as TextBlock;
|
||||
IsTodayBorder = GetTemplateChild(PART_IsTodayBorder) as Border;
|
||||
AllDayItemsControl = GetTemplateChild(PART_AllDayItemsControl) as AllDayItemsControl;
|
||||
|
||||
UpdateValues();
|
||||
}
|
||||
@@ -57,6 +61,8 @@ namespace Wino.Calendar.Controls
|
||||
HeaderDateDayText.Text = DayModel.RepresentingDate.Day.ToString();
|
||||
ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo);
|
||||
|
||||
AllDayItemsControl.CalendarDayModel = DayModel;
|
||||
|
||||
bool isToday = DayModel.RepresentingDate.Date == DateTime.Now.Date;
|
||||
|
||||
VisualStateManager.GoToState(this, isToday ? TodayState : NotTodayState, false);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Itenso.TimePeriod;
|
||||
@@ -19,13 +19,12 @@ namespace Wino.Calendar.Controls
|
||||
private const double LastItemRightExtraMargin = 12d;
|
||||
|
||||
// Store each ICalendarItem measurements by their Id.
|
||||
private readonly Dictionary<Guid, CalendarItemMeasurement> _measurements = new Dictionary<Guid, CalendarItemMeasurement>();
|
||||
private readonly Dictionary<ICalendarItem, CalendarItemMeasurement> _measurements = new Dictionary<ICalendarItem, 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 HourHeightProperty = DependencyProperty.Register(nameof(HourHeight), typeof(double), typeof(WinoCalendarPanel), new PropertyMetadata(0d));
|
||||
public static readonly DependencyProperty PeriodProperty = DependencyProperty.Register(nameof(Period), typeof(ITimePeriod), typeof(WinoCalendarPanel), new PropertyMetadata(null));
|
||||
|
||||
|
||||
public ITimePeriod Period
|
||||
{
|
||||
get { return (ITimePeriod)GetValue(PeriodProperty); }
|
||||
@@ -46,9 +45,6 @@ namespace Wino.Calendar.Controls
|
||||
|
||||
private void ResetMeasurements() => _measurements.Clear();
|
||||
|
||||
// No need to handle actions. Each action requires a full measurement update.
|
||||
private void EventCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => ResetMeasurements();
|
||||
|
||||
private double GetChildTopMargin(ICalendarItem calendarItemViewModel, double availableHeight)
|
||||
{
|
||||
var childStart = calendarItemViewModel.StartDate;
|
||||
@@ -75,31 +71,25 @@ namespace Wino.Calendar.Controls
|
||||
|
||||
private double GetChildHeight(ICalendarItem child)
|
||||
{
|
||||
double childDurationInMinutes = 0d;
|
||||
// All day events are not measured.
|
||||
if (child.IsAllDayEvent) return 0;
|
||||
|
||||
double childDurationInMinutes = 0d;
|
||||
double availableHeight = HourHeight * 24;
|
||||
|
||||
var childStart = child.Period.Start;
|
||||
var childEnd = child.Period.End;
|
||||
var periodRelation = child.Period.GetRelation(Period);
|
||||
|
||||
// Multi-day event.
|
||||
Debug.WriteLine($"Render relation of {child.Title} ({child.Period.Start} - {child.Period.End}) is {periodRelation} with {Period.Start.Day}");
|
||||
|
||||
if (childStart < Period.Start)
|
||||
if (!child.IsMultiDayEvent)
|
||||
{
|
||||
if (childEnd >= Period.End)
|
||||
{
|
||||
// Event spans the whole period.
|
||||
return availableHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check how many of the event falls into the current period.
|
||||
childDurationInMinutes = (childEnd - Period.Start).TotalMinutes;
|
||||
}
|
||||
childDurationInMinutes = child.Period.Duration.TotalMinutes;
|
||||
}
|
||||
else
|
||||
{
|
||||
childDurationInMinutes = (childEnd - childStart).TotalMinutes;
|
||||
// Multi-day event.
|
||||
// Check how many of the event falls into the current period.
|
||||
childDurationInMinutes = (child.Period.End - Period.Start).TotalMinutes;
|
||||
}
|
||||
|
||||
return (childDurationInMinutes / 1440) * availableHeight;
|
||||
@@ -131,33 +121,51 @@ namespace Wino.Calendar.Controls
|
||||
|
||||
if (!calendarControls.Any()) return base.ArrangeOverride(finalSize);
|
||||
|
||||
if (_measurements.Count == 0 && calendarControls.Any())
|
||||
{
|
||||
// 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.
|
||||
var events = calendarControls.Select(a => a.Content as CalendarItemViewModel);
|
||||
|
||||
var events = calendarControls.Select(a => a.Content as CalendarItemViewModel);
|
||||
|
||||
LayoutEvents(events);
|
||||
}
|
||||
LayoutEvents(events);
|
||||
|
||||
foreach (var control in calendarControls)
|
||||
{
|
||||
// We can't arrange this child. It doesn't have a valid ICalendarItem or measurement.
|
||||
if (!(control.Content is ICalendarItem child) || !_measurements.ContainsKey(child.Id)) continue;
|
||||
// We can't arrange this child.
|
||||
if (!(control.Content is ICalendarItem child)) continue;
|
||||
|
||||
var childMeasurement = _measurements[child.Id];
|
||||
bool isHorizontallyLastItem = false;
|
||||
|
||||
double childHeight = Math.Max(0, GetChildHeight(child));
|
||||
double childWidth = Math.Max(0, GetChildWidth(childMeasurement, finalSize.Width));
|
||||
double childTop = Math.Max(0, GetChildTopMargin(child, availableHeight));
|
||||
double childLeft = Math.Max(0, GetChildLeftMargin(childMeasurement, availableWidth));
|
||||
double childWidth = 0,
|
||||
childHeight = Math.Max(0, GetChildHeight(child)),
|
||||
childTop = Math.Max(0, GetChildTopMargin(child, availableHeight)),
|
||||
childLeft = 0;
|
||||
|
||||
bool isHorizontallyLastItem = childMeasurement.Right == 1;
|
||||
// No need to measure anything here.
|
||||
if (childHeight == 0) continue;
|
||||
|
||||
if (!_measurements.ContainsKey(child))
|
||||
{
|
||||
// Multi-day event.
|
||||
|
||||
childLeft = 0;
|
||||
childWidth = availableWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
var childMeasurement = _measurements[child];
|
||||
|
||||
childWidth = Math.Max(0, GetChildWidth(childMeasurement, finalSize.Width));
|
||||
childLeft = Math.Max(0, GetChildLeftMargin(childMeasurement, availableWidth));
|
||||
|
||||
isHorizontallyLastItem = childMeasurement.Right == 1;
|
||||
}
|
||||
|
||||
// Add additional right margin to items that falls on the right edge of the panel.
|
||||
// Max of 5% of the width or 20px max.
|
||||
var extraRightMargin = isHorizontallyLastItem ? Math.Max(LastItemRightExtraMargin, finalSize.Width * 5 / 100) : 0;
|
||||
double extraRightMargin = 0;
|
||||
|
||||
// Multi-day events don't have any margin and their hit test is disabled.
|
||||
if (!child.IsMultiDayEvent)
|
||||
{
|
||||
// Max of 5% of the width or 20px max.
|
||||
extraRightMargin = isHorizontallyLastItem ? Math.Max(LastItemRightExtraMargin, finalSize.Width * 5 / 100) : 0;
|
||||
}
|
||||
|
||||
if (childWidth < 0) childWidth = 1;
|
||||
|
||||
@@ -178,13 +186,13 @@ namespace Wino.Calendar.Controls
|
||||
|
||||
private void AddOrUpdateMeasurement(ICalendarItem calendarItem, CalendarItemMeasurement measurement)
|
||||
{
|
||||
if (_measurements.ContainsKey(calendarItem.Id))
|
||||
if (_measurements.ContainsKey(calendarItem))
|
||||
{
|
||||
_measurements[calendarItem.Id] = measurement;
|
||||
_measurements[calendarItem] = measurement;
|
||||
}
|
||||
else
|
||||
{
|
||||
_measurements.Add(calendarItem.Id, measurement);
|
||||
_measurements.Add(calendarItem, measurement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +204,9 @@ namespace Wino.Calendar.Controls
|
||||
|
||||
foreach (var ev in events.OrderBy(ev => ev.StartDate).ThenBy(ev => ev.EndDate))
|
||||
{
|
||||
// Multi-day events are not measured.
|
||||
if (ev.IsMultiDayEvent) continue;
|
||||
|
||||
if (ev.Period.Start >= lastEventEnding)
|
||||
{
|
||||
PackEvents(columns);
|
||||
|
||||
22
Wino.Calendar/Selectors/CustomAreaCalendarItemSelector.cs
Normal file
22
Wino.Calendar/Selectors/CustomAreaCalendarItemSelector.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Wino.Calendar.ViewModels.Data;
|
||||
|
||||
namespace Wino.Calendar.Selectors
|
||||
{
|
||||
public class CustomAreaCalendarItemSelector : DataTemplateSelector
|
||||
{
|
||||
public DataTemplate AllDayTemplate { get; set; }
|
||||
public DataTemplate MultiDayTemplate { get; set; }
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
||||
{
|
||||
if (item is CalendarItemViewModel calendarItemViewModel)
|
||||
{
|
||||
return calendarItemViewModel.IsMultiDayEvent ? MultiDayTemplate : AllDayTemplate;
|
||||
}
|
||||
|
||||
return base.SelectTemplateCore(item, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,15 +11,7 @@
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:toolkitControls="using:CommunityToolkit.WinUI.Controls">
|
||||
|
||||
<!-- Default Calendar Item View Model Template -->
|
||||
<DataTemplate x:Key="CalendarItemViewModelItemTemplate" x:DataType="data:CalendarItemViewModel">
|
||||
<controls:CalendarItemControl CalendarItem="{x:Bind}" />
|
||||
</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. -->
|
||||
<DataTemplate x:Key="DayCalendarHourHeaderTemplate" x:DataType="models:DayHeaderRenderModel">
|
||||
@@ -33,7 +25,16 @@
|
||||
|
||||
<!-- Vertical panel that renders items on canvas. -->
|
||||
<DataTemplate x:Key="DayCalendarItemVerticalRenderTemplate" x:DataType="models:CalendarDayModel">
|
||||
<ItemsControl ItemTemplate="{StaticResource CalendarItemViewModelItemTemplate}" ItemsSource="{x:Bind EventsCollection.RegularEvents}">
|
||||
<ItemsControl x:Name="RegularEventItemsControl" ItemsSource="{x:Bind EventsCollection.RegularEvents}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<!-- Default Calendar Item View Model Template -->
|
||||
<DataTemplate x:DataType="data:CalendarItemViewModel">
|
||||
<controls:CalendarItemControl
|
||||
CalendarItem="{x:Bind}"
|
||||
DisplayingDate="{Binding ElementName=RegularEventItemsControl, Path=DataContext}"
|
||||
IsCustomEventArea="False" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
<ItemsControl.ItemContainerTransitions>
|
||||
<TransitionCollection>
|
||||
<PaneThemeTransition Edge="Left" />
|
||||
@@ -65,10 +66,7 @@
|
||||
ItemsSource="{x:Bind CalendarDays}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:CalendarDayModel">
|
||||
<controls:DayColumnControl
|
||||
MinHeight="100"
|
||||
MaxHeight="200"
|
||||
DayModel="{x:Bind}" />
|
||||
<controls:DayColumnControl DayModel="{x:Bind}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
<ItemsControl.ItemsPanel>
|
||||
@@ -212,7 +210,7 @@
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" MinHeight="35" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Day number -->
|
||||
@@ -221,15 +219,12 @@
|
||||
<!-- Extras -->
|
||||
<StackPanel Grid.Column="1" HorizontalAlignment="Right" />
|
||||
|
||||
<!-- All-Day Events -->
|
||||
|
||||
<!-- TODO: This control leaks. -->
|
||||
<!-- All-Multi Day Events -->
|
||||
<controls:AllDayItemsControl
|
||||
x:Name="PART_AllDayItemsControl"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
AllDayEventTemplate="{StaticResource CalendarItemViewModelItemTemplate}"
|
||||
EventCollection="{Binding EventsCollection}"
|
||||
RegularEventItemTemplate="{StaticResource CalendarItemViewModelItemTemplate}" />
|
||||
Margin="0,6" />
|
||||
</Grid>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -158,6 +158,7 @@
|
||||
</Compile>
|
||||
<Compile Include="Models\CalendarItemMeasurement.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Selectors\CustomAreaCalendarItemSelector.cs" />
|
||||
<Compile Include="Services\AccountCalendarStateService.cs" />
|
||||
<Compile Include="Services\CalendarAuthenticatorConfig.cs" />
|
||||
<Compile Include="Services\DialogService.cs" />
|
||||
|
||||
Reference in New Issue
Block a user