Monthly calendar basics.

This commit is contained in:
Burak Kaan Köse
2025-01-06 21:56:33 +01:00
parent 125c277c88
commit 0f57a4dfd7
43 changed files with 915 additions and 336 deletions

View File

@@ -0,0 +1,48 @@
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
using Wino.Calendar.ViewModels.Interfaces;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Navigation;
using Wino.Core.ViewModels;
using Wino.Mail.ViewModels.Data;
using Wino.Messaging.UI;
namespace Wino.Calendar.ViewModels
{
public partial class AccountDetailsPageViewModel : CalendarBaseViewModel
{
private readonly IAccountService _accountService;
public AccountProviderDetailViewModel Account { get; private set; }
public ICalendarDialogService CalendarDialogService { get; }
public IAccountCalendarStateService AccountCalendarStateService { get; }
public AccountDetailsPageViewModel(ICalendarDialogService calendarDialogService, IAccountService accountService, IAccountCalendarStateService accountCalendarStateService)
{
CalendarDialogService = calendarDialogService;
_accountService = accountService;
AccountCalendarStateService = accountCalendarStateService;
}
[RelayCommand]
private async Task RenameAccount()
{
if (Account == null)
return;
var updatedAccount = await CalendarDialogService.ShowEditAccountDialogAsync(Account.Account);
if (updatedAccount != null)
{
await _accountService.UpdateAccountAsync(updatedAccount);
ReportUIChange(new AccountUpdatedMessage(updatedAccount));
}
}
public override void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
}
}
}

View File

@@ -11,11 +11,11 @@ using Wino.Calendar.ViewModels.Data;
using Wino.Calendar.ViewModels.Interfaces;
using Wino.Core.Domain.Collections;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Extensions;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Calendar;
using Wino.Core.Domain.Models.Navigation;
using Wino.Core.Domain.Models.Synchronization;
using Wino.Core.Extensions;
using Wino.Core.ViewModels;
using Wino.Messaging.Client.Calendar;
using Wino.Messaging.Client.Navigation;
@@ -67,9 +67,6 @@ namespace Wino.Calendar.ViewModels
[ObservableProperty]
private int _selectedDateNavigationHeaderIndex;
public bool IsVerticalCalendar => StatePersistenceService.CalendarDisplayType == CalendarDisplayType.Month;
// For updating account calendars asynchronously.
@@ -209,7 +206,7 @@ namespace Wino.Calendar.ViewModels
ForceNavigateCalendarDate();
break;
case 0:
NavigationService.Navigate(WinoPage.AccountManagementPage);
NavigationService.Navigate(WinoPage.ManageAccountsPage);
break;
case 1:
NavigationService.Navigate(WinoPage.SettingsPage);

View File

@@ -31,7 +31,9 @@ namespace Wino.Calendar.ViewModels
IRecipient<CalendarSettingsUpdatedMessage>,
IRecipient<CalendarItemTappedMessage>,
IRecipient<CalendarItemDoubleTappedMessage>,
IRecipient<CalendarItemRightTappedMessage>
IRecipient<CalendarItemRightTappedMessage>,
IRecipient<CalendarDisplayTypeChangedMessage>
{
#region Quick Event Creation
@@ -92,6 +94,8 @@ namespace Wino.Calendar.ViewModels
#region Data Initialization
public bool IsVerticalCalendar => StatePersistanceService.CalendarDisplayType == CalendarDisplayType.Month;
[ObservableProperty]
private DayRangeCollection _dayRanges = [];
@@ -161,13 +165,16 @@ namespace Wino.Calendar.ViewModels
private void UpdateAccountCalendarRequested(object sender, AccountCalendarViewModel e)
=> FilterActiveCalendars(DayRanges);
private void FilterActiveCalendars(IEnumerable<DayRangeRenderModel> dayRangeRenderModels)
private async void FilterActiveCalendars(IEnumerable<DayRangeRenderModel> dayRangeRenderModels)
{
var days = dayRangeRenderModels.SelectMany(a => a.CalendarDays);
await ExecuteUIThread(() =>
{
var days = dayRangeRenderModels.SelectMany(a => a.CalendarDays);
days.ForEach(a => a.EventsCollection.FilterByCalendars(AccountCalendarStateService.ActiveCalendars.Select(a => a.Id)));
days.ForEach(a => a.EventsCollection.FilterByCalendars(AccountCalendarStateService.ActiveCalendars.Select(a => a.Id)));
DisplayDetailsCalendarItemViewModel = null;
DisplayDetailsCalendarItemViewModel = null;
});
}
// TODO: Replace when calendar settings are updated.
@@ -178,6 +185,7 @@ namespace Wino.Calendar.ViewModels
{
CalendarDisplayType.Day => new DayCalendarDrawingStrategy(CurrentSettings),
CalendarDisplayType.Week => new WeekCalendarDrawingStrategy(CurrentSettings),
CalendarDisplayType.Month => new MonthCalendarDrawingStrategy(CurrentSettings),
_ => throw new NotImplementedException(),
};
}
@@ -831,5 +839,7 @@ namespace Wino.Calendar.ViewModels
// var calendarItems = GetCalendarItems(deletedItem.Id);
});
}
public void Receive(CalendarDisplayTypeChangedMessage message) => OnPropertyChanged(nameof(IsVerticalCalendar));
}
}

View File

@@ -82,6 +82,7 @@ namespace Wino.Calendar
services.AddTransient(typeof(CalendarSettingsPageViewModel));
services.AddTransient(typeof(AccountManagementViewModel));
services.AddTransient(typeof(PersonalizationPageViewModel));
services.AddTransient(typeof(AccountDetailsPageViewModel));
}
#endregion

View File

@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Messaging;
using Itenso.TimePeriod;
using Windows.UI.Xaml;
@@ -126,7 +125,7 @@ namespace Wino.Calendar.Controls
CalendarItemTitle = CalendarItem.Title;
}
Debug.WriteLine($"{CalendarItem.Title} Period relation with {DisplayingDate.Period.ToString()}: {periodRelation}");
// Debug.WriteLine($"{CalendarItem.Title} Period relation with {DisplayingDate.Period.ToString()}: {periodRelation}");
}
else
{

View File

@@ -56,10 +56,15 @@ namespace Wino.Calendar.Controls
private void UpdateValues()
{
if (HeaderDateDayText == null || ColumnHeaderText == null || IsTodayBorder == null || DayModel == null) return;
if (HeaderDateDayText == null || IsTodayBorder == null || DayModel == null) return;
HeaderDateDayText.Text = DayModel.RepresentingDate.Day.ToString();
ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo);
// Monthly template does not use it.
if (ColumnHeaderText != null)
{
ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo);
}
AllDayItemsControl.ItemsSource = DayModel.EventsCollection.AllDayEvents;

View File

