Proper handling of DateTimeOffset, support for Multi-Day events and reacting to adding/removing events for the days.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Wino.Core.Domain.Collections;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
@@ -76,9 +75,6 @@ namespace Wino.Calendar.Controls
|
||||
collection.CalendarItemAdded += SingleEventUpdated;
|
||||
collection.CalendarItemRemoved += SingleEventUpdated;
|
||||
|
||||
collection.CalendarItemRangeAdded += CollectionOfEventsUpdated;
|
||||
collection.CalendarItemRangeRemoved += CollectionOfEventsUpdated;
|
||||
|
||||
collection.CalendarItemsCleared += EventsCleared;
|
||||
}
|
||||
|
||||
@@ -87,14 +83,10 @@ namespace Wino.Calendar.Controls
|
||||
collection.CalendarItemAdded -= SingleEventUpdated;
|
||||
collection.CalendarItemRemoved -= SingleEventUpdated;
|
||||
|
||||
collection.CalendarItemRangeAdded -= CollectionOfEventsUpdated;
|
||||
collection.CalendarItemRangeRemoved -= CollectionOfEventsUpdated;
|
||||
|
||||
collection.CalendarItemsCleared -= EventsCleared;
|
||||
}
|
||||
|
||||
private void SingleEventUpdated(object sender, ICalendarItem calendarItem) => UpdateCollectionVisuals();
|
||||
private void CollectionOfEventsUpdated(object sender, List<ICalendarItem> calendarItems) => UpdateCollectionVisuals();
|
||||
private void EventsCleared(object sender, System.EventArgs e) => UpdateCollectionVisuals();
|
||||
|
||||
private void UpdateCollectionVisuals()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Wino.Calendar.Args;
|
||||
@@ -95,8 +94,6 @@ namespace Wino.Calendar.Controls
|
||||
{
|
||||
if (canvas == null) return;
|
||||
|
||||
Debug.WriteLine("Deregister active canvas.");
|
||||
|
||||
canvas.SelectedDateTime = null;
|
||||
canvas.TimelineCellSelected -= ActiveTimelineCellSelected;
|
||||
canvas.TimelineCellUnselected -= ActiveTimelineCellUnselected;
|
||||
@@ -106,8 +103,6 @@ namespace Wino.Calendar.Controls
|
||||
{
|
||||
if (canvas == null) return;
|
||||
|
||||
Debug.WriteLine("Register new canvas.");
|
||||
|
||||
canvas.SelectedDateTime = null;
|
||||
canvas.TimelineCellSelected += ActiveTimelineCellSelected;
|
||||
canvas.TimelineCellUnselected += ActiveTimelineCellUnselected;
|
||||
@@ -127,13 +122,6 @@ namespace Wino.Calendar.Controls
|
||||
InternalFlipView = GetTemplateChild(PART_WinoFlipView) as WinoCalendarFlipView;
|
||||
}
|
||||
|
||||
private void FlipViewsActiveTimelineCanvasChanged(object sender, WinoDayTimelineCanvas e)
|
||||
{
|
||||
ActiveCanvas = e;
|
||||
|
||||
SelectedFlipViewDayRange = InternalFlipView.SelectedItem as DayRangeRenderModel;
|
||||
}
|
||||
|
||||
private void ActiveTimelineCellUnselected(object sender, TimelineCellUnselectedArgs e)
|
||||
=> TimelineCellUnselected?.Invoke(this, e);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using Itenso.TimePeriod;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
@@ -21,6 +22,14 @@ namespace Wino.Calendar.Controls
|
||||
|
||||
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); }
|
||||
set { SetValue(PeriodProperty, value); }
|
||||
}
|
||||
|
||||
public double HourHeight
|
||||
{
|
||||
@@ -41,11 +50,18 @@ namespace Wino.Calendar.Controls
|
||||
|
||||
private double GetChildTopMargin(ICalendarItem calendarItemViewModel, double availableHeight)
|
||||
{
|
||||
var childStart = calendarItemViewModel.StartTime;
|
||||
var childStart = calendarItemViewModel.StartDate;
|
||||
|
||||
double totalMinutes = 1440;
|
||||
double minutesFromStart = (childStart - childStart.DateTime.Date).TotalMinutes;
|
||||
return (minutesFromStart / totalMinutes) * availableHeight;
|
||||
if (childStart <= Period.Start)
|
||||
{
|
||||
// Event started before or exactly at the periods tart. This might be a multi-day event.
|
||||
// We can simply consider event must not have a top margin.
|
||||
|
||||
return 0d;
|
||||
}
|
||||
|
||||
double minutesFromStart = (childStart - Period.Start).TotalMinutes;
|
||||
return (minutesFromStart / 1440) * availableHeight;
|
||||
}
|
||||
|
||||
private double GetChildWidth(CalendarItemMeasurement calendarItemMeasurement, double availableWidth)
|
||||
@@ -56,16 +72,48 @@ namespace Wino.Calendar.Controls
|
||||
private double GetChildLeftMargin(CalendarItemMeasurement calendarItemMeasurement, double availableWidth)
|
||||
=> availableWidth * calendarItemMeasurement.Left;
|
||||
|
||||
private double GetChildHeight(DateTimeOffset childStart, DateTimeOffset childEnd)
|
||||
private double GetChildHeight(ICalendarItem child)
|
||||
{
|
||||
double totalMinutes = 1440;
|
||||
double childDurationInMinutes = 0d;
|
||||
|
||||
double availableHeight = HourHeight * 24;
|
||||
double childDuration = (childEnd - childStart).TotalMinutes;
|
||||
return (childDuration / totalMinutes) * availableHeight;
|
||||
|
||||
var childStart = child.Period.Start;
|
||||
var childEnd = child.Period.End;
|
||||
|
||||
// Multi-day event.
|
||||
|
||||
if (childStart < Period.Start)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
childDurationInMinutes = (childEnd - childStart).TotalMinutes;
|
||||
}
|
||||
|
||||
return (childDurationInMinutes / 1440) * availableHeight;
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
ResetMeasurements();
|
||||
return base.MeasureOverride(availableSize);
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
if (Period == null || HourHeight == 0d) return finalSize;
|
||||
|
||||
// Measure/arrange each child height and width.
|
||||
// This is a vertical calendar. Therefore the height of each child is the duration of the event.
|
||||
// Children weights for left and right will be saved if they don't exist.
|
||||
@@ -99,7 +147,7 @@ namespace Wino.Calendar.Controls
|
||||
|
||||
var childMeasurement = _measurements[child.Id];
|
||||
|
||||
double childHeight = Math.Max(0, GetChildHeight(child.StartTime, child.StartTime.AddMinutes(child.DurationInMinutes)));
|
||||
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));
|
||||
@@ -142,7 +190,7 @@ namespace Wino.Calendar.Controls
|
||||
var columns = new List<List<ICalendarItem>>();
|
||||
DateTime? lastEventEnding = null;
|
||||
|
||||
foreach (var ev in events.OrderBy(ev => ev.Period.Start).ThenBy(ev => ev.Period.End))
|
||||
foreach (var ev in events.OrderBy(ev => ev.StartDate).ThenBy(ev => ev.EndDate))
|
||||
{
|
||||
if (ev.Period.Start >= lastEventEnding)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
@@ -21,6 +22,16 @@ namespace Wino.Calendar.Services
|
||||
|
||||
private ObservableCollection<GroupedAccountCalendarViewModel> _internalGroupedAccountCalendars = new ObservableCollection<GroupedAccountCalendarViewModel>();
|
||||
|
||||
public IEnumerable<AccountCalendarViewModel> ActiveCalendars
|
||||
{
|
||||
get
|
||||
{
|
||||
return GroupedAccountCalendars
|
||||
.SelectMany(a => a.AccountCalendars)
|
||||
.Where(b => b.IsChecked);
|
||||
}
|
||||
}
|
||||
|
||||
public AccountCalendarStateService()
|
||||
{
|
||||
GroupedAccountCalendars = new ReadOnlyObservableCollection<GroupedAccountCalendarViewModel>(_internalGroupedAccountCalendars);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
|
||||
<!-- CalendarControl -->
|
||||
<SolidColorBrush x:Key="CalendarSeperatorBrush">#000000</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="CalendarSeperatorBrush">#525252</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="CalendarFieldWorkingHoursBackgroundBrush">#32262626</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="CalendarFieldSelectedBackgroundBrush">#121212</SolidColorBrush>
|
||||
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
|
||||
<!-- Default Calendar Item View Model Template -->
|
||||
<DataTemplate x:Key="CalendarItemViewModelItemTemplate" x:DataType="data:CalendarItemViewModel">
|
||||
<Grid Background="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(AssignedCalendar.BackgroundColorHex), Mode=OneWay}" CornerRadius="4">
|
||||
<Grid
|
||||
Background="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(AssignedCalendar.BackgroundColorHex), Mode=OneWay}"
|
||||
BorderBrush="{ThemeResource CalendarSeperatorBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="6">
|
||||
<TextBlock
|
||||
Margin="2,0"
|
||||
HorizontalAlignment="Center"
|
||||
@@ -44,7 +48,7 @@
|
||||
<ItemsControl ItemTemplate="{StaticResource CalendarItemViewModelItemTemplate}" ItemsSource="{x:Bind EventsCollection.RegularEvents}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<controls:WinoCalendarPanel HourHeight="{Binding Path=CalendarRenderOptions.CalendarSettings.HourHeight}" />
|
||||
<controls:WinoCalendarPanel HourHeight="{Binding Path=CalendarRenderOptions.CalendarSettings.HourHeight}" Period="{Binding Path=Period}" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
|
||||
@@ -44,11 +44,6 @@ namespace Wino.Calendar.Views
|
||||
|
||||
}
|
||||
|
||||
//public void Receive(GoToCalendarDayMessage message)
|
||||
//{
|
||||
// CalendarView.GoToDay(message.DateTime);
|
||||
//}
|
||||
|
||||
private void PreviousDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoPreviousDateRequestedMessage());
|
||||
|
||||
private void NextDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoNextDateRequestedMessage());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Itenso.TimePeriod;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
@@ -16,7 +17,7 @@ namespace Wino.Calendar.Views
|
||||
IRecipient<GoNextDateRequestedMessage>,
|
||||
IRecipient<GoPreviousDateRequestedMessage>
|
||||
{
|
||||
private DateTime? selectedDateTime;
|
||||
private DateTimeOffset? selectedDateTime;
|
||||
public CalendarPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -50,7 +51,13 @@ namespace Wino.Calendar.Views
|
||||
|
||||
private void CellSelected(object sender, TimelineCellSelectedArgs e)
|
||||
{
|
||||
// Selected date is in Local kind.
|
||||
selectedDateTime = e.ClickedDate;
|
||||
var utc = DateTime.SpecifyKind(e.ClickedDate, DateTimeKind.Utc);
|
||||
var unspecified = DateTime.SpecifyKind(e.ClickedDate, DateTimeKind.Unspecified);
|
||||
|
||||
var putc = new TimeRange(utc, utc.AddMinutes(30));
|
||||
var punspecified = new TimeRange(unspecified, unspecified.AddMinutes(30));
|
||||
|
||||
// TODO: Popup is not positioned well on daily view.
|
||||
TeachingTipPositionerGrid.Width = e.CellSize.Width;
|
||||
@@ -59,8 +66,19 @@ namespace Wino.Calendar.Views
|
||||
Canvas.SetLeft(TeachingTipPositionerGrid, e.PositionerPoint.X);
|
||||
Canvas.SetTop(TeachingTipPositionerGrid, e.PositionerPoint.Y);
|
||||
|
||||
// TODO: End time can be from settings.
|
||||
// WeakReferenceMessenger.Default.Send(new CalendarEventAdded(new CalendarItem(selectedDateTime.Value, selectedDateTime.Value.AddMinutes(30))));
|
||||
//var testCalendarItem = new CalendarItem
|
||||
//{
|
||||
// CalendarId = Guid.Parse("9ead7613-dacb-4163-8d33-2e32e65008a1"),
|
||||
// StartTime = selectedDateTime.Value, // All events are saved in UTC.
|
||||
// DurationInMinutes = 30,
|
||||
// CreatedAt = DateTime.UtcNow,
|
||||
// Description = "Test Description",
|
||||
// Location = "Poland",
|
||||
// Title = "Test event",
|
||||
// Id = Guid.NewGuid()
|
||||
//};
|
||||
|
||||
//WeakReferenceMessenger.Default.Send(new CalendarEventAdded(testCalendarItem));
|
||||
|
||||
NewEventTip.IsOpen = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user