Displaying events and all-day events.
This commit is contained in:
@@ -34,6 +34,7 @@ namespace Wino.Calendar.ViewModels
|
|||||||
|
|
||||||
// Get rid of some of the items if we have too many.
|
// Get rid of some of the items if we have too many.
|
||||||
private const int maxDayRangeSize = 10;
|
private const int maxDayRangeSize = 10;
|
||||||
|
private readonly ICalendarService _calendarService;
|
||||||
private readonly IPreferencesService _preferencesService;
|
private readonly IPreferencesService _preferencesService;
|
||||||
|
|
||||||
// Store latest rendered options.
|
// Store latest rendered options.
|
||||||
@@ -47,9 +48,11 @@ namespace Wino.Calendar.ViewModels
|
|||||||
public IStatePersistanceService StatePersistanceService { get; }
|
public IStatePersistanceService StatePersistanceService { get; }
|
||||||
|
|
||||||
public CalendarPageViewModel(IStatePersistanceService statePersistanceService,
|
public CalendarPageViewModel(IStatePersistanceService statePersistanceService,
|
||||||
|
ICalendarService calendarService,
|
||||||
IPreferencesService preferencesService)
|
IPreferencesService preferencesService)
|
||||||
{
|
{
|
||||||
StatePersistanceService = statePersistanceService;
|
StatePersistanceService = statePersistanceService;
|
||||||
|
_calendarService = calendarService;
|
||||||
_preferencesService = preferencesService;
|
_preferencesService = preferencesService;
|
||||||
|
|
||||||
_currentSettings = _preferencesService.GetCurrentCalendarSettings();
|
_currentSettings = _preferencesService.GetCurrentCalendarSettings();
|
||||||
@@ -187,6 +190,8 @@ namespace Wino.Calendar.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Create day ranges for each flip item until we reach the total days to load.
|
// Create day ranges for each flip item until we reach the total days to load.
|
||||||
int totalFlipItemCount = (int)Math.Ceiling((double)flipLoadRange.TotalDays / eachFlipItemCount);
|
int totalFlipItemCount = (int)Math.Ceiling((double)flipLoadRange.TotalDays / eachFlipItemCount);
|
||||||
|
|
||||||
@@ -203,6 +208,21 @@ namespace Wino.Calendar.ViewModels
|
|||||||
renderModels.Add(new DayRangeRenderModel(renderOptions));
|
renderModels.Add(new DayRangeRenderModel(renderOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dates are loaded. Now load the events for them.
|
||||||
|
|
||||||
|
foreach (var renderModel in renderModels)
|
||||||
|
{
|
||||||
|
foreach (var day in renderModel.CalendarDays)
|
||||||
|
{
|
||||||
|
var events = await _calendarService.GetCalendarEventsAsync(Guid.Parse("13e8e385-a1bb-4764-95b4-757901cad35a"), day.Period.Start, day.Period.End).ConfigureAwait(false);
|
||||||
|
|
||||||
|
foreach (var calendarItem in events)
|
||||||
|
{
|
||||||
|
day.EventsCollection.Add(calendarItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CalendarLoadDirection animationDirection = calendarLoadDirection;
|
CalendarLoadDirection animationDirection = calendarLoadDirection;
|
||||||
|
|
||||||
bool removeCurrent = calendarLoadDirection == CalendarLoadDirection.Replace;
|
bool removeCurrent = calendarLoadDirection == CalendarLoadDirection.Replace;
|
||||||
|
|||||||
27
Wino.Calendar.ViewModels/Data/CalendarItemViewModel.cs
Normal file
27
Wino.Calendar.ViewModels/Data/CalendarItemViewModel.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using Itenso.TimePeriod;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
|
namespace Wino.Calendar.ViewModels.Data
|
||||||
|
{
|
||||||
|
public partial class CalendarItemViewModel : ObservableObject, ICalendarItem
|
||||||
|
{
|
||||||
|
public ICalendarItem CalendarItem { get; }
|
||||||
|
|
||||||
|
public string Title => CalendarItem.Title;
|
||||||
|
|
||||||
|
public Guid Id => CalendarItem.Id;
|
||||||
|
|
||||||
|
public DateTimeOffset StartTime => CalendarItem.StartTime;
|
||||||
|
|
||||||
|
public int DurationInMinutes => CalendarItem.DurationInMinutes;
|
||||||
|
|
||||||
|
public TimeRange Period => CalendarItem.Period;
|
||||||
|
|
||||||
|
public CalendarItemViewModel(ICalendarItem calendarItem)
|
||||||
|
{
|
||||||
|
CalendarItem = calendarItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,9 +20,8 @@
|
|||||||
<ResourceDictionary Source="Styles/CalendarRenderStyles.xaml" />
|
<ResourceDictionary Source="Styles/CalendarRenderStyles.xaml" />
|
||||||
|
|
||||||
<ResourceDictionary Source="Styles/CalendarDayItemsControl.xaml" />
|
<ResourceDictionary Source="Styles/CalendarDayItemsControl.xaml" />
|
||||||
<ResourceDictionary Source="Styles/DayHeaderControl.xaml" />
|
<styles:DayColumnControlResources />
|
||||||
<ResourceDictionary Source="Styles/WinoDayTimelineCanvas.xaml" />
|
<ResourceDictionary Source="Styles/WinoDayTimelineCanvas.xaml" />
|
||||||
<ResourceDictionary Source="Styles/DayColumnControl.xaml" />
|
|
||||||
<ResourceDictionary Source="Styles/WinoCalendarView.xaml" />
|
<ResourceDictionary Source="Styles/WinoCalendarView.xaml" />
|
||||||
<ResourceDictionary Source="Styles/WinoCalendarTypeSelectorControl.xaml" />
|
<ResourceDictionary Source="Styles/WinoCalendarTypeSelectorControl.xaml" />
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ namespace Wino.Calendar.Controls
|
|||||||
{
|
{
|
||||||
if (e.OldValue != null && e.OldValue is CalendarDayModel oldCalendarDayModel)
|
if (e.OldValue != null && e.OldValue is CalendarDayModel oldCalendarDayModel)
|
||||||
{
|
{
|
||||||
control.DetachCollection(oldCalendarDayModel.Events);
|
control.DetachCollection(oldCalendarDayModel.EventsCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.NewValue != null && e.NewValue is CalendarDayModel newCalendarDayModel)
|
if (e.NewValue != null && e.NewValue is CalendarDayModel newCalendarDayModel)
|
||||||
{
|
{
|
||||||
control.AttachCollection(newCalendarDayModel.Events);
|
control.AttachCollection(newCalendarDayModel.EventsCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
control.ResetItems();
|
control.ResetItems();
|
||||||
@@ -109,13 +109,13 @@ namespace Wino.Calendar.Controls
|
|||||||
|
|
||||||
private void RenderCalendarItems()
|
private void RenderCalendarItems()
|
||||||
{
|
{
|
||||||
if (DayModel == null || DayModel.Events == null || DayModel.Events.Count == 0)
|
if (DayModel == null || DayModel.EventsCollection == null || DayModel.EventsCollection.Count == 0)
|
||||||
{
|
{
|
||||||
ResetItems();
|
ResetItems();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var item in DayModel.Events)
|
foreach (var item in DayModel.EventsCollection)
|
||||||
{
|
{
|
||||||
AddItem(item);
|
AddItem(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,12 +41,12 @@ namespace Wino.Calendar.Controls
|
|||||||
// 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.Events);
|
control.DetachCollection(oldDayModel.EventsCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.NewValue is CalendarDayModel newDayModel)
|
if (e.NewValue is CalendarDayModel newDayModel)
|
||||||
{
|
{
|
||||||
control.AttachCollection(newDayModel.Events);
|
control.AttachCollection(newDayModel.EventsCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
control.ResetMeasurements();
|
control.ResetMeasurements();
|
||||||
@@ -114,12 +114,17 @@ namespace Wino.Calendar.Controls
|
|||||||
|
|
||||||
var calendarControls = Children.Cast<CalendarItemControl>();
|
var calendarControls = Children.Cast<CalendarItemControl>();
|
||||||
|
|
||||||
if (_measurements.Count == 0 && DayModel.Events.Count > 0)
|
// We need to exclude all-day events from the layout algorithm.
|
||||||
|
// All-day events are displayed in a separate panel.
|
||||||
|
|
||||||
|
calendarControls = calendarControls.Where(x => x.Item.DurationInMinutes != 1440);
|
||||||
|
|
||||||
|
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.Events);
|
LayoutEvents(DayModel.EventsCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var child in calendarControls)
|
foreach (var child in calendarControls)
|
||||||
@@ -129,9 +134,7 @@ namespace Wino.Calendar.Controls
|
|||||||
|
|
||||||
var childMeasurement = _measurements[child.Item.Id];
|
var childMeasurement = _measurements[child.Item.Id];
|
||||||
|
|
||||||
// TODO Math.Max(0, GetChildHeight(child.Item.StartTime, child.Item.EndTime));
|
double childHeight = Math.Max(0, GetChildHeight(child.Item.StartTime, child.Item.StartTime.AddMinutes(child.Item.DurationInMinutes)));
|
||||||
// Recurring events may not have an end time. We need to calculate the height based on the start time and duration.
|
|
||||||
double childHeight = 50;
|
|
||||||
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.Item.StartTime, availableHeight));
|
||||||
double childLeft = Math.Max(0, GetChildLeftMargin(childMeasurement, availableWidth));
|
double childLeft = Math.Max(0, GetChildLeftMargin(childMeasurement, availableWidth));
|
||||||
@@ -139,12 +142,10 @@ namespace Wino.Calendar.Controls
|
|||||||
bool isHorizontallyLastItem = childMeasurement.Right == 1;
|
bool isHorizontallyLastItem = childMeasurement.Right == 1;
|
||||||
|
|
||||||
// Add additional right margin to items that falls on the right edge of the panel.
|
// Add additional right margin to items that falls on the right edge of the panel.
|
||||||
// Max of 5% of the width or 20px.
|
// Max of 5% of the width or 20px max.
|
||||||
var extraRightMargin = isHorizontallyLastItem ? Math.Max(LastItemRightExtraMargin, finalSize.Width * 5 / 100) : 0;
|
var extraRightMargin = isHorizontallyLastItem ? Math.Max(LastItemRightExtraMargin, finalSize.Width * 5 / 100) : 0;
|
||||||
|
|
||||||
var finalChildWidth = childWidth - extraRightMargin;
|
if (childWidth < 0) childWidth = 1;
|
||||||
|
|
||||||
if (finalChildWidth < 0) finalChildWidth = 1;
|
|
||||||
|
|
||||||
child.Measure(new Size(childWidth, childHeight));
|
child.Measure(new Size(childWidth, childHeight));
|
||||||
|
|
||||||
@@ -178,6 +179,8 @@ 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);
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Bind Item.Title, Mode=OneWay}" />
|
Text="{x:Bind Item.Title, Mode=OneWay}"
|
||||||
|
TextWrapping="WrapWholeWords" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
<ResourceDictionary
|
<ResourceDictionary
|
||||||
|
x:Class="Wino.Calendar.Styles.DayColumnControlResources"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
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:data="using:Wino.Calendar.ViewModels.Data"
|
||||||
|
xmlns:interfaces="using:Wino.Core.Domain.Interfaces"
|
||||||
|
xmlns:local="using:Wino.Calendar.Styles">
|
||||||
<!-- Top column header DayColumnControl -->
|
<!-- Top column header DayColumnControl -->
|
||||||
<Style TargetType="controls:DayColumnControl">
|
<Style TargetType="controls:DayColumnControl">
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="controls:DayColumnControl">
|
<ControlTemplate TargetType="controls:DayColumnControl">
|
||||||
<Grid MinHeight="100" MaxHeight="150">
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="25" />
|
<RowDefinition Height="25" />
|
||||||
<RowDefinition Height="7" />
|
<RowDefinition Height="7" />
|
||||||
@@ -62,11 +65,20 @@
|
|||||||
<!-- Extras -->
|
<!-- Extras -->
|
||||||
<StackPanel Grid.Column="1" HorizontalAlignment="Right" />
|
<StackPanel Grid.Column="1" HorizontalAlignment="Right" />
|
||||||
|
|
||||||
<!-- Events -->
|
<!-- All-Day Events -->
|
||||||
<ScrollViewer
|
<ScrollViewer
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.ColumnSpan="2"
|
Grid.ColumnSpan="2"
|
||||||
VerticalScrollBarVisibility="Hidden" />
|
VerticalScrollBarVisibility="Hidden">
|
||||||
|
<ItemsControl ItemsSource="{Binding EventsCollection.AllDayEvents, Mode=OneWay}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<!-- All-Day Event template -->
|
||||||
|
<DataTemplate x:DataType="interfaces:ICalendarItem">
|
||||||
|
<TextBlock Text="{x:Bind Title}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
@@ -89,5 +101,4 @@
|
|||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
12
Wino.Calendar/Styles/DayColumnControlResources.xaml.cs
Normal file
12
Wino.Calendar/Styles/DayColumnControlResources.xaml.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Windows.UI.Xaml;
|
||||||
|
|
||||||
|
namespace Wino.Calendar.Styles
|
||||||
|
{
|
||||||
|
partial class DayColumnControlResources : ResourceDictionary
|
||||||
|
{
|
||||||
|
public DayColumnControlResources()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,10 @@
|
|||||||
ItemsSource="{x:Bind CalendarDays}">
|
ItemsSource="{x:Bind CalendarDays}">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate x:DataType="models:CalendarDayModel">
|
<DataTemplate x:DataType="models:CalendarDayModel">
|
||||||
<controls:DayColumnControl DayModel="{x:Bind}" />
|
<controls:DayColumnControl
|
||||||
|
MinHeight="100"
|
||||||
|
MaxHeight="200"
|
||||||
|
DayModel="{x:Bind}" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
|
|||||||
@@ -158,6 +158,9 @@
|
|||||||
<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\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" />
|
||||||
@@ -261,9 +264,9 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Styles\DayColumnControl.xaml">
|
<Page Include="Styles\DayColumnControlResources.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Styles\DayHeaderControl.xaml">
|
<Page Include="Styles\DayHeaderControl.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|||||||
29
Wino.Core.Domain/Collections/CalendarEventCollection.cs
Normal file
29
Wino.Core.Domain/Collections/CalendarEventCollection.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
|
||||||
|
namespace Wino.Core.Domain.Collections
|
||||||
|
{
|
||||||
|
public class CalendarEventCollection : ObservableRangeCollection<ICalendarItem>
|
||||||
|
{
|
||||||
|
public ObservableCollection<ICalendarItem> AllDayEvents { get; } = new ObservableCollection<ICalendarItem>();
|
||||||
|
public new void Add(ICalendarItem calendarItem)
|
||||||
|
{
|
||||||
|
base.Add(calendarItem);
|
||||||
|
|
||||||
|
if (calendarItem.Period.Duration.TotalMinutes == 1440)
|
||||||
|
{
|
||||||
|
AllDayEvents.Add(calendarItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Remove(ICalendarItem calendarItem)
|
||||||
|
{
|
||||||
|
base.Remove(calendarItem);
|
||||||
|
|
||||||
|
if (calendarItem.Period.Duration.TotalMinutes == 1440)
|
||||||
|
{
|
||||||
|
AllDayEvents.Remove(calendarItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
public const string WinoLocalDraftHeader = "X-Wino-Draft-Id";
|
public const string WinoLocalDraftHeader = "X-Wino-Draft-Id";
|
||||||
public const string LocalDraftStartPrefix = "localDraft_";
|
public const string LocalDraftStartPrefix = "localDraft_";
|
||||||
|
|
||||||
|
public const string CalendarEventRecurrenceRuleSeperator = "___";
|
||||||
|
|
||||||
public const string ToastMailUniqueIdKey = nameof(ToastMailUniqueIdKey);
|
public const string ToastMailUniqueIdKey = nameof(ToastMailUniqueIdKey);
|
||||||
public const string ToastActionKey = nameof(ToastActionKey);
|
public const string ToastActionKey = nameof(ToastActionKey);
|
||||||
|
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ namespace Wino.Core.Domain.Interfaces
|
|||||||
Task InsertAccountCalendarAsync(AccountCalendar accountCalendar);
|
Task InsertAccountCalendarAsync(AccountCalendar accountCalendar);
|
||||||
Task UpdateAccountCalendarAsync(AccountCalendar accountCalendar);
|
Task UpdateAccountCalendarAsync(AccountCalendar accountCalendar);
|
||||||
Task CreateNewCalendarItemAsync(CalendarItem calendarItem, List<CalendarEventAttendee> attendees);
|
Task CreateNewCalendarItemAsync(CalendarItem calendarItem, List<CalendarEventAttendee> attendees);
|
||||||
|
Task<List<ICalendarItem>> GetCalendarEventsAsync(Guid calendarId, DateTime rangeStart, DateTime rangeEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using Itenso.TimePeriod;
|
using Itenso.TimePeriod;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Collections;
|
||||||
|
|
||||||
namespace Wino.Core.Domain.Models.Calendar
|
namespace Wino.Core.Domain.Models.Calendar
|
||||||
{
|
{
|
||||||
@@ -12,7 +11,7 @@ namespace Wino.Core.Domain.Models.Calendar
|
|||||||
public class CalendarDayModel
|
public class CalendarDayModel
|
||||||
{
|
{
|
||||||
public TimeRange Period { get; }
|
public TimeRange Period { get; }
|
||||||
public ObservableCollection<ICalendarItem> Events { get; } = new ObservableCollection<ICalendarItem>();
|
public CalendarEventCollection EventsCollection { get; } = new CalendarEventCollection();
|
||||||
public CalendarDayModel(DateTime representingDate, CalendarRenderOptions calendarRenderOptions)
|
public CalendarDayModel(DateTime representingDate, CalendarRenderOptions calendarRenderOptions)
|
||||||
{
|
{
|
||||||
RepresentingDate = representingDate;
|
RepresentingDate = representingDate;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Web;
|
|||||||
using Google.Apis.Calendar.v3.Data;
|
using Google.Apis.Calendar.v3.Data;
|
||||||
using Google.Apis.Gmail.v1.Data;
|
using Google.Apis.Gmail.v1.Data;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
|
using Wino.Core.Domain;
|
||||||
using Wino.Core.Domain.Entities.Calendar;
|
using Wino.Core.Domain.Entities.Calendar;
|
||||||
using Wino.Core.Domain.Entities.Mail;
|
using Wino.Core.Domain.Entities.Mail;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
@@ -278,7 +279,7 @@ namespace Wino.Core.Extensions
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Join("___", calendarEvent.Recurrence);
|
return string.Join(Constants.CalendarEventRecurrenceRuleSeperator, calendarEvent.Recurrence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using Ical.Net.DataTypes;
|
||||||
using SqlKata;
|
using SqlKata;
|
||||||
|
using Wino.Core.Domain;
|
||||||
using Wino.Core.Domain.Entities.Calendar;
|
using Wino.Core.Domain.Entities.Calendar;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Messaging.Client.Calendar;
|
using Wino.Messaging.Client.Calendar;
|
||||||
@@ -67,5 +70,54 @@ namespace Wino.Services
|
|||||||
conn.InsertAll(attendees);
|
conn.InsertAll(attendees);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<ICalendarItem>> GetCalendarEventsAsync(Guid calendarId, DateTime rangeStart, DateTime rangeEnd)
|
||||||
|
{
|
||||||
|
// TODO: We might need to implement caching here.
|
||||||
|
// I don't know how much of the events we'll have in total, but this logic scans all events every time.
|
||||||
|
|
||||||
|
var accountEvents = await Connection.Table<CalendarItem>().Where(x => x.CalendarId == calendarId).ToListAsync();
|
||||||
|
var result = new List<ICalendarItem>();
|
||||||
|
|
||||||
|
foreach (var ev in accountEvents)
|
||||||
|
{
|
||||||
|
// Parse recurrence rules
|
||||||
|
var calendarEvent = new Ical.Net.CalendarComponents.CalendarEvent
|
||||||
|
{
|
||||||
|
Start = new CalDateTime(ev.StartTime.UtcDateTime),
|
||||||
|
Duration = TimeSpan.FromMinutes(ev.DurationInMinutes),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(ev.Recurrence))
|
||||||
|
{
|
||||||
|
// No recurrence, only check if we fall into the date range.
|
||||||
|
// All events are saved in UTC, so we need to convert the range to UTC as well.
|
||||||
|
if (ev.StartTime.UtcDateTime < rangeEnd
|
||||||
|
&& ev.StartTime.UtcDateTime.AddMinutes(ev.DurationInMinutes) > rangeStart)
|
||||||
|
{
|
||||||
|
result.Add(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var recurrenceLines = Regex.Split(ev.Recurrence, Constants.CalendarEventRecurrenceRuleSeperator);
|
||||||
|
|
||||||
|
foreach (var line in recurrenceLines)
|
||||||
|
{
|
||||||
|
calendarEvent.RecurrenceRules.Add(new RecurrencePattern(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate occurrences in the range.
|
||||||
|
var occurrences = calendarEvent.GetOccurrences(rangeStart, rangeEnd);
|
||||||
|
|
||||||
|
foreach (var occurrence in occurrences)
|
||||||
|
{
|
||||||
|
result.Add(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.70" />
|
<PackageReference Include="HtmlAgilityPack" Version="1.11.70" />
|
||||||
|
<PackageReference Include="Ical.Net" Version="4.3.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
||||||
<PackageReference Include="Serilog" Version="4.1.0" />
|
<PackageReference Include="Serilog" Version="4.1.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
||||||
|
|||||||
Reference in New Issue
Block a user