@@ -6,6 +6,7 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Wino.Calendar.Args;
using Wino.Calendar.ViewModels.Data;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.Calendar;
using Wino.Helpers;
@@ -30,6 +31,28 @@ namespace Wino.Calendar.Controls
public static readonly DependencyProperty IsFlipIdleProperty = DependencyProperty.Register(nameof(IsFlipIdle), typeof(bool), typeof(WinoCalendarControl), new PropertyMetadata(true, new PropertyChangedCallback(OnIdleStateChanged)));
public static readonly DependencyProperty ActiveScrollViewerProperty = DependencyProperty.Register(nameof(ActiveScrollViewer), typeof(ScrollViewer), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnActiveVerticalScrollViewerChanged)));
public static readonly DependencyProperty VerticalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(VerticalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnIsVerticalCalendarChanged)));
public static readonly DependencyProperty HorizontalItemsPanelTemplateProperty = DependencyProperty.Register(nameof(HorizontalItemsPanelTemplate), typeof(ItemsPanelTemplate), typeof(WinoCalendarControl), new PropertyMetadata(null, new PropertyChangedCallback(OnIsVerticalCalendarChanged)));
public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register(nameof(DisplayType), typeof(CalendarDisplayType), typeof(WinoCalendarControl), new PropertyMetadata(CalendarDisplayType.Day, new PropertyChangedCallback(OnIsVerticalCalendarChanged)));
public CalendarDisplayType DisplayType
{
get { return (CalendarDisplayType)GetValue(DisplayTypeProperty); }
set { SetValue(DisplayTypeProperty, value); }
}
public ItemsPanelTemplate VerticalItemsPanelTemplate
{
get { return (ItemsPanelTemplate)GetValue(VerticalItemsPanelTemplateProperty); }
set { SetValue(VerticalItemsPanelTemplateProperty, value); }
}
public ItemsPanelTemplate HorizontalItemsPanelTemplate
{
get { return (ItemsPanelTemplate)GetValue(HorizontalItemsPanelTemplateProperty); }
set { SetValue(HorizontalItemsPanelTemplateProperty, value); }
}
public DayRangeRenderModel SelectedFlipViewDayRange
{
get { return (DayRangeRenderModel)GetValue(SelectedFlipViewDayRangeProperty); }
@@ -81,6 +104,14 @@ namespace Wino.Calendar.Controls
SizeChanged += CalendarSizeChanged;
}
private static void OnIsVerticalCalendarChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl control)
{
control.ManageCalendarOrientation();
}
}
private static void OnIdleStateChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl calendarControl)
@@ -89,6 +120,7 @@ namespace Wino.Calendar.Controls
}
}
private static void OnActiveVerticalScrollViewerChanged(DependencyObject calendar, DependencyPropertyChangedEventArgs e)
{
if (calendar is WinoCalendarControl calendarControl)
@@ -124,6 +156,22 @@ namespace Wino.Calendar.Controls
}
}
private void ManageCalendarOrientation()
{
if (InternalFlipView == null || HorizontalItemsPanelTemplate == null || VerticalItemsPanelTemplate == null) return;
bool isHorizontalCalendar = DisplayType == CalendarDisplayType.Day || DisplayType == CalendarDisplayType.Week || DisplayType == CalendarDisplayType.WorkWeek;
if (isHorizontalCalendar)
{
InternalFlipView.ItemsPanel = HorizontalItemsPanelTemplate;
}
else
{
InternalFlipView.ItemsPanel = VerticalItemsPanelTemplate;
}
}
private void ManageHighlightedDateRange()
{
if (ActiveCanvas == null)
@@ -186,6 +234,7 @@ namespace Wino.Calendar.Controls
IdleGrid = GetTemplateChild(PART_IdleGrid) as Grid;
UpdateIdleState();
ManageCalendarOrientation();
}
private void UpdateIdleState()
@@ -248,8 +297,6 @@ namespace Wino.Calendar.Controls
public CalendarItemControl GetCalendarItemControl(CalendarItemViewModel calendarItemViewModel)
{
if (ActiveCanvas == null) return null;
return this.FindDescendants<CalendarItemControl>().FirstOrDefault(a => a.CalendarItem == calendarItemViewModel);
}
}

View File

@@ -0,0 +1,34 @@
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
namespace Wino.Calendar.Selectors
{
public class WinoCalendarItemTemplateSelector : DataTemplateSelector
{
public CalendarDisplayType DisplayType { get; set; }
public DataTemplate DayWeekWorkWeekTemplate { get; set; }
public DataTemplate MonthlyTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
switch (DisplayType)
{
case CalendarDisplayType.Day:
case CalendarDisplayType.Week:
case CalendarDisplayType.WorkWeek:
return DayWeekWorkWeekTemplate;
case CalendarDisplayType.Month:
return MonthlyTemplate;
case CalendarDisplayType.Year:
break;
default:
break;
}
return base.SelectTemplateCore(item, container);
}
}
}

View File

@@ -16,21 +16,17 @@ namespace Wino.Calendar.Services
{
public Type GetPageType(WinoPage winoPage)
{
switch (winoPage)
return winoPage switch
{
case WinoPage.CalendarPage:
return typeof(CalendarPage);
case WinoPage.SettingsPage:
return typeof(SettingsPage);
case WinoPage.CalendarSettingsPage:
return typeof(CalendarSettingsPage);
case WinoPage.AccountManagementPage:
return typeof(AccountManagementPage);
case WinoPage.PersonalizationPage:
return typeof(PersonalizationPage);
default:
throw new Exception("Page is not implemented yet.");
}
WinoPage.CalendarPage => typeof(CalendarPage),
WinoPage.SettingsPage => typeof(SettingsPage),
WinoPage.CalendarSettingsPage => typeof(CalendarSettingsPage),
WinoPage.AccountManagementPage => typeof(AccountManagementPage),
WinoPage.ManageAccountsPage => typeof(ManageAccountsPage),
WinoPage.PersonalizationPage => typeof(PersonalizationPage),
WinoPage.AccountDetailsPage => typeof(AccountDetailsPage),
_ => throw new Exception("Page is not implemented yet."),
};
}
public bool Navigate(WinoPage page, object parameter = null, NavigationReferenceFrame frame = NavigationReferenceFrame.ShellFrame, NavigationTransitionType transition = NavigationTransitionType.None)

View File

