Remove old shells, some UI improvements for settings.
This commit is contained in:
@@ -1,479 +0,0 @@
|
||||
<abstract:MailAppShellAbstract
|
||||
x:Class="Wino.Views.MailAppShell"
|
||||
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:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||
xmlns:animations="using:CommunityToolkit.WinUI.Animations"
|
||||
xmlns:controls="using:Wino.Controls"
|
||||
xmlns:controls1="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
|
||||
xmlns:coreConverters="using:Wino.Mail.WinUI.Converters"
|
||||
xmlns:coreSelectors="using:Wino.Mail.WinUI.Selectors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:enums="using:Wino.Core.Domain.Enums"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:menu="using:Wino.Core.Domain.MenuItems"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
x:Name="Root"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
|
||||
<coreConverters:HexToColorBrushConverter x:Key="HexToColorBrushConverter" />
|
||||
|
||||
<!-- Clickable New Style Account Template -->
|
||||
<DataTemplate x:Key="ClickableAccountMenuTemplate" x:DataType="menu:AccountMenuItem">
|
||||
<controls:AccountNavigationItem
|
||||
x:Name="AccountItem"
|
||||
Height="50"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
BindingData="{x:Bind}"
|
||||
DataContext="{x:Bind}"
|
||||
IsActiveAccount="{x:Bind IsSelected, Mode=OneWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
SelectsOnInvoked="False"
|
||||
Style="{StaticResource SingleAccountNavigationViewItemTemplate}">
|
||||
<coreControls:WinoNavigationViewItem.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<EdgeUIThemeTransition Edge="Top" />
|
||||
</TransitionCollection>
|
||||
</coreControls:WinoNavigationViewItem.ContentTransitions>
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon
|
||||
FontSize="12"
|
||||
Foreground="{x:Bind AccountColorHex, Converter={StaticResource HexToColorBrushConverter}, Mode=OneWay}"
|
||||
Icon="{x:Bind helpers:XamlHelpers.GetProviderIcon(Parameter)}" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
<muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:InfoBadge
|
||||
Background="{ThemeResource SystemAccentColor}"
|
||||
Foreground="White"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(UnreadItemCount), Mode=OneWay}"
|
||||
Value="{x:Bind UnreadItemCount, Mode=OneWay}" />
|
||||
</muxc:NavigationViewItem.InfoBadge>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="AccountNameTextblock"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsSelected), Mode=OneWay}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind AccountName, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind Parameter.Address, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Converter={StaticResource ReverseBooleanToVisibilityConverter}, Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
x:Name="SyncStatusText"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind SynchronizationStatus, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
|
||||
<PathIcon
|
||||
x:Name="AttentionIcon"
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
x:Load="{x:Bind IsAttentionRequired, Mode=OneWay}"
|
||||
Data="F1 M 2.021484 18.769531 C 1.767578 18.769531 1.52832 18.720703 1.303711 18.623047 C 1.079102 18.525391 0.880534 18.391928 0.708008 18.222656 C 0.535482 18.053385 0.398763 17.856445 0.297852 17.631836 C 0.19694 17.407227 0.146484 17.167969 0.146484 16.914062 C 0.146484 16.614584 0.211589 16.328125 0.341797 16.054688 L 7.695312 1.347656 C 7.851562 1.035156 8.082682 0.784506 8.388672 0.595703 C 8.694661 0.406902 9.023438 0.3125 9.375 0.3125 C 9.726562 0.3125 10.055338 0.406902 10.361328 0.595703 C 10.667317 0.784506 10.898438 1.035156 11.054688 1.347656 L 18.408203 16.054688 C 18.53841 16.328125 18.603516 16.614584 18.603516 16.914062 C 18.603516 17.167969 18.553059 17.407227 18.452148 17.631836 C 18.351236 17.856445 18.216145 18.053385 18.046875 18.222656 C 17.877604 18.391928 17.679035 18.525391 17.451172 18.623047 C 17.223307 18.720703 16.982422 18.769531 16.728516 18.769531 Z M 16.728516 17.519531 C 16.884766 17.519531 17.027994 17.460938 17.158203 17.34375 C 17.28841 17.226562 17.353516 17.086588 17.353516 16.923828 C 17.353516 16.806641 17.330729 16.702475 17.285156 16.611328 L 9.931641 1.904297 C 9.879557 1.793621 9.80306 1.708984 9.702148 1.650391 C 9.601236 1.591797 9.492188 1.5625 9.375 1.5625 C 9.257812 1.5625 9.148763 1.593426 9.047852 1.655273 C 8.946939 1.717123 8.870442 1.800131 8.818359 1.904297 L 1.464844 16.611328 C 1.419271 16.702475 1.396484 16.803387 1.396484 16.914062 C 1.396484 17.083334 1.459961 17.226562 1.586914 17.34375 C 1.713867 17.460938 1.858724 17.519531 2.021484 17.519531 Z M 8.75 11.875 L 8.75 6.875 C 8.75 6.705729 8.811849 6.559245 8.935547 6.435547 C 9.059244 6.31185 9.205729 6.25 9.375 6.25 C 9.544271 6.25 9.690755 6.31185 9.814453 6.435547 C 9.93815 6.559245 10 6.705729 10 6.875 L 10 11.875 C 10 12.044271 9.93815 12.190756 9.814453 12.314453 C 9.690755 12.438151 9.544271 12.5 9.375 12.5 C 9.205729 12.5 9.059244 12.438151 8.935547 12.314453 C 8.811849 12.190756 8.75 12.044271 8.75 11.875 Z M 8.4375 14.375 C 8.4375 14.114584 8.528646 13.893229 8.710938 13.710938 C 8.893229 13.528646 9.114583 13.4375 9.375 13.4375 C 9.635416 13.4375 9.856771 13.528646 10.039062 13.710938 C 10.221354 13.893229 10.3125 14.114584 10.3125 14.375 C 10.3125 14.635417 10.221354 14.856771 10.039062 15.039062 C 9.856771 15.221354 9.635416 15.3125 9.375 15.3125 C 9.114583 15.3125 8.893229 15.221354 8.710938 15.039062 C 8.528646 14.856771 8.4375 14.635417 8.4375 14.375 Z "
|
||||
Foreground="{ThemeResource InfoBarWarningSeverityIconBackground}" />
|
||||
|
||||
<muxc:ProgressRing
|
||||
x:Name="SynchronizationProgressBar"
|
||||
Grid.Column="2"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsActive="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}"
|
||||
IsIndeterminate="{x:Bind IsProgressIndeterminate, Mode=OneWay}"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</controls:AccountNavigationItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Fix account issues. -->
|
||||
<!-- Authentication -->
|
||||
<DataTemplate x:Key="FixAuthenticationIssueTemplate" x:DataType="menu:FixAccountIssuesMenuItem">
|
||||
<coreControls:WinoNavigationViewItem SelectsOnInvoked="False">
|
||||
<coreControls:WinoNavigationViewItem.Content>
|
||||
<TextBlock
|
||||
Margin="0,10"
|
||||
Foreground="{ThemeResource InfoBarWarningSeverityIconBackground}"
|
||||
HorizontalTextAlignment="Center"
|
||||
TextWrapping="WrapWholeWords">
|
||||
<Run Text="Account credentials can not be verified." /><LineBreak /><Run Text="Click here to fix it." />
|
||||
</TextBlock>
|
||||
</coreControls:WinoNavigationViewItem.Content>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Missing system folder config. -->
|
||||
<DataTemplate x:Key="FixMissingFolderConfig" x:DataType="menu:FixAccountIssuesMenuItem">
|
||||
<coreControls:WinoNavigationViewItem SelectsOnInvoked="False">
|
||||
<coreControls:WinoNavigationViewItem.Content>
|
||||
<TextBlock
|
||||
Margin="0,10"
|
||||
Foreground="{ThemeResource InfoBarWarningSeverityIconBackground}"
|
||||
HorizontalTextAlignment="Center"
|
||||
TextWrapping="WrapWholeWords">
|
||||
<Run Text="Account is missing system folder configuration." /><LineBreak /><LineBreak /><Run Text="Click here to fix it." />
|
||||
</TextBlock>
|
||||
</coreControls:WinoNavigationViewItem.Content>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- New Mail -->
|
||||
<DataTemplate x:Key="CreateNewMailTemplate" x:DataType="menu:NewMailMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
Height="50"
|
||||
DataContext="{x:Bind}"
|
||||
SelectsOnInvoked="False">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon Icon="NewMail" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
<TextBlock
|
||||
Margin="0,-2,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Style="{StaticResource FlyoutPickerTitleTextBlockStyle}"
|
||||
Text="{x:Bind domain:Translator.MenuNewMail}" />
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Inbox or any other folders. -->
|
||||
<DataTemplate x:Key="FolderMenuTemplate" x:DataType="menu:FolderMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
MinHeight="40"
|
||||
AllowDrop="True"
|
||||
ContextRequested="MenuItemContextRequested"
|
||||
DataContext="{x:Bind}"
|
||||
DragEnter="ItemDragEnterOnFolder"
|
||||
DragLeave="ItemDragLeaveFromFolder"
|
||||
Drop="ItemDroppedOnFolder"
|
||||
FontSize="50"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsSelected), Mode=OneWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
IsSelected="{x:Bind IsSelected, Mode=TwoWay}"
|
||||
MenuItemsSource="{x:Bind SubMenuItems, Mode=OneWay}"
|
||||
SelectsOnInvoked="{x:Bind IsMoveTarget, Mode=OneWay}"
|
||||
ToolTipService.ToolTip="{x:Bind FolderName, Mode=OneWay}">
|
||||
<animations:Implicit.Animations>
|
||||
<animations:ScaleAnimation Duration="0:0:0.5" />
|
||||
</animations:Implicit.Animations>
|
||||
<coreControls:WinoNavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon FontSize="64" Icon="{x:Bind helpers:XamlHelpers.GetSpecialFolderPathIconGeometry(Parameter.SpecialFolderType)}" />
|
||||
</coreControls:WinoNavigationViewItem.Icon>
|
||||
<muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:InfoBadge
|
||||
x:Name="FolderInfoBadge"
|
||||
Background="{StaticResource SystemAccentColor}"
|
||||
Foreground="White"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(UnreadItemCount), Mode=OneWay}"
|
||||
Value="{x:Bind UnreadItemCount, Mode=OneWay}" />
|
||||
</muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:NavigationViewItem.Content>
|
||||
<Grid
|
||||
x:Name="FolderBackgroundGrid"
|
||||
MaxHeight="36"
|
||||
Padding="2"
|
||||
VerticalAlignment="Center">
|
||||
<Grid
|
||||
x:Name="BackgroundColorGrid"
|
||||
x:Load="{x:Bind HasTextColor, Mode=OneWay}"
|
||||
Background="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(Parameter.BackgroundColorHex), Mode=OneWay}"
|
||||
CornerRadius="3">
|
||||
<TextBlock
|
||||
x:Name="CustomColorTitle"
|
||||
Margin="4,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightBySyncState(IsSelected), Mode=OneWay}"
|
||||
Foreground="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(Parameter.TextColorHex), Mode=OneWay}"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind FolderName, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
x:Name="NormalTitle"
|
||||
VerticalAlignment="Center"
|
||||
x:Load="{x:Bind HasTextColor, Converter={StaticResource ReverseBooleanConverter}}"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightBySyncState(IsSelected), Mode=OneWay}"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind FolderName, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Grid>
|
||||
</muxc:NavigationViewItem.Content>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Merged Inbox -->
|
||||
<DataTemplate x:Key="MergedAccountTemplate" x:DataType="menu:MergedAccountMenuItem">
|
||||
<controls:AccountNavigationItem
|
||||
x:Name="AccountItem"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
BindingData="{x:Bind}"
|
||||
DataContext="{x:Bind}"
|
||||
IsActiveAccount="{x:Bind IsSelected, Mode=TwoWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
MenuItemsSource="{x:Bind SubMenuItems}"
|
||||
SelectsOnInvoked="False"
|
||||
Style="{StaticResource SingleAccountNavigationViewItemTemplate}">
|
||||
<muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:InfoBadge
|
||||
x:Name="FolderInfoBadge"
|
||||
Background="{StaticResource SystemAccentColor}"
|
||||
Foreground="White"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(UnreadItemCount), Mode=OneWay}"
|
||||
Value="{x:Bind UnreadItemCount, Mode=OneWay}" />
|
||||
</muxc:NavigationViewItem.InfoBadge>
|
||||
<coreControls:WinoNavigationViewItem.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<EdgeUIThemeTransition Edge="Top" />
|
||||
</TransitionCollection>
|
||||
</coreControls:WinoNavigationViewItem.ContentTransitions>
|
||||
<coreControls:WinoNavigationViewItem.Icon>
|
||||
<PathIcon Data="F1 M 8.613281 17.5 C 8.75 17.942709 8.945312 18.359375 9.199219 18.75 L 4.921875 18.75 C 4.433594 18.75 3.966471 18.650717 3.520508 18.452148 C 3.074544 18.25358 2.683919 17.986654 2.348633 17.651367 C 2.013346 17.31608 1.746419 16.925455 1.547852 16.479492 C 1.349284 16.033529 1.25 15.566406 1.25 15.078125 L 1.25 4.921875 C 1.25 4.433594 1.349284 3.966473 1.547852 3.520508 C 1.746419 3.074545 2.013346 2.68392 2.348633 2.348633 C 2.683919 2.013348 3.074544 1.74642 3.520508 1.547852 C 3.966471 1.349285 4.433594 1.25 4.921875 1.25 L 15.078125 1.25 C 15.566406 1.25 16.033527 1.349285 16.479492 1.547852 C 16.925455 1.74642 17.31608 2.013348 17.651367 2.348633 C 17.986652 2.68392 18.25358 3.074545 18.452148 3.520508 C 18.650715 3.966473 18.75 4.433594 18.75 4.921875 L 18.75 6.572266 C 18.580729 6.344402 18.390299 6.132813 18.178711 5.9375 C 17.967121 5.742188 17.740885 5.566407 17.5 5.410156 L 17.5 4.951172 C 17.5 4.625651 17.433268 4.314779 17.299805 4.018555 C 17.16634 3.722332 16.987305 3.461914 16.762695 3.237305 C 16.538086 3.012695 16.277668 2.83366 15.981445 2.700195 C 15.685221 2.566732 15.374349 2.5 15.048828 2.5 L 4.951172 2.5 C 4.619141 2.5 4.303385 2.568359 4.003906 2.705078 C 3.704427 2.841797 3.44401 3.02409 3.222656 3.251953 C 3.001302 3.479818 2.825521 3.745117 2.695312 4.047852 C 2.565104 4.350587 2.5 4.66797 2.5 5 L 13.310547 5 C 12.60091 5.266928 11.998697 5.683594 11.503906 6.25 L 2.5 6.25 L 2.5 15.048828 C 2.5 15.38737 2.568359 15.704753 2.705078 16.000977 C 2.841797 16.297201 3.024088 16.55599 3.251953 16.777344 C 3.479818 16.998697 3.745117 17.174479 4.047852 17.304688 C 4.350586 17.434896 4.667969 17.5 5 17.5 Z" />
|
||||
</coreControls:WinoNavigationViewItem.Icon>
|
||||
|
||||
<Grid Height="50">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel VerticalAlignment="Center" Spacing="0">
|
||||
<TextBlock
|
||||
x:Name="AccountNameTextblock"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsChildSelected), Mode=OneWay}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind MergedAccountName, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind SynchronizationStatus, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(IsSynchronizationProgressVisible), Mode=OneWay}">
|
||||
<Run Text="{x:Bind MergedAccountCount, Mode=OneWay}" /><Run Text="{x:Bind domain:Translator.MenuMergedAccountItemAccountsSuffix}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<muxc:ProgressRing
|
||||
x:Name="SynchronizationProgressBar"
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsActive="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}"
|
||||
IsIndeterminate="{x:Bind IsProgressIndeterminate, Mode=OneWay}"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</controls:AccountNavigationItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Merged Account Common Folder Item -->
|
||||
<DataTemplate x:Key="MergedAccountFolderMenuItemTemplate" x:DataType="menu:MergedAccountFolderMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
MinHeight="30"
|
||||
AllowDrop="True"
|
||||
ContextRequested="MenuItemContextRequested"
|
||||
DataContext="{x:Bind}"
|
||||
DragEnter="ItemDragEnterOnFolder"
|
||||
DragLeave="ItemDragLeaveFromFolder"
|
||||
Drop="ItemDroppedOnFolder"
|
||||
FontSize="50"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsSelected), Mode=OneWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
IsSelected="{x:Bind IsSelected, Mode=TwoWay}"
|
||||
SelectsOnInvoked="True"
|
||||
ToolTipService.ToolTip="{x:Bind FolderName, Mode=OneWay}">
|
||||
<animations:Implicit.Animations>
|
||||
<animations:ScaleAnimation Duration="0:0:0.5" />
|
||||
</animations:Implicit.Animations>
|
||||
<coreControls:WinoNavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon FontSize="64" Icon="{x:Bind helpers:XamlHelpers.GetSpecialFolderPathIconGeometry(FolderType)}" />
|
||||
</coreControls:WinoNavigationViewItem.Icon>
|
||||
<muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:InfoBadge
|
||||
x:Name="FolderInfoBadge"
|
||||
Background="{StaticResource SystemAccentColor}"
|
||||
Foreground="White"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(UnreadItemCount), Mode=OneWay}"
|
||||
Value="{x:Bind UnreadItemCount, Mode=OneWay}" />
|
||||
</muxc:NavigationViewItem.InfoBadge>
|
||||
<Grid
|
||||
x:Name="FolderBackgroundGrid"
|
||||
Padding="2"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="NormalTitle"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightBySyncState(IsSelected), Mode=OneWay}"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind FolderName, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Grid>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Merged Account More Expansion Item -->
|
||||
<DataTemplate x:Key="MergedAccountMoreFolderItemTemplate" x:DataType="menu:MergedAccountMoreFolderMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
MinHeight="30"
|
||||
Content="{x:Bind domain:Translator.More}"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsSelected), Mode=OneWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
IsSelected="{x:Bind IsSelected, Mode=TwoWay}"
|
||||
MenuItemsSource="{x:Bind SubMenuItems, Mode=OneWay}"
|
||||
SelectsOnInvoked="True">
|
||||
<animations:Implicit.Animations>
|
||||
<animations:ScaleAnimation Duration="0:0:0.5" />
|
||||
</animations:Implicit.Animations>
|
||||
<coreControls:WinoNavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon FontSize="64" Icon="{x:Bind helpers:XamlHelpers.GetSpecialFolderPathIconGeometry(enums:SpecialFolderType.More)}" />
|
||||
</coreControls:WinoNavigationViewItem.Icon>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<coreSelectors:NavigationMenuTemplateSelector
|
||||
x:Key="NavigationMenuTemplateSelector"
|
||||
ClickableAccountMenuTemplate="{StaticResource ClickableAccountMenuTemplate}"
|
||||
FixAuthenticationIssueTemplate="{StaticResource FixAuthenticationIssueTemplate}"
|
||||
FixMissingFolderConfigTemplate="{StaticResource FixMissingFolderConfig}"
|
||||
FolderMenuTemplate="{StaticResource FolderMenuTemplate}"
|
||||
MergedAccountFolderTemplate="{StaticResource MergedAccountFolderMenuItemTemplate}"
|
||||
MergedAccountMoreExpansionItemTemplate="{StaticResource MergedAccountMoreFolderItemTemplate}"
|
||||
MergedAccountTemplate="{StaticResource MergedAccountTemplate}"
|
||||
NewMailTemplate="{StaticResource CreateNewMailTemplate}"
|
||||
RatingItemTemplate="{StaticResource RatingItemTemplate}"
|
||||
SeperatorTemplate="{StaticResource SeperatorTemplate}"
|
||||
StoreUpdateItemTemplate="{StaticResource StoreUpdateItemTemplate}" />
|
||||
</Page.Resources>
|
||||
|
||||
<Grid
|
||||
x:Name="RootGrid"
|
||||
Padding="0"
|
||||
ColumnSpacing="0"
|
||||
RowSpacing="0">
|
||||
|
||||
<muxc:NavigationView
|
||||
x:Name="navigationView"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="-1,-1,0,0"
|
||||
Style="{StaticResource CalendarShellNavigationViewStyle}"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
AlwaysShowHeader="True"
|
||||
DisplayModeChanged="NavigationViewDisplayModeChanged"
|
||||
IsBackButtonVisible="Collapsed"
|
||||
IsPaneOpen="{x:Bind ViewModel.PreferencesService.IsNavigationPaneOpened, Mode=TwoWay}"
|
||||
IsPaneToggleButtonVisible="False"
|
||||
IsSettingsVisible="False"
|
||||
IsTabStop="True"
|
||||
IsTitleBarAutoPaddingEnabled="False"
|
||||
ItemInvoked="NavigationViewItemInvoked"
|
||||
MenuItemTemplateSelector="{StaticResource NavigationMenuTemplateSelector}"
|
||||
MenuItemsSource="{x:Bind ViewModel.MenuItems, Mode=OneWay}"
|
||||
OpenPaneLength="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=TwoWay}"
|
||||
PaneDisplayMode="Auto"
|
||||
PaneOpening="NavigationPaneOpening"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Hidden"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedMenuItem, Mode=TwoWay}"
|
||||
SelectionChanged="MenuSelectionChanged">
|
||||
<muxc:NavigationView.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<AddDeleteThemeTransition />
|
||||
</TransitionCollection>
|
||||
</muxc:NavigationView.ContentTransitions>
|
||||
<Grid ColumnSpacing="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<controls1:PropertySizer
|
||||
Width="1"
|
||||
HorizontalAlignment="Left"
|
||||
Background="Transparent"
|
||||
Binding="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=TwoWay}"
|
||||
Canvas.ZIndex="20"
|
||||
Foreground="Transparent"
|
||||
IsHitTestVisible="{x:Bind navigationView.IsPaneOpen, Mode=OneWay}"
|
||||
IsTabStop="False"
|
||||
Maximum="1000"
|
||||
Minimum="116" />
|
||||
|
||||
<!-- Main Content -->
|
||||
<Frame
|
||||
x:Name="InnerShellFrame"
|
||||
Padding="0,0,7,7"
|
||||
IsNavigationStackEnabled="False"
|
||||
Navigated="ShellFrameContentNavigated">
|
||||
<Frame.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<PopupThemeTransition />
|
||||
</TransitionCollection>
|
||||
</Frame.ContentTransitions>
|
||||
</Frame>
|
||||
|
||||
<!-- InfoBar -->
|
||||
<coreControls:WinoInfoBar
|
||||
x:Name="ShellInfoBar"
|
||||
MaxWidth="700"
|
||||
Margin="0,60,25,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
IsClosable="False"
|
||||
IsOpen="False" />
|
||||
|
||||
<!-- Teaching Tip -->
|
||||
<muxc:TeachingTip
|
||||
x:Name="ShellTip"
|
||||
IsOpen="False"
|
||||
PreferredPlacement="Bottom"
|
||||
Target="{x:Bind ShellInfoBar}" />
|
||||
</Grid>
|
||||
</muxc:NavigationView>
|
||||
|
||||
</Grid>
|
||||
</abstract:MailAppShellAbstract>
|
||||
|
||||
|
||||
@@ -1,432 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Windows.Foundation;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Mail.WinUI;
|
||||
using Wino.Mail.WinUI.Controls;
|
||||
using Wino.MenuFlyouts;
|
||||
using Wino.MenuFlyouts.Context;
|
||||
using Wino.Messaging.Client.Accounts;
|
||||
using Wino.Messaging.Client.Mails;
|
||||
using Wino.Messaging.Client.Shell;
|
||||
using Wino.Messaging.UI;
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views;
|
||||
|
||||
public sealed partial class MailAppShell : MailAppShellAbstract,
|
||||
IRecipient<AccountMenuItemExtended>,
|
||||
IRecipient<NavigateMailFolderEvent>,
|
||||
IRecipient<CreateNewMailWithMultipleAccountsRequested>
|
||||
{
|
||||
public Frame GetShellFrame() => InnerShellFrame;
|
||||
|
||||
[GeneratedDependencyProperty]
|
||||
public partial UIElement? TopShellContent { get; set; }
|
||||
|
||||
public MailAppShell() : base()
|
||||
{
|
||||
InitializeComponent();
|
||||
PreviewKeyDown += OnPreviewKeyDown;
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedFrom(e);
|
||||
|
||||
Bindings.StopTracking();
|
||||
}
|
||||
|
||||
private async void ItemDroppedOnFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
// Validate package content.
|
||||
if (sender is WinoNavigationViewItem droppedContainer)
|
||||
{
|
||||
droppedContainer.IsDraggingItemOver = false;
|
||||
|
||||
if (CanContinueDragDrop(droppedContainer, e))
|
||||
{
|
||||
if (droppedContainer.DataContext is IBaseFolderMenuItem draggingFolder)
|
||||
{
|
||||
var dragPackage = e.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage;
|
||||
|
||||
if (dragPackage == null) return;
|
||||
|
||||
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
||||
var mailCopies = ExtractMailCopies(dragPackage).ToList();
|
||||
|
||||
await ViewModel.PerformMoveOperationAsync(mailCopies, draggingFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ItemDragLeaveFromFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
if (sender is WinoNavigationViewItem leavingContainer)
|
||||
{
|
||||
leavingContainer.IsDraggingItemOver = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanContinueDragDrop(WinoNavigationViewItem interactingContainer, DragEventArgs args)
|
||||
{
|
||||
// TODO: Maybe override caption with some information why the validation failed?
|
||||
// Note: Caption has a max length. It may be trimmed in some languages.
|
||||
|
||||
if (interactingContainer == null || !args.DataView.Properties.ContainsKey(nameof(MailDragPackage))) return false;
|
||||
|
||||
var dragPackage = args.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage;
|
||||
|
||||
// Invalid package.
|
||||
if (dragPackage == null || !dragPackage.DraggingMails.Any()) return false;
|
||||
|
||||
// Check whether source and target folder are the same.
|
||||
if (interactingContainer.IsSelected) return false;
|
||||
|
||||
// Check if the interacting container is a folder.
|
||||
if (!(interactingContainer.DataContext is IBaseFolderMenuItem folderMenuItem)) return false;
|
||||
|
||||
// Check if the folder is a move target.
|
||||
if (!folderMenuItem.IsMoveTarget) return false;
|
||||
|
||||
// Check whether the moving item's account has at least one same as the target folder's account.
|
||||
var draggedAccountIds = folderMenuItem.HandlingFolders.Select(a => a.MailAccountId);
|
||||
|
||||
var draggedMails = ExtractMailCopies(dragPackage);
|
||||
|
||||
if (!draggedMails.Any()) return false;
|
||||
if (!draggedMails.Any(a => draggedAccountIds.Contains(a.AssignedAccount.Id))) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static IEnumerable<MailCopy> ExtractMailCopies(MailDragPackage dragPackage)
|
||||
{
|
||||
foreach (var item in dragPackage.DraggingMails)
|
||||
{
|
||||
if (item is MailCopy mailCopy)
|
||||
{
|
||||
yield return mailCopy;
|
||||
}
|
||||
else if (item is MailItemViewModel singleMailItemViewModel)
|
||||
{
|
||||
yield return singleMailItemViewModel.MailCopy;
|
||||
}
|
||||
else if (item is ThreadMailItemViewModel threadViewModel)
|
||||
{
|
||||
foreach (var threadMail in threadViewModel.ThreadEmails)
|
||||
{
|
||||
yield return threadMail.MailCopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ItemDragEnterOnFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
// Validate package content.
|
||||
if (sender is WinoNavigationViewItem droppedContainer && CanContinueDragDrop(droppedContainer, e))
|
||||
{
|
||||
droppedContainer.IsDraggingItemOver = true;
|
||||
|
||||
var draggingFolder = droppedContainer.DataContext as IBaseFolderMenuItem;
|
||||
|
||||
if (draggingFolder == null) return;
|
||||
|
||||
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
||||
e.DragUIOverride.Caption = string.Format(Translator.DragMoveToFolderCaption, draggingFolder.FolderName);
|
||||
}
|
||||
}
|
||||
|
||||
public async void Receive(AccountMenuItemExtended message)
|
||||
{
|
||||
await DispatcherQueue.EnqueueAsync(async () =>
|
||||
{
|
||||
if (message.FolderId == default) return;
|
||||
|
||||
if (ViewModel.MenuItems.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem foundMenuItem))
|
||||
{
|
||||
foundMenuItem.Expand();
|
||||
|
||||
await ViewModel.NavigateFolderAsync(foundMenuItem);
|
||||
|
||||
navigationView.SelectedItem = foundMenuItem;
|
||||
|
||||
if (message.NavigateMailItem == null) return;
|
||||
|
||||
// At this point folder is navigated and items are loaded.
|
||||
WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId, ScrollToItem: true));
|
||||
}
|
||||
else if (ViewModel.MenuItems.TryGetAccountMenuItem(message.NavigateMailItem.AssignedAccount.Id, out IAccountMenuItem accountMenuItem))
|
||||
{
|
||||
// Loaded account is different. First change the folder items and navigate.
|
||||
|
||||
await ViewModel.ChangeLoadedAccountAsync(accountMenuItem, navigateInbox: false);
|
||||
|
||||
// Find the folder.
|
||||
|
||||
if (ViewModel.MenuItems.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem accountFolderMenuItem))
|
||||
{
|
||||
accountFolderMenuItem.Expand();
|
||||
|
||||
await ViewModel.NavigateFolderAsync(accountFolderMenuItem);
|
||||
|
||||
navigationView.SelectedItem = accountFolderMenuItem;
|
||||
|
||||
// At this point folder is navigated and items are loaded.
|
||||
WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId, ScrollToItem: true));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async void MenuSelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args)
|
||||
{
|
||||
if (args.SelectedItem is IMenuItem invokedMenuItem)
|
||||
{
|
||||
await ViewModel.MenuItemInvokedOrSelectedAsync(invokedMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
private async void NavigationViewItemInvoked(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args)
|
||||
{
|
||||
// SelectsOnInvoked is handled in MenuSelectionChanged.
|
||||
// This part is only for the items that are not selectable.
|
||||
if (args.InvokedItemContainer is WinoNavigationViewItem winoNavigationViewItem)
|
||||
{
|
||||
if (winoNavigationViewItem.SelectsOnInvoked) return;
|
||||
|
||||
await ViewModel.MenuItemInvokedOrSelectedAsync(winoNavigationViewItem.DataContext as IMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(NavigateMailFolderEvent message)
|
||||
{
|
||||
if (message.BaseFolderMenuItem == null) return;
|
||||
|
||||
if (navigationView.SelectedItem != message.BaseFolderMenuItem)
|
||||
{
|
||||
var navigateFolderArgs = new NavigateMailFolderEventArgs(message.BaseFolderMenuItem, message.FolderInitLoadAwaitTask);
|
||||
|
||||
ViewModel.NavigationService.Navigate(WinoPage.MailListPage, navigateFolderArgs, NavigationReferenceFrame.InnerShellFrame);
|
||||
|
||||
// Prevent double navigation.
|
||||
navigationView.SelectionChanged -= MenuSelectionChanged;
|
||||
navigationView.SelectedItem = message.BaseFolderMenuItem;
|
||||
navigationView.SelectionChanged += MenuSelectionChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Complete the init task since we are already on the right page.
|
||||
message.FolderInitLoadAwaitTask?.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShellFrameContentNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e) => TopShellContent = ((BasePage)e.Content).ShellContent;
|
||||
|
||||
partial void OnTopShellContentChanged(UIElement? newValue) => WeakReferenceMessenger.Default.Send(new TitleBarShellContentUpdated());
|
||||
|
||||
private async void MenuItemContextRequested(UIElement sender, ContextRequestedEventArgs args)
|
||||
{
|
||||
// Delegate this request to ViewModel.
|
||||
// VM will prepare available actions for this folder and show Menu Flyout.
|
||||
|
||||
if (sender is WinoNavigationViewItem menuItem &&
|
||||
menuItem.DataContext is IBaseFolderMenuItem baseFolderMenuItem &&
|
||||
baseFolderMenuItem.IsMoveTarget &&
|
||||
args.TryGetPosition(sender, out Point p))
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
var source = new TaskCompletionSource<FolderOperationMenuItem>();
|
||||
|
||||
var actions = ViewModel.GetFolderContextMenuActions(baseFolderMenuItem);
|
||||
var flyout = new FolderOperationFlyout(actions, source);
|
||||
|
||||
flyout.ShowAt(menuItem, new FlyoutShowOptions()
|
||||
{
|
||||
ShowMode = FlyoutShowMode.Standard,
|
||||
Position = new Point(p.X + 30, p.Y - 20)
|
||||
});
|
||||
|
||||
var operation = await source.Task;
|
||||
|
||||
flyout.Dispose();
|
||||
|
||||
// No action selected.
|
||||
if (operation == null) return;
|
||||
|
||||
await ViewModel.PerformFolderOperationAsync(operation.Operation, baseFolderMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(CreateNewMailWithMultipleAccountsRequested message)
|
||||
{
|
||||
// Find the NewMail menu item container.
|
||||
|
||||
var container = navigationView.ContainerFromMenuItem(ViewModel.CreateMailMenuItem);
|
||||
|
||||
var flyout = new AccountSelectorFlyout(message.AllAccounts, ViewModel.CreateNewMailForAsync);
|
||||
|
||||
flyout.ShowAt(container, new FlyoutShowOptions()
|
||||
{
|
||||
ShowMode = FlyoutShowMode.Auto,
|
||||
Placement = FlyoutPlacementMode.Right
|
||||
});
|
||||
}
|
||||
|
||||
private void NavigationPaneOpening(Microsoft.UI.Xaml.Controls.NavigationView sender, object args)
|
||||
{
|
||||
// It's annoying that NavigationView doesn't respect expansion state of the items in Minimal display mode.
|
||||
// Expanded items are collaped, and users need to expand them again.
|
||||
// Regardless of the reason, we will expand the selected item if it's a folder with parent account for visibility.
|
||||
|
||||
if (sender.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Minimal && sender.SelectedItem is IFolderMenuItem selectedFolderMenuItem)
|
||||
{
|
||||
selectedFolderMenuItem.Expand();
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigationViewDisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args)
|
||||
{
|
||||
if (args.DisplayMode == NavigationViewDisplayMode.Minimal)
|
||||
{
|
||||
InnerShellFrame.Margin = new Thickness(7, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
InnerShellFrame.Margin = new Thickness(0);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnPreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
if (e.KeyStatus.RepeatCount > 1 || ShouldIgnoreShortcut())
|
||||
return;
|
||||
|
||||
var key = NormalizeKey(e.Key);
|
||||
if (string.IsNullOrEmpty(key))
|
||||
return;
|
||||
|
||||
var shortcutService = WinoApplication.Current.Services.GetRequiredService<IKeyboardShortcutService>();
|
||||
var shortcut = await shortcutService.GetShortcutForKeyAsync(WinoApplicationMode.Mail, key, GetCurrentModifierKeys());
|
||||
|
||||
if (shortcut == null)
|
||||
return;
|
||||
|
||||
var details = new KeyboardShortcutTriggerDetails
|
||||
{
|
||||
ShortcutId = shortcut.Id,
|
||||
Mode = shortcut.Mode,
|
||||
Action = shortcut.Action,
|
||||
Key = shortcut.Key,
|
||||
ModifierKeys = shortcut.ModifierKeys,
|
||||
Sender = sender,
|
||||
Origin = FocusManager.GetFocusedElement(XamlRoot)
|
||||
};
|
||||
|
||||
await ViewModel.KeyboardShortcutHook(details);
|
||||
|
||||
if (InnerShellFrame.Content is BasePage activePage && activePage.AssociatedViewModel != null)
|
||||
{
|
||||
await activePage.AssociatedViewModel.KeyboardShortcutHook(details);
|
||||
}
|
||||
|
||||
if (details.Handled)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldIgnoreShortcut()
|
||||
{
|
||||
var focusedElement = FocusManager.GetFocusedElement(XamlRoot);
|
||||
|
||||
if (focusedElement is TextBox or AutoSuggestBox or PasswordBox or RichEditBox or ComboBox)
|
||||
return true;
|
||||
|
||||
if (focusedElement is FrameworkElement frameworkElement)
|
||||
{
|
||||
var typeName = frameworkElement.GetType().Name;
|
||||
if (typeName.Contains("WebView", StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static ModifierKeys GetCurrentModifierKeys()
|
||||
{
|
||||
var modifiers = ModifierKeys.None;
|
||||
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Control).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
modifiers |= ModifierKeys.Control;
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Menu).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
modifiers |= ModifierKeys.Alt;
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Shift).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
modifiers |= ModifierKeys.Shift;
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.LeftWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down) ||
|
||||
Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.RightWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
{
|
||||
modifiers |= ModifierKeys.Windows;
|
||||
}
|
||||
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
private static string NormalizeKey(Windows.System.VirtualKey key)
|
||||
{
|
||||
return key switch
|
||||
{
|
||||
Windows.System.VirtualKey.Control or
|
||||
Windows.System.VirtualKey.LeftControl or
|
||||
Windows.System.VirtualKey.RightControl or
|
||||
Windows.System.VirtualKey.Menu or
|
||||
Windows.System.VirtualKey.LeftMenu or
|
||||
Windows.System.VirtualKey.RightMenu or
|
||||
Windows.System.VirtualKey.Shift or
|
||||
Windows.System.VirtualKey.LeftShift or
|
||||
Windows.System.VirtualKey.RightShift or
|
||||
Windows.System.VirtualKey.LeftWindows or
|
||||
Windows.System.VirtualKey.RightWindows => string.Empty,
|
||||
_ => key.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<AccountMenuItemExtended>(this);
|
||||
WeakReferenceMessenger.Default.Register<CreateNewMailWithMultipleAccountsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigateMailFolderEvent>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<AccountMenuItemExtended>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<CreateNewMailWithMultipleAccountsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<NavigateMailFolderEvent>(this);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Wino.Calendar.ViewModels;
|
||||
using Wino.Mail.WinUI;
|
||||
|
||||
namespace Wino.Mail.Views.Abstract;
|
||||
|
||||
public abstract class CalendarAppShellAbstract : BasePage<CalendarAppShellViewModel>
|
||||
{
|
||||
protected CalendarAppShellAbstract()
|
||||
{
|
||||
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Disabled;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
using Wino.Mail.WinUI;
|
||||
|
||||
namespace Wino.Views.Abstract;
|
||||
|
||||
public abstract class MailAppShellAbstract : BasePage<MailAppShellViewModel>
|
||||
{
|
||||
protected MailAppShellAbstract()
|
||||
{
|
||||
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Disabled;
|
||||
}
|
||||
}
|
||||
@@ -1,308 +0,0 @@
|
||||
<abstract:CalendarAppShellAbstract
|
||||
x:Class="Wino.Mail.WinUI.Views.Calendar.CalendarAppShell"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:abstract="using:Wino.Mail.Views.Abstract"
|
||||
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||
xmlns:animations="using:CommunityToolkit.WinUI.Animations"
|
||||
xmlns:calendarControls="using:Wino.Calendar.Controls"
|
||||
xmlns:communityControls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
|
||||
xmlns:coreSelectors="using:Wino.Mail.WinUI.Selectors"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:data="using:Wino.Calendar.ViewModels.Data"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:local="using:Wino.Calendar.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:menu="using:Wino.Core.Domain.MenuItems"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
Loaded="OnLoaded"
|
||||
PreviewKeyDown="OnPreviewKeyDown"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<DataTemplate x:Key="CalendarSettingsItemTemplate" x:DataType="menu:SettingsItem">
|
||||
<coreControls:WinoNavigationViewItem DataContext="{x:Bind}" SelectsOnInvoked="False">
|
||||
<coreControls:WinoNavigationViewItem.Icon>
|
||||
<muxc:AnimatedIcon>
|
||||
<muxc:AnimatedIcon.Source>
|
||||
<animatedvisuals:AnimatedSettingsVisualSource />
|
||||
</muxc:AnimatedIcon.Source>
|
||||
<muxc:AnimatedIcon.FallbackIconSource>
|
||||
<muxc:SymbolIconSource Symbol="Setting" />
|
||||
</muxc:AnimatedIcon.FallbackIconSource>
|
||||
</muxc:AnimatedIcon>
|
||||
</coreControls:WinoNavigationViewItem.Icon>
|
||||
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.MenuSettings}" />
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="CalendarStoreUpdateItemTemplate" x:DataType="menu:StoreUpdateMenuItem">
|
||||
<coreControls:WinoNavigationViewItem DataContext="{x:Bind}" SelectsOnInvoked="False">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
<TextBlock VerticalAlignment="Center" Text="{x:Bind domain:Translator.MenuUpdateAvailable}" />
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<coreSelectors:NavigationMenuTemplateSelector
|
||||
x:Key="NavigationMenuTemplateSelector"
|
||||
RatingItemTemplate="{StaticResource RatingItemTemplate}"
|
||||
SeperatorTemplate="{StaticResource SeperatorTemplate}" />
|
||||
|
||||
<Style
|
||||
x:Key="CalendarNavigationButtonStyle"
|
||||
BasedOn="{StaticResource DefaultButtonStyle}"
|
||||
TargetType="Button">
|
||||
<Setter Property="Margin" Value="0,4,0,0" />
|
||||
<Setter Property="Padding" Value="8,4,8,6" />
|
||||
<Setter Property="CornerRadius" Value="6" />
|
||||
<Setter Property="Width" Value="40" />
|
||||
</Style>
|
||||
</Page.Resources>
|
||||
|
||||
<Grid
|
||||
x:Name="RootGrid"
|
||||
Padding="0"
|
||||
ColumnSpacing="0"
|
||||
RowSpacing="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="48" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
||||
<Grid
|
||||
Grid.ColumnSpan="2"
|
||||
Background="{ThemeResource WinoApplicationBackgroundColor}"
|
||||
IsHitTestVisible="False">
|
||||
<Grid.BackgroundTransition>
|
||||
<BrushTransition />
|
||||
</Grid.BackgroundTransition>
|
||||
</Grid>
|
||||
|
||||
<muxc:NavigationView
|
||||
x:Name="navigationView"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
Background="Transparent"
|
||||
DisplayModeChanged="NavigationViewDisplayModeChanged"
|
||||
IsBackButtonVisible="Collapsed"
|
||||
IsPaneOpen="{x:Bind ViewModel.PreferencesService.IsNavigationPaneOpened, Mode=TwoWay}"
|
||||
IsPaneToggleButtonVisible="False"
|
||||
IsSettingsVisible="False"
|
||||
IsTitleBarAutoPaddingEnabled="False"
|
||||
ItemInvoked="NavigationViewItemInvoked"
|
||||
MenuItemTemplateSelector="{StaticResource NavigationMenuTemplateSelector}"
|
||||
MenuItemsSource="{x:Bind ViewModel.MenuItems, Mode=OneWay}"
|
||||
OpenPaneLength="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=TwoWay}"
|
||||
PaneClosed="NavigationPaneClosed"
|
||||
PaneDisplayMode="Auto"
|
||||
PaneOpened="NavigationPaneOpened"
|
||||
Style="{StaticResource CalendarShellNavigationViewStyle}">
|
||||
<muxc:NavigationView.PaneCustomContent>
|
||||
<Grid x:Name="PaneCustomContent" Padding="0,0,0,6">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<coreControls:WinoNavigationViewItem
|
||||
x:Name="NewCalendarEventNavigationItem"
|
||||
Grid.Row="0"
|
||||
Height="50"
|
||||
Margin="0,0,0,12"
|
||||
AutomationProperties.Name="{x:Bind domain:Translator.CalendarEventCompose_NewEventButton, Mode=OneTime}"
|
||||
IsTabStop="True"
|
||||
KeyDown="NewCalendarEventNavigationItemKeyDown"
|
||||
SelectsOnInvoked="False"
|
||||
Tapped="NewCalendarEventNavigationItemTapped">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon Icon="NewMail" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
<TextBlock
|
||||
Margin="0,-2,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Style="{StaticResource FlyoutPickerTitleTextBlockStyle}"
|
||||
Text="{x:Bind domain:Translator.CalendarEventCompose_NewEventButton, Mode=OneTime}" />
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
|
||||
<Border
|
||||
x:Name="RangeSummaryCard"
|
||||
Grid.Row="1"
|
||||
Margin="16,0,16,12"
|
||||
Padding="12"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8">
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock
|
||||
FontWeight="SemiBold"
|
||||
Text="{x:Bind ViewModel.VisibleDateRangeText, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
|
||||
<muxc:CalendarView
|
||||
x:Name="VisibleDateRangeCalendarView"
|
||||
HorizontalAlignment="Stretch"
|
||||
SelectionMode="Multiple"
|
||||
SelectedDatesChanged="VisibleDateRangeCalendarViewSelectedDatesChanged" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Account Calendars Host -->
|
||||
<ListView
|
||||
x:Name="CalendarHostListView"
|
||||
Grid.Row="2"
|
||||
ItemsSource="{x:Bind ViewModel.AccountCalendarStateService.GroupedAccountCalendars}"
|
||||
SelectionMode="None">
|
||||
<ListView.Header>
|
||||
<TextBlock
|
||||
Margin="20,12,12,12"
|
||||
FontSize="16"
|
||||
Text="Calendars" />
|
||||
</ListView.Header>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="data:GroupedAccountCalendarViewModel">
|
||||
<muxc:Expander
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}">
|
||||
<muxc:Expander.Header>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox
|
||||
Width="26"
|
||||
MinWidth="0"
|
||||
IsChecked="{x:Bind IsCheckedState, Mode=TwoWay}"
|
||||
IsThreeState="True" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap">
|
||||
<Run FontWeight="SemiBold" Text="{x:Bind Account.Name}" />
|
||||
<Run FontSize="12" Text="(" /><Run FontSize="12" Text="{x:Bind Account.Address}" /><Run FontSize="12" Text=")" />
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</muxc:Expander.Header>
|
||||
<muxc:Expander.Content>
|
||||
<ItemsControl ItemsSource="{x:Bind AccountCalendars}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="data:AccountCalendarViewModel">
|
||||
<CheckBox
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
IsChecked="{x:Bind IsChecked, Mode=TwoWay}">
|
||||
<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>
|
||||
</CheckBox>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</muxc:Expander.Content>
|
||||
</muxc:Expander>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</muxc:NavigationView.PaneCustomContent>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Main Content -->
|
||||
<Frame
|
||||
x:Name="InnerShellFrame"
|
||||
Padding="0,0,7,7"
|
||||
CacheSize="0"
|
||||
IsNavigationStackEnabled="True">
|
||||
<Frame.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<PopupThemeTransition />
|
||||
</TransitionCollection>
|
||||
</Frame.ContentTransitions>
|
||||
</Frame>
|
||||
|
||||
<!-- InfoBar -->
|
||||
<coreControls:WinoInfoBar
|
||||
x:Name="ShellInfoBar"
|
||||
MaxWidth="700"
|
||||
Margin="0,60,25,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
IsClosable="False"
|
||||
IsOpen="False" />
|
||||
</Grid>
|
||||
</muxc:NavigationView>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="LowResolutionStates">
|
||||
<VisualState x:Name="BigScreen">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="1200" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="navigationView.IsPaneOpen" Value="True" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="SmallScreen">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="navigationView.IsPaneOpen" Value="False" />
|
||||
</VisualState.Setters>
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="0" />
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
|
||||
<VisualStateGroup x:Name="CalendarOrientationStates">
|
||||
<VisualState x:Name="HorizontalCalendar" />
|
||||
<VisualState x:Name="VerticalCalendar" />
|
||||
</VisualStateGroup>
|
||||
|
||||
<VisualStateGroup x:Name="ShellStateContentGroup">
|
||||
<VisualState x:Name="DefaultShellContentState" />
|
||||
<VisualState x:Name="EventDetailsContentState">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="RangeSummaryCard.IsEnabled" Value="False" />
|
||||
<Setter Target="CalendarHostListView.IsEnabled" Value="False" />
|
||||
</VisualState.Setters>
|
||||
<VisualState.StateTriggers>
|
||||
<StateTrigger IsActive="{x:Bind ViewModel.StatePersistenceService.IsEventDetailsVisible, Mode=OneWay}" />
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</abstract:CalendarAppShellAbstract>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.MenuItems;
|
||||
using Wino.Core.Domain.Models;
|
||||
using Wino.Core.Domain.Models.Calendar;
|
||||
using Wino.Mail.Views.Abstract;
|
||||
using Wino.Messaging.Client.Calendar;
|
||||
using Windows.System;
|
||||
|
||||
namespace Wino.Mail.WinUI.Views.Calendar;
|
||||
|
||||
public sealed partial class CalendarAppShell : CalendarAppShellAbstract,
|
||||
IRecipient<CalendarDisplayTypeChangedMessage>
|
||||
{
|
||||
private const string STATE_HorizontalCalendar = "HorizontalCalendar";
|
||||
private const string STATE_VerticalCalendar = "VerticalCalendar";
|
||||
private bool _isSynchronizingVisibleDateRangeCalendar;
|
||||
|
||||
public Frame GetShellFrame() => InnerShellFrame;
|
||||
|
||||
public CalendarAppShell()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
ViewModel.PropertyChanged += ViewModelPropertyChanged;
|
||||
ManageCalendarDisplayType(ViewModel.StatePersistenceService.CalendarDisplayType);
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateNavigationPaneLayout(navigationView.DisplayMode);
|
||||
SynchronizeVisibleDateRangeCalendar();
|
||||
}
|
||||
|
||||
private void ManageCalendarDisplayType(Core.Domain.Enums.CalendarDisplayType displayType)
|
||||
{
|
||||
if (displayType == Core.Domain.Enums.CalendarDisplayType.Month)
|
||||
{
|
||||
VisualStateManager.GoToState(this, STATE_VerticalCalendar, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManager.GoToState(this, STATE_HorizontalCalendar, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void PreviousDateClicked(object sender, RoutedEventArgs e)
|
||||
=> ViewModel.PreviousDateRangeCommand.Execute(null);
|
||||
|
||||
private void NextDateClicked(object sender, RoutedEventArgs e)
|
||||
=> ViewModel.NextDateRangeCommand.Execute(null);
|
||||
|
||||
private async void NewCalendarEventNavigationItemTapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
await InvokeNewCalendarEventAsync();
|
||||
}
|
||||
|
||||
private void VisibleDateRangeCalendarViewSelectedDatesChanged(CalendarView sender, CalendarViewSelectedDatesChangedEventArgs args)
|
||||
{
|
||||
if (_isSynchronizingVisibleDateRangeCalendar)
|
||||
return;
|
||||
|
||||
DateTimeOffset? interactedDate = null;
|
||||
|
||||
if (args.AddedDates.Count > 0)
|
||||
{
|
||||
interactedDate = args.AddedDates[0];
|
||||
}
|
||||
else if (args.RemovedDates.Count > 0)
|
||||
{
|
||||
interactedDate = args.RemovedDates[0];
|
||||
}
|
||||
|
||||
if (interactedDate is null)
|
||||
return;
|
||||
|
||||
var clickedArgs = new CalendarViewDayClickedEventArgs(interactedDate.Value.DateTime);
|
||||
|
||||
if (ViewModel.DateClickedCommand.CanExecute(clickedArgs))
|
||||
{
|
||||
ViewModel.DateClickedCommand.Execute(clickedArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private async void NewCalendarEventNavigationItemKeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
if (e.Key is not (VirtualKey.Enter or VirtualKey.Space))
|
||||
return;
|
||||
|
||||
e.Handled = true;
|
||||
await InvokeNewCalendarEventAsync();
|
||||
}
|
||||
|
||||
private async void NavigationViewItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
|
||||
{
|
||||
if (args.InvokedItemContainer is FrameworkElement { DataContext: IMenuItem menuItem })
|
||||
{
|
||||
await ViewModel.HandleNavigationItemInvokedAsync(menuItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigationViewDisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args)
|
||||
=> UpdateNavigationPaneLayout(args.DisplayMode);
|
||||
|
||||
private void NavigationPaneOpened(NavigationView sender, object args)
|
||||
=> UpdateNavigationPaneLayout(sender.DisplayMode);
|
||||
|
||||
private void NavigationPaneClosed(NavigationView sender, object args)
|
||||
=> UpdateNavigationPaneLayout(sender.DisplayMode);
|
||||
|
||||
private Task InvokeNewCalendarEventAsync()
|
||||
=> ViewModel.HandleNavigationItemInvokedAsync(new NewCalendarEventMenuItem());
|
||||
|
||||
private void UpdateNavigationPaneLayout(NavigationViewDisplayMode displayMode)
|
||||
{
|
||||
var paneContentVisibility = displayMode == NavigationViewDisplayMode.Expanded && navigationView.IsPaneOpen
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
|
||||
PaneCustomContent.Visibility = paneContentVisibility;
|
||||
|
||||
Debug.WriteLine($"NavigationView display mode changed to {displayMode}. Pane custom content visibility set to {paneContentVisibility}.");
|
||||
}
|
||||
|
||||
public void Receive(CalendarDisplayTypeChangedMessage message)
|
||||
{
|
||||
ManageCalendarDisplayType(message.NewDisplayType);
|
||||
SynchronizeVisibleDateRangeCalendar();
|
||||
}
|
||||
|
||||
private void ViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName is nameof(ViewModel.CurrentVisibleRange) or nameof(ViewModel.VisibleDateRangeText))
|
||||
{
|
||||
SynchronizeVisibleDateRangeCalendar();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedFrom(e);
|
||||
|
||||
InnerShellFrame.BackStack.Clear();
|
||||
InnerShellFrame.ForwardStack.Clear();
|
||||
|
||||
if (InnerShellFrame.Content is IDisposable disposableContent)
|
||||
{
|
||||
disposableContent.Dispose();
|
||||
}
|
||||
|
||||
Bindings.StopTracking();
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<CalendarDisplayTypeChangedMessage>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<CalendarDisplayTypeChangedMessage>(this);
|
||||
}
|
||||
|
||||
private async void OnPreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
if (e.KeyStatus.RepeatCount > 1 || ShouldIgnoreShortcut())
|
||||
return;
|
||||
|
||||
var key = NormalizeKey(e.Key);
|
||||
if (string.IsNullOrEmpty(key))
|
||||
return;
|
||||
|
||||
var shortcutService = WinoApplication.Current.Services.GetRequiredService<IKeyboardShortcutService>();
|
||||
var shortcut = await shortcutService.GetShortcutForKeyAsync(WinoApplicationMode.Calendar, key, GetCurrentModifierKeys());
|
||||
|
||||
if (shortcut == null)
|
||||
return;
|
||||
|
||||
var details = new KeyboardShortcutTriggerDetails
|
||||
{
|
||||
ShortcutId = shortcut.Id,
|
||||
Mode = shortcut.Mode,
|
||||
Action = shortcut.Action,
|
||||
Key = shortcut.Key,
|
||||
ModifierKeys = shortcut.ModifierKeys,
|
||||
Sender = sender,
|
||||
Origin = FocusManager.GetFocusedElement(XamlRoot)
|
||||
};
|
||||
|
||||
await ViewModel.KeyboardShortcutHook(details);
|
||||
|
||||
if (InnerShellFrame.Content is BasePage activePage && activePage.AssociatedViewModel != null)
|
||||
{
|
||||
await activePage.AssociatedViewModel.KeyboardShortcutHook(details);
|
||||
}
|
||||
|
||||
if (details.Handled)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldIgnoreShortcut()
|
||||
{
|
||||
var focusedElement = FocusManager.GetFocusedElement(XamlRoot);
|
||||
|
||||
if (focusedElement is TextBox or AutoSuggestBox or PasswordBox or RichEditBox or ComboBox)
|
||||
return true;
|
||||
|
||||
if (focusedElement is FrameworkElement frameworkElement)
|
||||
{
|
||||
var typeName = frameworkElement.GetType().Name;
|
||||
if (typeName.Contains("WebView", StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static ModifierKeys GetCurrentModifierKeys()
|
||||
{
|
||||
var modifiers = ModifierKeys.None;
|
||||
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Control).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
modifiers |= ModifierKeys.Control;
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Menu).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
modifiers |= ModifierKeys.Alt;
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Shift).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
modifiers |= ModifierKeys.Shift;
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.LeftWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down) ||
|
||||
Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.RightWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
{
|
||||
modifiers |= ModifierKeys.Windows;
|
||||
}
|
||||
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
private static string NormalizeKey(Windows.System.VirtualKey key)
|
||||
{
|
||||
return key switch
|
||||
{
|
||||
Windows.System.VirtualKey.Control or
|
||||
Windows.System.VirtualKey.LeftControl or
|
||||
Windows.System.VirtualKey.RightControl or
|
||||
Windows.System.VirtualKey.Menu or
|
||||
Windows.System.VirtualKey.LeftMenu or
|
||||
Windows.System.VirtualKey.RightMenu or
|
||||
Windows.System.VirtualKey.Shift or
|
||||
Windows.System.VirtualKey.LeftShift or
|
||||
Windows.System.VirtualKey.RightShift or
|
||||
Windows.System.VirtualKey.LeftWindows or
|
||||
Windows.System.VirtualKey.RightWindows => string.Empty,
|
||||
_ => key.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
private void SynchronizeVisibleDateRangeCalendar()
|
||||
{
|
||||
if (!DispatcherQueue.HasThreadAccess)
|
||||
{
|
||||
var enqueued = DispatcherQueue.TryEnqueue(SynchronizeVisibleDateRangeCalendar);
|
||||
|
||||
if (!enqueued)
|
||||
throw new InvalidOperationException("Could not marshal visible date range calendar synchronization onto the UI thread.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_isSynchronizingVisibleDateRangeCalendar = true;
|
||||
|
||||
try
|
||||
{
|
||||
VisibleDateRangeCalendarView.SelectedDates.Clear();
|
||||
|
||||
var currentRange = ViewModel.CurrentVisibleRange;
|
||||
if (currentRange == null)
|
||||
return;
|
||||
|
||||
foreach (var date in currentRange.Dates)
|
||||
{
|
||||
VisibleDateRangeCalendarView.SelectedDates.Add(new DateTimeOffset(date.ToDateTime(TimeOnly.MinValue)));
|
||||
}
|
||||
|
||||
VisibleDateRangeCalendarView.SetDisplayDate(new DateTimeOffset(currentRange.AnchorDate.ToDateTime(TimeOnly.MinValue)));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSynchronizingVisibleDateRangeCalendar = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -568,27 +568,14 @@
|
||||
Text="{x:Bind domain:Translator.CalendarEventCompose_NewEventButton, Mode=OneTime}" />
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
|
||||
<Border
|
||||
x:Name="RangeSummaryCard"
|
||||
<muxc:CalendarView
|
||||
x:Name="VisibleDateRangeCalendarView"
|
||||
Grid.Row="1"
|
||||
Margin="16,0,16,12"
|
||||
Padding="12"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8">
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock
|
||||
FontWeight="SemiBold"
|
||||
Text="{x:Bind ViewModel.CalendarClient.VisibleDateRangeText, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
|
||||
<muxc:CalendarView
|
||||
x:Name="VisibleDateRangeCalendarView"
|
||||
HorizontalAlignment="Stretch"
|
||||
SelectedDatesChanged="VisibleDateRangeCalendarViewSelectedDatesChanged"
|
||||
SelectionMode="Multiple"
|
||||
Style="{StaticResource WinoCalendarViewStyle}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
Margin="12,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
SelectedDatesChanged="VisibleDateRangeCalendarViewSelectedDatesChanged"
|
||||
SelectionMode="Multiple"
|
||||
Style="{StaticResource WinoCalendarViewStyle}" />
|
||||
|
||||
<ListView
|
||||
x:Name="CalendarHostListView"
|
||||
|
||||
@@ -66,6 +66,7 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
|
||||
ViewModel.MailClient.PropertyChanged += MailClientPropertyChanged;
|
||||
ViewModel.CalendarClient.PropertyChanged += CalendarClientPropertyChanged;
|
||||
ViewModel.PropertyChanged += ViewModelPropertyChanged;
|
||||
ViewModel.PreferencesService.PreferenceChanged += PreferencesServiceChanged;
|
||||
ViewModel.StatePersistenceService.StatePropertyChanged += StatePersistenceServiceChanged;
|
||||
CalendarTypeSelector.RegisterPropertyChangedCallback(WinoCalendarTypeSelectorControl.SelectedTypeProperty, CalendarTypeSelectorSelectedTypeChanged);
|
||||
|
||||
@@ -561,6 +562,7 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
|
||||
|
||||
try
|
||||
{
|
||||
VisibleDateRangeCalendarView.FirstDayOfWeek = MapFirstDayOfWeek(ViewModel.PreferencesService.FirstDayOfWeek);
|
||||
VisibleDateRangeCalendarView.SelectedDates.Clear();
|
||||
|
||||
var currentRange = ViewModel.CalendarClient.CurrentVisibleRange;
|
||||
@@ -580,6 +582,27 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
|
||||
}
|
||||
}
|
||||
|
||||
private void PreferencesServiceChanged(object? sender, string propertyName)
|
||||
{
|
||||
if (propertyName == nameof(IPreferencesService.FirstDayOfWeek))
|
||||
{
|
||||
SynchronizeVisibleDateRangeCalendar();
|
||||
}
|
||||
}
|
||||
|
||||
private static Windows.Globalization.DayOfWeek MapFirstDayOfWeek(DayOfWeek dayOfWeek)
|
||||
=> dayOfWeek switch
|
||||
{
|
||||
DayOfWeek.Sunday => Windows.Globalization.DayOfWeek.Sunday,
|
||||
DayOfWeek.Monday => Windows.Globalization.DayOfWeek.Monday,
|
||||
DayOfWeek.Tuesday => Windows.Globalization.DayOfWeek.Tuesday,
|
||||
DayOfWeek.Wednesday => Windows.Globalization.DayOfWeek.Wednesday,
|
||||
DayOfWeek.Thursday => Windows.Globalization.DayOfWeek.Thursday,
|
||||
DayOfWeek.Friday => Windows.Globalization.DayOfWeek.Friday,
|
||||
DayOfWeek.Saturday => Windows.Globalization.DayOfWeek.Saturday,
|
||||
_ => Windows.Globalization.DayOfWeek.Monday
|
||||
};
|
||||
|
||||
private void ViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName != nameof(ViewModel.SelectedMenuItem) || !ViewModel.CurrentClient.HandlesNavigationSelection)
|
||||
|
||||
Reference in New Issue
Block a user