@@ -3,6 +3,7 @@
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:controls1="using:Wino.Core.UWP.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:data="using:Wino.Calendar.ViewModels.Data"
xmlns:helpers="using:Wino.Helpers"
@@ -12,8 +13,6 @@
xmlns:selectors="using:Wino.Calendar.Selectors"
xmlns:toolkitControls="using:CommunityToolkit.WinUI.Controls">
<!-- 08:00 or 8 AM/PM on the left etc. -->
<DataTemplate x:Key="DayCalendarHourHeaderTemplate" x:DataType="models:DayHeaderRenderModel">
<Grid Height="{x:Bind HourHeight}">
@@ -50,6 +49,8 @@
</DataTemplate>
<!-- Equally distributed days of week representation in FlipView. -->
<!-- Used for day-week-work week templates. -->
<!-- Horizontal template -->
<DataTemplate x:Key="FlipTemplate" x:DataType="models:DayRangeRenderModel">
<Grid
x:Name="RootGrid"
@@ -57,14 +58,11 @@
ColumnSpacing="0"
RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="100" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ItemsControl
Grid.Column="1"
Margin="50,0,16,0"
ItemsSource="{x:Bind CalendarDays}">
<ItemsControl Margin="50,0,16,0" ItemsSource="{x:Bind CalendarDays}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:CalendarDayModel">
<controls:DayColumnControl DayModel="{x:Bind}" />
@@ -125,9 +123,58 @@
</Grid>
</DataTemplate>
<!-- Template that displays 35 days in total. -->
<!-- Used for monthly view -->
<!-- Vertical template -->
<DataTemplate x:Key="MonthlyFlipTemplate" x:DataType="models:DayRangeRenderModel">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Height="20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<ItemsControl Grid.Row="1" ItemsSource="{x:Bind CalendarDays}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:CalendarDayModel">
<controls:DayColumnControl DayModel="{x:Bind Mode=OneWay}" Template="{StaticResource MonthlyColumnControlTemplate}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls1:EqualGridPanel Columns="7" Rows="5" />
<!--<ItemsWrapGrid MaximumRowsOrColumns="7" Orientation="Horizontal" />-->
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</DataTemplate>
<ItemsPanelTemplate x:Key="VerticalFlipViewItemsPanel">
<VirtualizingStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="HorizontalFlipViewItemsPanel">
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
<!-- Default style for WinoCalendarControl -->
<Style TargetType="controls:WinoCalendarControl">
<Style.Setters>
<Setter Property="HorizontalItemsPanelTemplate" Value="{StaticResource HorizontalFlipViewItemsPanel}" />
<Setter Property="VerticalItemsPanelTemplate" Value="{StaticResource VerticalFlipViewItemsPanel}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:WinoCalendarControl">
@@ -141,9 +188,15 @@
Background="Transparent"
IsIdle="{x:Bind IsFlipIdle, Mode=TwoWay}"
IsTabStop="False"
ItemTemplate="{StaticResource FlipTemplate}"
ItemsSource="{TemplateBinding DayRanges}"
SelectedIndex="{Binding SelectedFlipViewIndex, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}" />
SelectedIndex="{Binding SelectedFlipViewIndex, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}">
<controls:WinoCalendarFlipView.ItemTemplateSelector>
<selectors:WinoCalendarItemTemplateSelector
DayWeekWorkWeekTemplate="{StaticResource FlipTemplate}"
DisplayType="{x:Bind DisplayType, Mode=OneWay}"
MonthlyTemplate="{StaticResource MonthlyFlipTemplate}" />
</controls:WinoCalendarFlipView.ItemTemplateSelector>
</controls:WinoCalendarFlipView>
<Grid x:Name="PART_IdleGrid" Visibility="Collapsed">
<muxc:ProgressRing
@@ -160,122 +213,227 @@
</Style.Setters>
</Style>
<!-- Top header control for days. -->
<ControlTemplate x:Key="DailyColumnControlTemplate" 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="*" MinHeight="35" />
</Grid.RowDefinitions>
<!-- Day number -->
<TextBlock x:Name="PART_HeaderDateDayText" FontSize="17" />
<!-- Extras -->
<StackPanel Grid.Column="1" HorizontalAlignment="Right" />
<!-- All-Multi Day Events -->
<ItemsControl
x:Name="PART_AllDayItemsControl"
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="0,6">
<ItemsControl.ItemTemplateSelector>
<selectors:CustomAreaCalendarItemSelector>
<selectors:CustomAreaCalendarItemSelector.AllDayTemplate>
<DataTemplate x:DataType="data:CalendarItemViewModel">
<controls:CalendarItemControl
CalendarItem="{x:Bind}"
DisplayingDate="{Binding DataContext, ElementName=PART_AllDayItemsControl}"
IsCustomEventArea="True" />
</DataTemplate>
</selectors:CustomAreaCalendarItemSelector.AllDayTemplate>
<selectors:CustomAreaCalendarItemSelector.MultiDayTemplate>
<DataTemplate x:DataType="data:CalendarItemViewModel">
<controls:CalendarItemControl
CalendarItem="{x:Bind}"
DisplayingDate="{Binding DataContext, ElementName=PART_AllDayItemsControl}"
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>
</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>
<!-- Monthly data control for months -->
<ControlTemplate x:Key="MonthlyColumnControlTemplate" TargetType="controls:DayColumnControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="5" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Border for today indication. -->
<Border
x:Name="PART_IsTodayBorder"
Grid.Row="0"
Height="5"
Margin="2,0,2,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Background="{ThemeResource SystemAccentColor}"
CornerRadius="2"
Visibility="Collapsed" />
<!-- Border -->
<Grid
Grid.Row="0"
Grid.RowSpan="2"
BorderBrush="{ThemeResource CalendarSeperatorBrush}"
BorderThickness="1,1,0,1" />
<!-- Place where full day events go. -->
<Grid
x:Name="PART_DayDataAreaGrid"
Grid.Row="1"
Padding="6"
BorderBrush="{ThemeResource CalendarSeperatorBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" MinHeight="35" />
</Grid.RowDefinitions>
<!-- Day number -->
<TextBlock x:Name="PART_HeaderDateDayText" FontSize="17" />
<!-- Extras -->
<StackPanel Grid.Column="1" HorizontalAlignment="Right" />
<!-- All events summary. -->
<ScrollViewer
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="0,6"
Padding="0,0,16,0">
<ItemsControl x:Name="PART_AllDayItemsControl">
<ItemsControl.ItemTemplateSelector>
<selectors:CustomAreaCalendarItemSelector>
<selectors:CustomAreaCalendarItemSelector.AllDayTemplate>
<DataTemplate x:DataType="data:CalendarItemViewModel">
<controls:CalendarItemControl
CalendarItem="{x:Bind}"
DisplayingDate="{Binding DataContext, ElementName=PART_AllDayItemsControl}"
IsCustomEventArea="True" />
</DataTemplate>
</selectors:CustomAreaCalendarItemSelector.AllDayTemplate>
<selectors:CustomAreaCalendarItemSelector.MultiDayTemplate>
<DataTemplate x:DataType="data:CalendarItemViewModel">
<controls:CalendarItemControl
CalendarItem="{x:Bind}"
DisplayingDate="{Binding DataContext, ElementName=PART_AllDayItemsControl}"
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>
</ScrollViewer>
</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" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
<!-- 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="*" MinHeight="35" />
</Grid.RowDefinitions>
<!-- Day number -->
<TextBlock x:Name="PART_HeaderDateDayText" FontSize="17" />
<!-- Extras -->
<StackPanel Grid.Column="1" HorizontalAlignment="Right" />
<!-- All-Multi Day Events -->
<ItemsControl
x:Name="PART_AllDayItemsControl"
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="0,6">
<ItemsControl.ItemTemplateSelector>
<selectors:CustomAreaCalendarItemSelector>
<selectors:CustomAreaCalendarItemSelector.AllDayTemplate>
<DataTemplate x:DataType="data:CalendarItemViewModel">
<controls:CalendarItemControl
CalendarItem="{x:Bind}"
DisplayingDate="{Binding DataContext, ElementName=PART_AllDayItemsControl}"
IsCustomEventArea="True" />
</DataTemplate>
</selectors:CustomAreaCalendarItemSelector.AllDayTemplate>
<selectors:CustomAreaCalendarItemSelector.MultiDayTemplate>
<DataTemplate x:DataType="data:CalendarItemViewModel">
<controls:CalendarItemControl
CalendarItem="{x:Bind}"
DisplayingDate="{Binding DataContext, ElementName=PART_AllDayItemsControl}"
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>
</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>
<Setter Property="Template" Value="{StaticResource DailyColumnControlTemplate}" />
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,7 @@
using Wino.Calendar.ViewModels;
using Wino.Core.UWP;
namespace Wino.Calendar.Views.Abstract
{
public abstract class AccountDetailsPageAbstract : BasePage<AccountDetailsPageViewModel> { }
}

View File

@@ -9,6 +9,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:winuiControls="using:CommunityToolkit.WinUI.Controls"
x:Name="root"
mc:Ignorable="d">
<ScrollViewer Margin="-12,0">

View File

@@ -6,7 +6,7 @@ namespace Wino.Calendar.Views.Account
{
public AccountManagementPage()
{
this.InitializeComponent();
InitializeComponent();
}
}
}

View File

@@ -231,19 +231,33 @@
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
IsChecked="{x:Bind IsChecked, Mode=TwoWay}">
<Border
<Grid Margin="0,0,0,5" ColumnSpacing="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Ellipse
Width="20"
Height="20"
Fill="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
FontSize="14"
Text="{x:Bind Name, Mode=OneWay}"
TextWrapping="Wrap" />
</Grid>
<!--<Border
Margin="0,0,0,4"
Padding="4,2,4,2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Background="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}"
CornerRadius="3">
<TextBlock
FontSize="14"
Foreground="{x:Bind helpers:XamlHelpers.GetReadableTextColor(BackgroundColorHex), Mode=OneWay}"
Text="{x:Bind Name, Mode=OneWay}"
TextWrapping="Wrap" />
</Border>
</Border>-->
</CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
@@ -360,8 +374,8 @@
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Target="PreviousDateButtonPathIcon.Data" Value="F1 M 16.799999 13.079999 C 16.933332 12.92 16.993332 12.74 16.98 12.539999 C 16.966665 12.34 16.886665 12.166667 16.74 12.02 C 16.593334 11.873333 16.42 11.799999 16.219999 11.799999 C 16.02 11.799999 15.853333 11.879999 15.719999 12.039999 L 10.76 17.279999 L 10.76 4.559999 C 10.76 4.346666 10.686666 4.166668 10.54 4.02 C 10.393332 3.873333 10.213333 3.799999 10 3.799999 C 9.786666 3.799999 9.606666 3.873333 9.46 4.02 C 9.313333 4.166668 9.24 4.346666 9.24 4.559999 L 9.24 17.279999 L 4.28 12.039999 C 4.146667 11.879999 3.98 11.799999 3.78 11.799999 C 3.58 11.799999 3.4 11.873333 3.24 12.02 C 3.08 12.166667 3 12.34 3 12.539999 C 3 12.74 3.066667 12.92 3.2 13.079999 L 9.28 19.48 C 9.439999 19.639999 9.626666 19.746666 9.84 19.799999 C 9.946667 19.799999 10.053333 19.799999 10.16 19.799999 C 10.373333 19.746666 10.559999 19.639999 10.719999 19.48 Z " />
<Setter Target="NextDateButtonPathIcon.Data" Value="F1 M 3.2 10.52 C 2.986666 10.733333 2.92 10.98 3 11.259999 C 3.08 11.54 3.266666 11.713333 3.56 11.78 C 3.853333 11.846666 4.093333 11.773333 4.28 11.559999 L 9.24 6.32 L 9.24 19.039999 C 9.24 19.253332 9.313333 19.433332 9.46 19.58 C 9.606666 19.726665 9.786666 19.799999 10 19.799999 C 10.213333 19.799999 10.393332 19.726665 10.54 19.58 C 10.686666 19.433332 10.76 19.253332 10.76 19.039999 L 10.76 6.32 L 15.719999 11.559999 C 15.906666 11.773333 16.139999 11.846666 16.42 11.78 C 16.700001 11.713333 16.886665 11.54 16.98 11.259999 C 17.073332 10.98 17.013332 10.733333 16.799999 10.52 L 10.719999 4.119999 C 10.559999 3.959999 10.373333 3.853333 10.16 3.799999 C 10.053333 3.799999 9.946667 3.799999 9.84 3.799999 C 9.626666 3.853333 9.439999 3.959999 9.28 4.119999 Z " />
<Setter Target="PreviousDateButtonPathIcon.Data" Value="F1 M 3.2 10.52 C 2.986666 10.733333 2.92 10.98 3 11.259999 C 3.08 11.54 3.266666 11.713333 3.56 11.78 C 3.853333 11.846666 4.093333 11.773333 4.28 11.559999 L 9.24 6.32 L 9.24 19.039999 C 9.24 19.253332 9.313333 19.433332 9.46 19.58 C 9.606666 19.726665 9.786666 19.799999 10 19.799999 C 10.213333 19.799999 10.393332 19.726665 10.54 19.58 C 10.686666 19.433332 10.76 19.253332 10.76 19.039999 L 10.76 6.32 L 15.719999 11.559999 C 15.906666 11.773333 16.139999 11.846666 16.42 11.78 C 16.700001 11.713333 16.886665 11.54 16.98 11.259999 C 17.073332 10.98 17.013332 10.733333 16.799999 10.52 L 10.719999 4.119999 C 10.559999 3.959999 10.373333 3.853333 10.16 3.799999 C 10.053333 3.799999 9.946667 3.799999 9.84 3.799999 C 9.626666 3.853333 9.439999 3.959999 9.28 4.119999 Z " />
<Setter Target="NextDateButtonPathIcon.Data" Value="F1 M 16.799999 13.079999 C 16.933332 12.92 16.993332 12.74 16.98 12.539999 C 16.966665 12.34 16.886665 12.166667 16.74 12.02 C 16.593334 11.873333 16.42 11.799999 16.219999 11.799999 C 16.02 11.799999 15.853333 11.879999 15.719999 12.039999 L 10.76 17.279999 L 10.76 4.559999 C 10.76 4.346666 10.686666 4.166668 10.54 4.02 C 10.393332 3.873333 10.213333 3.799999 10 3.799999 C 9.786666 3.799999 9.606666 3.873333 9.46 4.02 C 9.313333 4.166668 9.24 4.346666 9.24 4.559999 L 9.24 17.279999 L 4.28 12.039999 C 4.146667 11.879999 3.98 11.799999 3.78 11.799999 C 3.58 11.799999 3.4 11.873333 3.24 12.02 C 3.08 12.166667 3 12.34 3 12.539999 C 3 12.74 3.066667 12.92 3.2 13.079999 L 9.28 19.48 C 9.439999 19.639999 9.626666 19.746666 9.84 19.799999 C 9.946667 19.799999 10.053333 19.799999 10.16 19.799999 C 10.373333 19.746666 10.559999 19.639999 10.719999 19.48 Z " />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>

View File

@@ -18,9 +18,9 @@ namespace Wino.Calendar.Views
InitializeComponent();
Window.Current.SetTitleBar(DragArea);
ManageCalendarDisplayType();
}
private void ManageCalendarDisplayType()
{
// Go to different states based on the display type.

View File

@@ -33,6 +33,7 @@
<calendarControls:WinoCalendarControl
x:Name="CalendarControl"
DayRanges="{x:Bind ViewModel.DayRanges}"
DisplayType="{x:Bind ViewModel.StatePersistanceService.CalendarDisplayType, Mode=OneWay}"
IsHitTestVisible="{x:Bind ViewModel.IsCalendarEnabled, Mode=OneWay}"
ScrollPositionChanging="CalendarScrolling"
SelectedFlipViewDayRange="{x:Bind ViewModel.SelectedDayRange, Mode=TwoWay}"

View File

@@ -155,7 +155,5 @@ namespace Wino.Calendar.Views
// In case of scrolling, we must dismiss the event details dialog.
ViewModel.DisplayDetailsCalendarItemViewModel = null;
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
using Wino.Calendar.Views.Abstract;
namespace Wino.Calendar.Views.Settings
{
public sealed partial class AccountDetailsPage : AccountDetailsPageAbstract
{
public AccountDetailsPage()
{
this.InitializeComponent();
}
}
}

View File

@@ -156,6 +156,7 @@
<Compile Include="Models\CalendarItemMeasurement.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Selectors\CustomAreaCalendarItemSelector.cs" />
<Compile Include="Selectors\WinoCalendarItemTemplateSelector.cs" />
<Compile Include="Services\AccountCalendarStateService.cs" />
<Compile Include="Services\CalendarAuthenticatorConfig.cs" />
<Compile Include="Services\DialogService.cs" />
@@ -163,6 +164,7 @@
<Compile Include="Services\ProviderService.cs" />
<Compile Include="Services\SettingsBuilderService.cs" />
<Compile Include="Styles\WinoCalendarResources.xaml.cs" />
<Compile Include="Views\Abstract\AccountDetailsPageAbstract.cs" />
<Compile Include="Views\Abstract\AccountManagementPageAbstract.cs" />
<Compile Include="Views\Abstract\AppShellAbstract.cs" />
<Compile Include="Views\Abstract\CalendarPageAbstract.cs" />
@@ -177,6 +179,9 @@
<Compile Include="Views\CalendarPage.xaml.cs">
<DependentUpon>CalendarPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\AccountDetailsPage.xaml.cs">
<DependentUpon>AccountDetailsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\CalendarSettingsPage.xaml.cs">
<DependentUpon>CalendarSettingsPage.xaml</DependentUpon>
</Compile>
@@ -293,6 +298,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\AccountDetailsPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\CalendarSettingsPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@@ -40,6 +40,13 @@ namespace Wino.Core.Domain.Entities.Shared
/// </summary>
public string SynchronizationDeltaIdentifier { get; set; }
/// <summary>
/// For tracking calendar change delta.
/// Gmail: It's per-calendar, so unused.
/// Outlook: deltaLink
/// </summary>
public string CalendarSynchronizationDeltaIdentifier { get; set; }
/// <summary>
/// TODO: Gets or sets the custom account identifier color in hex.
/// </summary>

View File

@@ -13,6 +13,7 @@
WelcomePage,
AccountDetailsPage,
MergedAccountDetailsPage,
ManageAccountsPage,
AccountManagementPage,
SignatureManagementPage,
AboutPage,

View File

@@ -1,7 +1,7 @@
using System;
using Wino.Core.Domain.Models.Calendar;
namespace Wino.Core.Extensions
namespace Wino.Core.Domain.Extensions
{
public static class DateTimeExtensions
{
@@ -11,16 +11,14 @@ namespace Wino.Core.Extensions
/// <param name="date">Date to get range for.</param>
public static DateRange GetMonthDateRangeStartingWeekday(this DateTime date, DayOfWeek WeekStartDay)
{
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
DateTime firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
int daysToWeekDay = (int)firstDayOfMonth.DayOfWeek - (int)WeekStartDay;
if (daysToWeekDay < 0) daysToWeekDay += 7;
int daysToSubtract = (7 + (firstDayOfMonth.DayOfWeek - WeekStartDay)) % 7;
DateTime rangeStart = firstDayOfMonth.AddDays(-daysToSubtract);
firstDayOfMonth = firstDayOfMonth.AddDays(-daysToWeekDay);
DateTime rangeEnd = rangeStart.AddDays(34);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
return new DateRange(firstDayOfMonth, lastDayOfMonth);
return new DateRange(rangeStart, rangeEnd);
}
public static DateTime GetWeekStartDateForDate(this DateTime date, DayOfWeek firstDayOfWeek)

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.Accounts;
using Wino.Core.Domain.Models.Common;
@@ -16,6 +17,7 @@ namespace Wino.Core.Domain.Interfaces
void InfoBarMessage(string title, string message, InfoBarMessageType messageType);
void InfoBarMessage(string title, string message, InfoBarMessageType messageType, string actionButtonText, Action action);
void ShowNotSupportedMessage();
Task<MailAccount> ShowEditAccountDialogAsync(MailAccount account);
Task<string> ShowTextInputDialogAsync(string currentInput, string dialogTitle, string dialogDescription, string primaryButtonText);
Task<bool> ShowWinoCustomMessageDialogAsync(string title,
string description,

View File

@@ -16,7 +16,6 @@ namespace Wino.Core.Domain.Interfaces
// Custom dialogs
Task<IMailItemFolder> ShowMoveMailFolderDialogAsync(List<IMailItemFolder> availableFolders);
Task<MailAccount> ShowEditAccountDialogAsync(MailAccount account);
Task<MailAccount> ShowAccountPickerDialogAsync(List<MailAccount> availableAccounts);
/// <summary>

View File

@@ -0,0 +1,36 @@
using System;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Extensions;
namespace Wino.Core.Domain.Models.Calendar.CalendarTypeStrategies
{
public class MonthCalendarDrawingStrategy : BaseCalendarTypeDrawingStrategy
{
public MonthCalendarDrawingStrategy(CalendarSettings settings)
: base(settings, CalendarDisplayType.Month)
{
}
public override DateRange GetNextDateRange(DateRange CurrentDateRange, int DayDisplayCount)
{
return DateTimeExtensions.GetMonthDateRangeStartingWeekday(CurrentDateRange.EndDate, Settings.FirstDayOfWeek);
}
public override DateRange GetPreviousDateRange(DateRange CurrentDateRange, int DayDisplayCount)
{
return DateTimeExtensions.GetMonthDateRangeStartingWeekday(CurrentDateRange.StartDate, Settings.FirstDayOfWeek);
}
public override DateRange GetRenderDateRange(DateTime DisplayDate, int DayDisplayCount)
{
// Load 2 months at first.
var initialRange = DateTimeExtensions.GetMonthDateRangeStartingWeekday(DisplayDate.Date, Settings.FirstDayOfWeek);
var nextRange = GetNextDateRange(initialRange, DayDisplayCount);
return new DateRange(initialRange.StartDate, nextRange.EndDate);
}
public override int GetRenderDayCount(DateTime DisplayDate, int DayDisplayCount) => 35;
}
}

View File

@@ -135,6 +135,8 @@
"CalendarItem_DetailsPopup_JoinOnline": "Join online",
"CalendarItem_DetailsPopup_ViewEventButton": "View event",
"CalendarItem_DetailsPopup_ViewSeriesButton": "View series",
"CalendarDisplayOptions_Expand": "Expand",
"CalendarDisplayOptions_Color": "Color",
"CreateAccountAliasDialog_Title": "Create Account Alias",
"CreateAccountAliasDialog_Description": "Make sure your outgoing server allows sending mails from this alias.",
"CreateAccountAliasDialog_AliasAddress": "Address",

View File

@@ -0,0 +1,87 @@
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Wino.Core.UWP.Controls
{
public class EqualGridPanel : Panel
{
public int Rows
{
get { return (int)GetValue(RowsProperty); }
set { SetValue(RowsProperty, value); }
}
public static readonly DependencyProperty RowsProperty =
DependencyProperty.Register(
nameof(Rows),
typeof(int),
typeof(EqualGridPanel),
new PropertyMetadata(1, OnLayoutPropertyChanged));
public int Columns
{
get { return (int)GetValue(ColumnsProperty); }
set { SetValue(ColumnsProperty, value); }
}
public static readonly DependencyProperty ColumnsProperty =
DependencyProperty.Register(
nameof(Columns),
typeof(int),
typeof(EqualGridPanel),
new PropertyMetadata(1, OnLayoutPropertyChanged));
private static void OnLayoutPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is EqualGridPanel panel)
{
panel.InvalidateMeasure();
panel.InvalidateArrange();
}
}
protected override Size MeasureOverride(Size availableSize)
{
if (Rows <= 0 || Columns <= 0)
{
return new Size(0, 0);
}
double cellWidth = availableSize.Width / Columns;
double cellHeight = availableSize.Height / Rows;
foreach (UIElement child in Children)
{
child.Measure(new Size(cellWidth, cellHeight));
}
return availableSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
if (Rows <= 0 || Columns <= 0)
{
return new Size(0, 0);
}
double cellWidth = finalSize.Width / Columns;
double cellHeight = finalSize.Height / Rows;
for (int i = 0; i < Children.Count; i++)
{
int row = i / Columns;
int column = i % Columns;
double x = column * cellWidth;
double y = row * cellHeight;
Rect rect = new Rect(x, y, cellWidth, cellHeight);
Children[i].Arrange(rect);
}
return finalSize;
}
}
}

View File

@@ -45,7 +45,7 @@ namespace Wino.Core.UWP
services.AddTransient(typeof(SettingOptionsPageViewModel));
services.AddTransient(typeof(AboutPageViewModel));
services.AddTransient(typeof(SettingsPageViewModel));
services.AddTransient(typeof(NewAccountManagementPageViewModel));
services.AddTransient(typeof(ManageAccountsPagePageViewModel));
}
}
}

View File

@@ -101,6 +101,9 @@ namespace Wino.Helpers
};
}
public static string GetColorFromHex(Color color) => color.ToHex();
public static Color GetWindowsColorFromHex(string hex) => hex.ToColor();
public static SolidColorBrush GetSolidColorBrushFromHex(string colorHex) => string.IsNullOrEmpty(colorHex) ? new SolidColorBrush(Colors.Transparent) : new SolidColorBrush(colorHex.ToColor());
public static Visibility IsSelectionModeMultiple(ListViewSelectionMode mode) => mode == ListViewSelectionMode.Multiple ? Visibility.Visible : Visibility.Collapsed;
public static FontWeight GetFontWeightBySyncState(bool isSyncing) => isSyncing ? FontWeights.SemiBold : FontWeights.Normal;

View File

@@ -11,6 +11,7 @@ using Windows.Storage.Pickers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Accounts;
@@ -38,6 +39,18 @@ namespace Wino.Core.UWP.Services
ApplicationResourceManager = applicationResourceManager;
}
public async Task<MailAccount> ShowEditAccountDialogAsync(MailAccount account)
{
var editAccountDialog = new AccountEditDialog(account)
{
RequestedTheme = ThemeService.RootTheme.ToWindowsElementTheme()
};
await HandleDialogPresentationAsync(editAccountDialog);
return editAccountDialog.IsSaved ? editAccountDialog.Account : null;
}
public async Task<string> PickFilePathAsync(string saveFileName)
{
var picker = new FolderPicker()

View File

@@ -34,8 +34,6 @@
</winuiControls:SettingsCard>
</DataTemplate>
<!--#region Navigation Menu Templates-->
<!-- Manage Accounts etc. Other navigatable. -->

View File

@@ -0,0 +1,8 @@
using Wino.Core.ViewModels;
namespace Wino.Core.UWP.Views.Abstract
{
public abstract class ManageAccountsPageAbstract : BasePage<ManageAccountsPagePageViewModel>
{
}
}

View File

@@ -1,8 +1,8 @@
<abstract:NewAccountManagementPageAbstract
x:Class="Wino.Views.NewAccountManagementPage"
<abstract:ManageAccountsPageAbstract
x:Class="Wino.Views.ManageAccountsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:abstract="using:Wino.Views.Abstract"
xmlns:abstract="using:Wino.Core.UWP.Views.Abstract"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="using:Wino.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -46,4 +46,4 @@
<Frame x:Name="AccountPagesFrame" Grid.Row="1" />
</Grid>
</Border>
</abstract:NewAccountManagementPageAbstract>
</abstract:ManageAccountsPageAbstract>

View File

@@ -1,28 +1,27 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.Messaging;
using MoreLinq;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;
using Wino.Core.Domain;
using Wino.Core.Domain.Enums;
using Wino.Core.UWP.Views.Abstract;
using Wino.Mail.ViewModels.Data;
using Wino.Messaging.Client.Navigation;
using Wino.Messaging.UI;
using Wino.Views.Abstract;
using Wino.Views.Account;
using Wino.Views.Settings;
namespace Wino.Views
{
public sealed partial class NewAccountManagementPage : NewAccountManagementPageAbstract,
public sealed partial class ManageAccountsPage : ManageAccountsPageAbstract,
IRecipient<BackBreadcrumNavigationRequested>,
IRecipient<BreadcrumbNavigationRequested>,
IRecipient<MergedInboxRenamed>
{
public ObservableCollection<BreadcrumbNavigationItemViewModel> PageHistory { get; set; } = new ObservableCollection<BreadcrumbNavigationItemViewModel>();
public NewAccountManagementPage()
public ManageAccountsPage()
{
InitializeComponent();
}
@@ -31,27 +30,18 @@ namespace Wino.Views
{
base.OnNavigatedTo(e);
var initialRequest = new BreadcrumbNavigationRequested("Manage Accounts", Core.Domain.Enums.WinoPage.AccountManagementPage);
var initialRequest = new BreadcrumbNavigationRequested(Translator.MenuManageAccounts, WinoPage.AccountManagementPage);
PageHistory.Add(new BreadcrumbNavigationItemViewModel(initialRequest, true));
AccountPagesFrame.Navigate(typeof(AccountManagementPage), null, new SuppressNavigationTransitionInfo());
var accountManagementPageType = ViewModel.NavigationService.GetPageType(WinoPage.AccountManagementPage);
AccountPagesFrame.Navigate(accountManagementPageType, null, new SuppressNavigationTransitionInfo());
}
private Type GetPageNavigationType(WinoPage page)
{
return page switch
{
WinoPage.SignatureManagementPage => typeof(SignatureManagementPage),
WinoPage.AccountDetailsPage => typeof(AccountDetailsPage),
WinoPage.MergedAccountDetailsPage => typeof(MergedAccountDetailsPage),
WinoPage.AliasManagementPage => typeof(AliasManagementPage),
_ => null,
};
}
void IRecipient<BreadcrumbNavigationRequested>.Receive(BreadcrumbNavigationRequested message)
{
var pageType = GetPageNavigationType(message.PageType);
var pageType = ViewModel.NavigationService.GetPageType(message.PageType);
if (pageType == null) return;

View File

@@ -86,6 +86,7 @@
<Compile Include="BasePage.cs" />
<Compile Include="Controls\ControlConstants.cs" />
<Compile Include="Controls\CustomWrapPanel.cs" />
<Compile Include="Controls\EqualGridPanel.cs" />
<Compile Include="Controls\WinoAppTitleBar.xaml.cs">
<DependentUpon>WinoAppTitleBar.xaml</DependentUpon>
</Compile>
@@ -166,9 +167,13 @@
<Compile Include="Styles\DataTemplates.xaml.cs">
<DependentUpon>DataTemplates.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Abstract\ManageAccountsPageAbstract.cs" />
<Compile Include="Views\Abstract\SettingOptionsPageAbstract.cs" />
<Compile Include="Views\Abstract\SettingsPageAbstract.cs" />
<Compile Include="Views\Abstract\SettingsPageBase.cs" />
<Compile Include="Views\ManageAccountsPage.xaml.cs">
<DependentUpon>ManageAccountsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingOptionsPage.xaml.cs">
<DependentUpon>SettingOptionsPage.xaml</DependentUpon>
</Compile>
@@ -400,6 +405,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\ManageAccountsPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\SettingOptionsPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

View File

@@ -2,10 +2,13 @@
namespace Wino.Core.ViewModels
{
public class NewAccountManagementPageViewModel : CoreBaseViewModel
public class ManageAccountsPagePageViewModel : CoreBaseViewModel
{
public NewAccountManagementPageViewModel(IMailDialogService dialogService)
public ManageAccountsPagePageViewModel(INavigationService navigationService)
{
NavigationService = navigationService;
}
public INavigationService NavigationService { get; }
}
}

View File

@@ -966,85 +966,83 @@ namespace Wino.Core.Synchronizers.Mail
// await SynchronizeCalendarsAsync(cancellationToken).ConfigureAwait(false);
bool isInitialSync = string.IsNullOrEmpty(Account.CalendarSynchronizationDeltaIdentifier);
var localCalendars = await _outlookChangeProcessor.GetAccountCalendarsAsync(Account.Id).ConfigureAwait(false);
foreach (var calendar in localCalendars)
Microsoft.Graph.Me.CalendarView.Delta.DeltaGetResponse eventsDeltaResponse = null;
if (isInitialSync)
{
bool isInitialSync = string.IsNullOrEmpty(calendar.SynchronizationDeltaToken);
_logger.Debug("No calendar sync identifier for account {Name}. Performing initial sync.", Account.Name);
Microsoft.Graph.Me.CalendarView.Delta.DeltaGetResponse eventsDeltaResponse = null;
var startDate = DateTime.UtcNow.AddYears(-2).ToString("u");
var endDate = DateTime.UtcNow.ToString("u");
if (isInitialSync)
// No delta link. Performing initial sync.
eventsDeltaResponse = await _graphClient.Me.CalendarView.Delta.GetAsDeltaGetResponseAsync((requestConfiguration) =>
{
_logger.Debug("No sync identifier for Calendar {FolderName}. Performing initial sync.", calendar.Name);
requestConfiguration.QueryParameters.StartDateTime = startDate;
requestConfiguration.QueryParameters.EndDateTime = endDate;
var startDate = DateTime.UtcNow.AddYears(-2).ToString("u");
var endDate = DateTime.UtcNow.ToString("u");
// TODO: Expand does not work.
// https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/2358
// No delta link. Performing initial sync.
eventsDeltaResponse = await _graphClient.Me.CalendarView.Delta.GetAsDeltaGetResponseAsync((requestConfiguration) =>
{
requestConfiguration.QueryParameters.StartDateTime = startDate;
requestConfiguration.QueryParameters.EndDateTime = endDate;
requestConfiguration.QueryParameters.Expand = ["calendar"];
}, cancellationToken: cancellationToken);
}
else
{
var currentDeltaToken = calendar.SynchronizationDeltaToken;
var requestInformation = _graphClient.Me.Calendars[calendar.RemoteCalendarId].Events.Delta.ToGetRequestInformation((config) =>
{
config.QueryParameters.Top = (int)InitialMessageDownloadCountPerFolder;
config.QueryParameters.Select = outlookMessageSelectParameters;
config.QueryParameters.Orderby = ["receivedDateTime desc"];
});
requestInformation.UrlTemplate = requestInformation.UrlTemplate.Insert(requestInformation.UrlTemplate.Length - 1, ",%24deltatoken");
requestInformation.QueryParameters.Add("%24deltatoken", currentDeltaToken);
// eventsDeltaResponse = await _graphClient.RequestAdapter.SendAsync(requestInformation, Microsoft.Graph.Me.Calendars.Item.Events.Delta.DeltaGetResponse.CreateFromDiscriminatorValue);
}
List<Event> events = new();
// We must first save the parent recurring events to not lose exceptions.
// Therefore, order the existing items by their type and save the parent recurring events first.
var messageIteratorAsync = PageIterator<Event, Microsoft.Graph.Me.CalendarView.Delta.DeltaGetResponse>.CreatePageIterator(_graphClient, eventsDeltaResponse, (item) =>
{
events.Add(item);
return true;
});
await messageIteratorAsync
.IterateAsync(cancellationToken)
.ConfigureAwait(false);
// Desc-order will move parent recurring events to the top.
events = events.OrderByDescending(a => a.Type).ToList();
foreach (var item in events)
{
try
{
await _handleItemRetrievalSemaphore.WaitAsync();
await _outlookChangeProcessor.ManageCalendarEventAsync(item, calendar, Account).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.Error(ex, "Error occurred while handling item {Id} for calendar {Name}", item.Id, calendar.Name);
}
finally
{
_handleItemRetrievalSemaphore.Release();
}
}
// latestDeltaLink = messageIteratorAsync.Deltalink;
requestConfiguration.QueryParameters.Expand = new string[] { "calendar($select=name,id)" }; // Expand the calendar and select name and id. Customize as needed.
}, cancellationToken: cancellationToken);
}
else
{
//var requestInformation = _graphClient.Me.Calendars[calendar.RemoteCalendarId].Events.Delta.ToGetRequestInformation((config) =>
//{
// config.QueryParameters.Top = (int)InitialMessageDownloadCountPerFolder;
// config.QueryParameters.Select = outlookMessageSelectParameters;
// config.QueryParameters.Orderby = ["receivedDateTime desc"];
//});
//requestInformation.UrlTemplate = requestInformation.UrlTemplate.Insert(requestInformation.UrlTemplate.Length - 1, ",%24deltatoken");
//requestInformation.QueryParameters.Add("%24deltatoken", currentDeltaToken);
// eventsDeltaResponse = await _graphClient.RequestAdapter.SendAsync(requestInformation, Microsoft.Graph.Me.Calendars.Item.Events.Delta.DeltaGetResponse.CreateFromDiscriminatorValue);
}
List<Event> events = new();
// We must first save the parent recurring events to not lose exceptions.
// Therefore, order the existing items by their type and save the parent recurring events first.
var messageIteratorAsync = PageIterator<Event, Microsoft.Graph.Me.CalendarView.Delta.DeltaGetResponse>.CreatePageIterator(_graphClient, eventsDeltaResponse, (item) =>
{
events.Add(item);
return true;
});
await messageIteratorAsync
.IterateAsync(cancellationToken)
.ConfigureAwait(false);
// Desc-order will move parent recurring events to the top.
events = events.OrderByDescending(a => a.Type).ToList();
foreach (var item in events)
{
try
{
await _handleItemRetrievalSemaphore.WaitAsync();
//await _outlookChangeProcessor.ManageCalendarEventAsync(item, calendar, Account).ConfigureAwait(false);
}
catch (Exception ex)
{
// _logger.Error(ex, "Error occurred while handling item {Id} for calendar {Name}", item.Id, calendar.Name);
}
finally
{
_handleItemRetrievalSemaphore.Release();
}
}
// latestDeltaLink = messageIteratorAsync.Deltalink;
return default;
}

View File

@@ -34,49 +34,30 @@ namespace Wino.Services
public Type GetPageType(WinoPage winoPage)
{
switch (winoPage)
return winoPage switch
{
case WinoPage.None:
return null;
case WinoPage.IdlePage:
return typeof(IdlePage);
case WinoPage.AccountDetailsPage:
return typeof(AccountDetailsPage);
case WinoPage.MergedAccountDetailsPage:
return typeof(MergedAccountDetailsPage);
case WinoPage.AccountManagementPage:
return typeof(NewAccountManagementPage);
case WinoPage.SignatureManagementPage:
return typeof(SignatureManagementPage);
case WinoPage.AboutPage:
return typeof(AboutPage);
case WinoPage.PersonalizationPage:
return typeof(PersonalizationPage);
case WinoPage.MessageListPage:
return typeof(MessageListPage);
case WinoPage.ReadComposePanePage:
return typeof(ReadComposePanePage);
case WinoPage.MailRenderingPage:
return typeof(MailRenderingPage);
case WinoPage.ComposePage:
return typeof(ComposePage);
case WinoPage.MailListPage:
return typeof(MailListPage);
case WinoPage.SettingsPage:
return typeof(SettingsPage);
case WinoPage.WelcomePage:
return typeof(WelcomePage);
case WinoPage.SettingOptionsPage:
return typeof(SettingOptionsPage);
case WinoPage.AppPreferencesPage:
return typeof(AppPreferencesPage);
case WinoPage.AliasManagementPage:
return typeof(AliasManagementPage);
case WinoPage.LanguageTimePage:
return typeof(LanguageTimePage);
default:
return null;
}
WinoPage.None => null,
WinoPage.IdlePage => typeof(IdlePage),
WinoPage.AccountDetailsPage => typeof(AccountDetailsPage),
WinoPage.MergedAccountDetailsPage => typeof(MergedAccountDetailsPage),
WinoPage.AccountManagementPage => typeof(AccountManagementPage),
WinoPage.ManageAccountsPage => typeof(ManageAccountsPage),
WinoPage.SignatureManagementPage => typeof(SignatureManagementPage),
WinoPage.AboutPage => typeof(AboutPage),
WinoPage.PersonalizationPage => typeof(PersonalizationPage),
WinoPage.MessageListPage => typeof(MessageListPage),
WinoPage.ReadComposePanePage => typeof(ReadComposePanePage),
WinoPage.MailRenderingPage => typeof(MailRenderingPage),
WinoPage.ComposePage => typeof(ComposePage),
WinoPage.MailListPage => typeof(MailListPage),
WinoPage.SettingsPage => typeof(SettingsPage),
WinoPage.WelcomePage => typeof(WelcomePage),
WinoPage.SettingOptionsPage => typeof(SettingOptionsPage),
WinoPage.AppPreferencesPage => typeof(AppPreferencesPage),
WinoPage.AliasManagementPage => typeof(AliasManagementPage),
WinoPage.LanguageTimePage => typeof(LanguageTimePage),
_ => null,
};
}
public Frame GetCoreFrame(NavigationReferenceFrame frameType)

View File

@@ -1,9 +0,0 @@
using Wino.Core.UWP;
using Wino.Core.ViewModels;
namespace Wino.Views.Abstract
{
public abstract class NewAccountManagementPageAbstract : BasePage<NewAccountManagementPageViewModel>
{
}
}

View File

@@ -8,7 +8,6 @@
xmlns:coreControls="using:Wino.Core.UWP.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="using:Wino.Core.Domain"
xmlns:entites="using:Wino.Core.Domain.Entities"
xmlns:folders="using:Wino.Core.Domain.Models.Folders"
xmlns:helpers="using:Wino.Helpers"
xmlns:interactionsCore="using:Microsoft.Xaml.Interactions.Core"

View File

@@ -281,7 +281,6 @@
<Compile Include="Views\Abstract\MailRenderingPageAbstract.cs" />
<Compile Include="Views\Abstract\MergedAccountDetailsPageAbstract.cs" />
<Compile Include="Views\Abstract\MessageListPageAbstract.cs" />
<Compile Include="Views\Abstract\NewAccountManagementPageAbstract.cs" />
<Compile Include="Views\Abstract\PersonalizationPageAbstract.cs" />
<Compile Include="Views\Abstract\ReadComposePanePageAbstract.cs" />
<Compile Include="Views\Abstract\SignatureManagementPageAbstract.cs" />
@@ -322,9 +321,6 @@
<Compile Include="Views\MailRenderingPage.xaml.cs">
<DependentUpon>MailRenderingPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\NewAccountManagementPage.xaml.cs">
<DependentUpon>NewAccountManagementPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\PersonalizationPage.xaml.cs">
<DependentUpon>PersonalizationPage.xaml</DependentUpon>
</Compile>
@@ -452,10 +448,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\NewAccountManagementPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\PersonalizationPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

View File

@@ -23,7 +23,7 @@ namespace Wino.Services
}
public Task<List<AccountCalendar>> GetAccountCalendarsAsync(Guid accountId)
=> Connection.Table<AccountCalendar>().Where(x => x.AccountId == accountId).ToListAsync();
=> Connection.Table<AccountCalendar>().Where(x => x.AccountId == accountId).OrderByDescending(a => a.IsPrimary).ToListAsync();
public async Task InsertAccountCalendarAsync(AccountCalendar accountCalendar)
{