From f4bbf6eb73d4280e034e364f0654bf7bfa0f7f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Mon, 26 Aug 2024 01:07:51 +0200 Subject: [PATCH 1/7] New expander control. --- Wino.Mail/App.xaml | 2 + Wino.Mail/Controls/Advanced/WinoListView.cs | 3 +- .../MailItemDisplayInformationControl.xaml | 30 ++++--- .../MailItemDisplayInformationControl.xaml.cs | 23 +++-- Wino.Mail/Controls/WinoExpander.cs | 44 ++++++++-- Wino.Mail/Styles/WinoExpanderStyle.xaml | 86 +++++++++++++++++++ Wino.Mail/Styles/WinoExpanderStyle.xaml.cs | 12 +++ Wino.Mail/Views/MailListPage.xaml | 14 ++- Wino.Mail/Wino.Mail.csproj | 7 ++ 9 files changed, 176 insertions(+), 45 deletions(-) create mode 100644 Wino.Mail/Styles/WinoExpanderStyle.xaml create mode 100644 Wino.Mail/Styles/WinoExpanderStyle.xaml.cs diff --git a/Wino.Mail/App.xaml b/Wino.Mail/App.xaml index bf1fe890..d2d05a9c 100644 --- a/Wino.Mail/App.xaml +++ b/Wino.Mail/App.xaml @@ -19,7 +19,9 @@ + + diff --git a/Wino.Mail/Controls/Advanced/WinoListView.cs b/Wino.Mail/Controls/Advanced/WinoListView.cs index 10f215da..219f8800 100644 --- a/Wino.Mail/Controls/Advanced/WinoListView.cs +++ b/Wino.Mail/Controls/Advanced/WinoListView.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Windows.Input; using CommunityToolkit.Mvvm.Messaging; -using Microsoft.UI.Xaml.Controls; using MoreLinq; using Serilog; using Windows.UI.Xaml; @@ -356,7 +355,7 @@ namespace Wino.Controls.Advanced if (itemContainer is ListViewItem listItem) { - var expander = listItem.GetChildByName("ThreadExpander"); + var expander = listItem.GetChildByName("ThreadExpander"); if (expander != null) return expander.Content as WinoListView; diff --git a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml index 889f633d..c8f931aa 100644 --- a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml +++ b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml @@ -3,14 +3,18 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="using:Wino.Controls" - xmlns:enums="using:Wino.Core.Domain.Enums" xmlns:domain="using:Wino.Core.Domain" + xmlns:enums="using:Wino.Core.Domain.Enums" + xmlns:helpers="using:Wino.Helpers" + HorizontalAlignment="Stretch" + VerticalAlignment="Stretch" + HorizontalContentAlignment="Stretch" + VerticalContentAlignment="Stretch" FocusVisualMargin="8" FocusVisualPrimaryBrush="{StaticResource SystemControlRevealFocusVisualBrush}" FocusVisualPrimaryThickness="2" FocusVisualSecondaryBrush="{StaticResource SystemControlFocusVisualSecondaryBrush}" FocusVisualSecondaryThickness="1" - xmlns:helpers="using:Wino.Helpers" PointerEntered="ControlPointerEntered" PointerExited="ControlPointerExited"> @@ -25,26 +29,24 @@ - - - - - + + Canvas.ZIndex="9999" + Fill="{ThemeResource SystemAccentColor}" + Visibility="{x:Bind IsCustomFocused, Mode=OneWay}" /> - + @@ -243,7 +245,7 @@ - + @@ -255,7 +257,7 @@ - + diff --git a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs index 4b080e1c..8c8c77d8 100644 --- a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs +++ b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs @@ -1,6 +1,5 @@ using System.Numerics; using System.Windows.Input; -using Microsoft.UI.Xaml.Controls; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; @@ -21,7 +20,7 @@ namespace Wino.Controls public static readonly DependencyProperty IsCustomFocusedProperty = DependencyProperty.Register(nameof(IsCustomFocused), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); public static readonly DependencyProperty IsAvatarVisibleProperty = DependencyProperty.Register(nameof(IsAvatarVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); public static readonly DependencyProperty IsSubjectVisibleProperty = DependencyProperty.Register(nameof(IsSubjectVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); - public static readonly DependencyProperty ConnectedExpanderProperty = DependencyProperty.Register(nameof(ConnectedExpander), typeof(Expander), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null)); + public static readonly DependencyProperty ConnectedExpanderProperty = DependencyProperty.Register(nameof(ConnectedExpander), typeof(WinoExpander), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null)); public static readonly DependencyProperty LeftHoverActionProperty = DependencyProperty.Register(nameof(LeftHoverAction), typeof(MailOperation), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailOperation.None)); public static readonly DependencyProperty CenterHoverActionProperty = DependencyProperty.Register(nameof(CenterHoverAction), typeof(MailOperation), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailOperation.None)); public static readonly DependencyProperty RightHoverActionProperty = DependencyProperty.Register(nameof(RightHoverAction), typeof(MailOperation), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailOperation.None)); @@ -73,9 +72,9 @@ namespace Wino.Controls } - public Expander ConnectedExpander + public WinoExpander ConnectedExpander { - get { return (Expander)GetValue(ConnectedExpanderProperty); } + get { return (WinoExpander)GetValue(ConnectedExpanderProperty); } set { SetValue(ConnectedExpanderProperty, value); } } @@ -167,16 +166,16 @@ namespace Wino.Controls // Also hover action button clicks will be delegated here after the execution runs. // We should not expand the thread if the reason we are here is for hover actions. - if (tappedHandlingFlag) - { - tappedHandlingFlag = false; - e.Handled = true; - return; - } + //if (tappedHandlingFlag) + //{ + // tappedHandlingFlag = false; + // e.Handled = true; + // return; + //} - if (ConnectedExpander == null) return; + //if (ConnectedExpander == null) return; - ConnectedExpander.IsExpanded = !ConnectedExpander.IsExpanded; + //ConnectedExpander.IsExpanded = !ConnectedExpander.IsExpanded; } private void FirstActionClicked(object sender, RoutedEventArgs e) diff --git a/Wino.Mail/Controls/WinoExpander.cs b/Wino.Mail/Controls/WinoExpander.cs index e407b6f2..3254d9d9 100644 --- a/Wino.Mail/Controls/WinoExpander.cs +++ b/Wino.Mail/Controls/WinoExpander.cs @@ -1,17 +1,43 @@ -using Microsoft.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Markup; namespace Wino.Controls { - public class WinoExpander : Expander + [ContentProperty(Name = nameof(Content))] + public class WinoExpander : Control { - protected override void OnApplyTemplate() + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(nameof(Header), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null)); + public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null)); + public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register(nameof(IsExpanded), typeof(bool), typeof(WinoExpander), new PropertyMetadata(false, new PropertyChangedCallback(OnIsExpandedChanged))); + + public bool IsExpanded { - base.OnApplyTemplate(); - if (GetTemplateChild("ExpanderHeader") is ToggleButton toggleButton) - { - toggleButton.Padding = new Windows.UI.Xaml.Thickness(0, 4, 0, 4); - } + get { return (bool)GetValue(IsExpandedProperty); } + set { SetValue(IsExpandedProperty, value); } + } + + public UIElement Content + { + get { return (UIElement)GetValue(ContentProperty); } + set { SetValue(ContentProperty, value); } + } + + public UIElement Header + { + get { return (UIElement)GetValue(HeaderProperty); } + set { SetValue(HeaderProperty, value); } + } + + private static void OnIsExpandedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoExpander control) + control.UpdateVisualStates(); + } + + private void UpdateVisualStates() + { + VisualStateManager.GoToState(this, IsExpanded ? "Expanded" : "Collapsed", true); } } } diff --git a/Wino.Mail/Styles/WinoExpanderStyle.xaml b/Wino.Mail/Styles/WinoExpanderStyle.xaml new file mode 100644 index 00000000..73358147 --- /dev/null +++ b/Wino.Mail/Styles/WinoExpanderStyle.xaml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail/Styles/WinoExpanderStyle.xaml.cs b/Wino.Mail/Styles/WinoExpanderStyle.xaml.cs new file mode 100644 index 00000000..817d086d --- /dev/null +++ b/Wino.Mail/Styles/WinoExpanderStyle.xaml.cs @@ -0,0 +1,12 @@ +using Windows.UI.Xaml; + +namespace Wino.Styles +{ + partial class WinoExpanderStyle : ResourceDictionary + { + public WinoExpanderStyle() + { + this.InitializeComponent(); + } + } +} diff --git a/Wino.Mail/Views/MailListPage.xaml b/Wino.Mail/Views/MailListPage.xaml index 61328647..a975f51a 100644 --- a/Wino.Mail/Views/MailListPage.xaml +++ b/Wino.Mail/Views/MailListPage.xaml @@ -158,18 +158,14 @@ - + - - + + - + @@ -273,6 +269,7 @@ x:Name="MailListContainer" Grid.Column="0" Padding="5,0,0,0" + HorizontalAlignment="Stretch" Background="{ThemeResource WinoContentZoneBackgroud}" BorderBrush="{StaticResource CardStrokeColorDefaultBrush}" BorderThickness="1" @@ -570,6 +567,7 @@ CustomMessageDialogStyles.xaml + + WinoExpanderStyle.xaml + @@ -529,6 +532,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile From b9a1756f90e44a7cdd56b652bdbf35c528db638d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Fri, 30 Aug 2024 02:20:16 +0200 Subject: [PATCH 2/7] Moving expander chevron to mail display control. --- Wino.Mail/Controls/Advanced/WinoListView.cs | 2 +- .../MailItemDisplayInformationControl.xaml | 28 +++++++++++++++++-- .../MailItemDisplayInformationControl.xaml.cs | 14 ++++++++++ Wino.Mail/Views/MailListPage.xaml | 2 ++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Wino.Mail/Controls/Advanced/WinoListView.cs b/Wino.Mail/Controls/Advanced/WinoListView.cs index 219f8800..d50fe249 100644 --- a/Wino.Mail/Controls/Advanced/WinoListView.cs +++ b/Wino.Mail/Controls/Advanced/WinoListView.cs @@ -310,7 +310,7 @@ namespace Wino.Controls.Advanced } else if (addedItem is ThreadMailItemViewModel threadMailItemViewModel) { - threadMailItemViewModel.IsThreadExpanded = true; + // threadMailItemViewModel.IsThreadExpanded = true; // Don't select thread containers. SelectedItems.Remove(addedItem); diff --git a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml index c8f931aa..42e65bf8 100644 --- a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml +++ b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml @@ -147,20 +147,31 @@ - + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs index 8c8c77d8..4d1c9361 100644 --- a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs +++ b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs @@ -28,6 +28,20 @@ namespace Wino.Controls public static readonly DependencyProperty MailItemProperty = DependencyProperty.Register(nameof(MailItem), typeof(IMailItem), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null)); public static readonly DependencyProperty IsHoverActionsEnabledProperty = DependencyProperty.Register(nameof(IsHoverActionsEnabled), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); public static readonly DependencyProperty Prefer24HourTimeFormatProperty = DependencyProperty.Register(nameof(Prefer24HourTimeFormat), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + public static readonly DependencyProperty IsThreadExpanderVisibleProperty = DependencyProperty.Register(nameof(IsThreadExpanderVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + public static readonly DependencyProperty IsThreadExpandedProperty = DependencyProperty.Register(nameof(IsThreadExpanded), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + + public bool IsThreadExpanded + { + get { return (bool)GetValue(IsThreadExpandedProperty); } + set { SetValue(IsThreadExpandedProperty, value); } + } + + public bool IsThreadExpanderVisible + { + get { return (bool)GetValue(IsThreadExpanderVisibleProperty); } + set { SetValue(IsThreadExpanderVisibleProperty, value); } + } public bool Prefer24HourTimeFormat { diff --git a/Wino.Mail/Views/MailListPage.xaml b/Wino.Mail/Views/MailListPage.xaml index a975f51a..276c9a59 100644 --- a/Wino.Mail/Views/MailListPage.xaml +++ b/Wino.Mail/Views/MailListPage.xaml @@ -176,6 +176,8 @@ IsAvatarVisible="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowSenderPicturesEnabled, Mode=OneWay}" IsHitTestVisible="True" IsHoverActionsEnabled="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsHoverActionsEnabled, Mode=OneWay}" + IsThreadExpanded="{x:Bind IsThreadExpanded, Mode=TwoWay}" + IsThreadExpanderVisible="True" LeftHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.LeftHoverAction, Mode=OneWay}" MailItem="{x:Bind MailItem, Mode=OneWay}" Prefer24HourTimeFormat="{Binding ElementName=root, Path=ViewModel.PreferencesService.Prefer24HourTimeFormat, Mode=OneWay}" From 6bb09f10d2bab6cb709207f4ac95ef83923feeb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sat, 31 Aug 2024 03:18:43 +0200 Subject: [PATCH 3/7] Finished wino expander implementation. --- Wino.Core/MenuItems/MenuItemCollection.cs | 8 +- Wino.Mail/Controls/Advanced/WinoListView.cs | 47 ++++---- Wino.Mail/Controls/ImagePreviewControl.cs | 2 - .../MailItemDisplayInformationControl.xaml | 34 ++++-- .../MailItemDisplayInformationControl.xaml.cs | 40 +++---- Wino.Mail/Controls/WinoExpander.cs | 90 ++++++++++++++-- Wino.Mail/Styles/WinoExpanderStyle.xaml | 101 +++++++++--------- Wino.Mail/Styles/WinoExpanderStyle.xaml.cs | 2 +- Wino.Mail/Wino.Mail.csproj | 2 +- 9 files changed, 209 insertions(+), 117 deletions(-) diff --git a/Wino.Core/MenuItems/MenuItemCollection.cs b/Wino.Core/MenuItems/MenuItemCollection.cs index d6f50cb3..c96351fe 100644 --- a/Wino.Core/MenuItems/MenuItemCollection.cs +++ b/Wino.Core/MenuItems/MenuItemCollection.cs @@ -192,10 +192,12 @@ namespace Wino.Core.MenuItems item.IsExpanded = false; item.IsSelected = false; - Remove(item); + try + { + Remove(item); + } + catch (Exception) { } }); - - // RemoveRange(itemsToRemove); } } } diff --git a/Wino.Mail/Controls/Advanced/WinoListView.cs b/Wino.Mail/Controls/Advanced/WinoListView.cs index d50fe249..c3289800 100644 --- a/Wino.Mail/Controls/Advanced/WinoListView.cs +++ b/Wino.Mail/Controls/Advanced/WinoListView.cs @@ -48,7 +48,7 @@ namespace Wino.Controls.Advanced } public static readonly DependencyProperty LoadMoreCommandProperty = DependencyProperty.Register(nameof(LoadMoreCommand), typeof(ICommand), typeof(WinoListView), new PropertyMetadata(null)); - public static readonly DependencyProperty IsThreadListViewProperty = DependencyProperty.Register(nameof(IsThreadListView), typeof(bool), typeof(WinoListView), new PropertyMetadata(false)); + public static readonly DependencyProperty IsThreadListViewProperty = DependencyProperty.Register(nameof(IsThreadListView), typeof(bool), typeof(WinoListView), new PropertyMetadata(false, new PropertyChangedCallback(OnIsThreadViewChanged))); public static readonly DependencyProperty ItemDeletedCommandProperty = DependencyProperty.Register(nameof(ItemDeletedCommand), typeof(ICommand), typeof(WinoListView), new PropertyMetadata(null)); public WinoListView() @@ -64,7 +64,6 @@ namespace Wino.Controls.Advanced DragItemsCompleted += ItemDragCompleted; DragItemsStarting += ItemDragStarting; SelectionChanged += SelectedItemsChanged; - ItemClick += MailItemClicked; ProcessKeyboardAccelerators += ProcessDelKey; } @@ -84,6 +83,22 @@ namespace Wino.Controls.Advanced internalScrollviewer.ViewChanged += InternalScrollVeiwerViewChanged; } + private static void OnIsThreadViewChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoListView winoListView) + { + winoListView.AdjustThreadViewContainerVisuals(); + } + } + + private void AdjustThreadViewContainerVisuals() + { + if (IsThreadListView) + { + ItemContainerTransitions.Clear(); + } + } + private double lastestRaisedOffset = 0; private int lastItemSize = 0; @@ -159,19 +174,6 @@ namespace Wino.Controls.Advanced } } - private void MailItemClicked(object sender, ItemClickEventArgs e) - { - if (e.ClickedItem is ThreadMailItemViewModel clickedThread) - { - clickedThread.IsThreadExpanded = !clickedThread.IsThreadExpanded; - - if (!clickedThread.IsThreadExpanded) - { - SelectedItems.Clear(); - } - } - } - public void ChangeSelectionMode(ListViewSelectionMode selectionMode) { SelectionMode = selectionMode; @@ -293,6 +295,10 @@ namespace Wino.Controls.Advanced removedMailItemViewModel.IsSelected = false; WeakReferenceMessenger.Default.Send(new MailItemSelectionRemovedEvent(removedMailItemViewModel)); } + else if (removedItem is ThreadMailItemViewModel removedThreadItemViewModel) + { + removedThreadItemViewModel.IsThreadExpanded = false; + } } } @@ -313,7 +319,7 @@ namespace Wino.Controls.Advanced // threadMailItemViewModel.IsThreadExpanded = true; // Don't select thread containers. - SelectedItems.Remove(addedItem); + // SelectedItems.Remove(addedItem); } } } @@ -341,10 +347,10 @@ namespace Wino.Controls.Advanced { // Tell main list view to unselect all his items. - if (SelectedItems[0] is MailItemViewModel selectedMailItemViewModel) - { - WeakReferenceMessenger.Default.Send(new ResetSingleMailItemSelectionEvent(selectedMailItemViewModel)); - } + //if (SelectedItems[0] is MailItemViewModel selectedMailItemViewModel) + //{ + // WeakReferenceMessenger.Default.Send(new ResetSingleMailItemSelectionEvent(selectedMailItemViewModel)); + //} } } } @@ -369,7 +375,6 @@ namespace Wino.Controls.Advanced DragItemsCompleted -= ItemDragCompleted; DragItemsStarting -= ItemDragStarting; SelectionChanged -= SelectedItemsChanged; - ItemClick -= MailItemClicked; ProcessKeyboardAccelerators -= ProcessDelKey; if (internalScrollviewer != null) diff --git a/Wino.Mail/Controls/ImagePreviewControl.cs b/Wino.Mail/Controls/ImagePreviewControl.cs index f8edd39f..344e1057 100644 --- a/Wino.Mail/Controls/ImagePreviewControl.cs +++ b/Wino.Mail/Controls/ImagePreviewControl.cs @@ -80,8 +80,6 @@ namespace Wino.Controls control.UpdateInformation(); } - - private async void UpdateInformation() { if (KnownHostImage == null || InitialsGrid == null || InitialsTextblock == null || (string.IsNullOrEmpty(FromName) && string.IsNullOrEmpty(FromAddress))) diff --git a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml index 42e65bf8..d93700a5 100644 --- a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml +++ b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml @@ -2,10 +2,12 @@ x:Class="Wino.Controls.MailItemDisplayInformationControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals" xmlns:controls="using:Wino.Controls" xmlns:domain="using:Wino.Core.Domain" xmlns:enums="using:Wino.Core.Domain.Enums" xmlns:helpers="using:Wino.Helpers" + xmlns:muxc="using:Microsoft.UI.Xaml.Controls" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" @@ -154,13 +156,29 @@ - + + + + + + + - + diff --git a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs index 4d1c9361..8d0cdd8c 100644 --- a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs +++ b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs @@ -2,7 +2,6 @@ using System.Windows.Input; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Input; using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Models.MailItem; @@ -29,7 +28,7 @@ namespace Wino.Controls public static readonly DependencyProperty IsHoverActionsEnabledProperty = DependencyProperty.Register(nameof(IsHoverActionsEnabled), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); public static readonly DependencyProperty Prefer24HourTimeFormatProperty = DependencyProperty.Register(nameof(Prefer24HourTimeFormat), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); public static readonly DependencyProperty IsThreadExpanderVisibleProperty = DependencyProperty.Register(nameof(IsThreadExpanderVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); - public static readonly DependencyProperty IsThreadExpandedProperty = DependencyProperty.Register(nameof(IsThreadExpanded), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + public static readonly DependencyProperty IsThreadExpandedProperty = DependencyProperty.Register(nameof(IsThreadExpanded), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false, new PropertyChangedCallback(OnIsExpandedChanged))); public bool IsThreadExpanded { @@ -85,7 +84,6 @@ namespace Wino.Controls set { SetValue(RightHoverActionProperty, value); } } - public WinoExpander ConnectedExpander { get { return (WinoExpander)GetValue(ConnectedExpanderProperty); } @@ -122,8 +120,6 @@ namespace Wino.Controls set { SetValue(DisplayModeProperty, value); } } - private bool tappedHandlingFlag = false; - public MailItemDisplayInformationControl() { this.InitializeComponent(); @@ -142,6 +138,20 @@ namespace Wino.Controls RootContainerVisualWrapper.SizeChanged += (s, e) => leftBackgroundVisual.Size = e.NewSize.ToVector2(); } + private static void OnIsExpandedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is MailItemDisplayInformationControl control) + { + control.AdjustRotation(); + } + } + + private void AdjustRotation() + { + + // ExpanderChevronGrid.Rotation = IsThreadExpanded ? 45 : 0; + } + private void ControlPointerEntered(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e) { if (IsHoverActionsEnabled) @@ -169,29 +179,9 @@ namespace Wino.Controls if (package == null) return; - tappedHandlingFlag = true; - HoverActionExecutedCommand?.Execute(package); } - private void ThreadHeaderTapped(object sender, TappedRoutedEventArgs e) - { - // Due to CanDrag=True, outer expander doesn't get the click event and it doesn't expand. We expand here manually. - // Also hover action button clicks will be delegated here after the execution runs. - // We should not expand the thread if the reason we are here is for hover actions. - - //if (tappedHandlingFlag) - //{ - // tappedHandlingFlag = false; - // e.Handled = true; - // return; - //} - - //if (ConnectedExpander == null) return; - - //ConnectedExpander.IsExpanded = !ConnectedExpander.IsExpanded; - } - private void FirstActionClicked(object sender, RoutedEventArgs e) { ExecuteHoverAction(LeftHoverAction); diff --git a/Wino.Mail/Controls/WinoExpander.cs b/Wino.Mail/Controls/WinoExpander.cs index 3254d9d9..cf24b5a8 100644 --- a/Wino.Mail/Controls/WinoExpander.cs +++ b/Wino.Mail/Controls/WinoExpander.cs @@ -1,5 +1,7 @@ -using Windows.UI.Xaml; +using CommunityToolkit.Diagnostics; +using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Hosting; using Windows.UI.Xaml.Markup; namespace Wino.Controls @@ -7,15 +9,18 @@ namespace Wino.Controls [ContentProperty(Name = nameof(Content))] public class WinoExpander : Control { + private const string PART_HeaderGrid = "HeaderGrid"; + private const string PART_ContentAreaWrapper = "ContentAreaWrapper"; + private const string PART_ContentArea = "ContentArea"; + + private ContentControl HeaderGrid; + private ContentControl ContentArea; + private Grid ContentAreaWrapper; + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(nameof(Header), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null)); public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null)); public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register(nameof(IsExpanded), typeof(bool), typeof(WinoExpander), new PropertyMetadata(false, new PropertyChangedCallback(OnIsExpandedChanged))); - - public bool IsExpanded - { - get { return (bool)GetValue(IsExpandedProperty); } - set { SetValue(IsExpandedProperty, value); } - } + public static readonly DependencyProperty TemplateSettingsProperty = DependencyProperty.Register(nameof(TemplateSettings), typeof(WinoExpanderTemplateSettings), typeof(WinoExpander), new PropertyMetadata(new WinoExpanderTemplateSettings())); public UIElement Content { @@ -23,12 +28,54 @@ namespace Wino.Controls set { SetValue(ContentProperty, value); } } + public WinoExpanderTemplateSettings TemplateSettings + { + get { return (WinoExpanderTemplateSettings)GetValue(TemplateSettingsProperty); } + set { SetValue(TemplateSettingsProperty, value); } + } + + public bool IsExpanded + { + get { return (bool)GetValue(IsExpandedProperty); } + set { SetValue(IsExpandedProperty, value); } + } + public UIElement Header { get { return (UIElement)GetValue(HeaderProperty); } set { SetValue(HeaderProperty, value); } } + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + HeaderGrid = GetTemplateChild(PART_HeaderGrid) as ContentControl; + ContentAreaWrapper = GetTemplateChild(PART_ContentAreaWrapper) as Grid; + ContentArea = GetTemplateChild(PART_ContentArea) as ContentControl; + + Guard.IsNotNull(HeaderGrid, nameof(HeaderGrid)); + Guard.IsNotNull(ContentAreaWrapper, nameof(ContentAreaWrapper)); + Guard.IsNotNull(ContentArea, nameof(ContentArea)); + + var clipComposition = ElementCompositionPreview.GetElementVisual(ContentAreaWrapper); + clipComposition.Clip = clipComposition.Compositor.CreateInsetClip(); + + ContentAreaWrapper.SizeChanged += ContentSizeChanged; + HeaderGrid.Tapped += HeaderTapped; + } + + private void ContentSizeChanged(object sender, SizeChangedEventArgs e) + { + TemplateSettings.ContentHeight = e.NewSize.Height; + TemplateSettings.NegativeContentHeight = -1 * (double)e.NewSize.Height; + } + + private void HeaderTapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) + { + IsExpanded = !IsExpanded; + } + private static void OnIsExpandedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { if (obj is WinoExpander control) @@ -40,4 +87,33 @@ namespace Wino.Controls VisualStateManager.GoToState(this, IsExpanded ? "Expanded" : "Collapsed", true); } } + + #region Settings + + public class WinoExpanderTemplateSettings : DependencyObject + { + public static readonly DependencyProperty HeaderHeightProperty = DependencyProperty.Register(nameof(HeaderHeight), typeof(double), typeof(WinoExpanderTemplateSettings), new PropertyMetadata(0.0)); + public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.Register(nameof(ContentHeight), typeof(double), typeof(WinoExpanderTemplateSettings), new PropertyMetadata(0.0)); + public static readonly DependencyProperty NegativeContentHeightProperty = DependencyProperty.Register(nameof(NegativeContentHeight), typeof(double), typeof(WinoExpanderTemplateSettings), new PropertyMetadata(0.0)); + + public double NegativeContentHeight + { + get { return (double)GetValue(NegativeContentHeightProperty); } + set { SetValue(NegativeContentHeightProperty, value); } + } + + public double HeaderHeight + { + get { return (double)GetValue(HeaderHeightProperty); } + set { SetValue(HeaderHeightProperty, value); } + } + + public double ContentHeight + { + get { return (double)GetValue(ContentHeightProperty); } + set { SetValue(ContentHeightProperty, value); } + } + } + + #endregion } diff --git a/Wino.Mail/Styles/WinoExpanderStyle.xaml b/Wino.Mail/Styles/WinoExpanderStyle.xaml index 73358147..0e455ff9 100644 --- a/Wino.Mail/Styles/WinoExpanderStyle.xaml +++ b/Wino.Mail/Styles/WinoExpanderStyle.xaml @@ -13,65 +13,68 @@ + - - - - - - - - - - - - - - - - - - + Background="{TemplateBinding Background}" + Content="{TemplateBinding Header}" /> + + + + + + + + + - + + + + + + + + + + + + + - - - - + + + + + + + + + + + diff --git a/Wino.Mail/Styles/WinoExpanderStyle.xaml.cs b/Wino.Mail/Styles/WinoExpanderStyle.xaml.cs index 817d086d..dd8a56fc 100644 --- a/Wino.Mail/Styles/WinoExpanderStyle.xaml.cs +++ b/Wino.Mail/Styles/WinoExpanderStyle.xaml.cs @@ -6,7 +6,7 @@ namespace Wino.Styles { public WinoExpanderStyle() { - this.InitializeComponent(); + InitializeComponent(); } } } diff --git a/Wino.Mail/Wino.Mail.csproj b/Wino.Mail/Wino.Mail.csproj index 76655829..8d9e62e9 100644 --- a/Wino.Mail/Wino.Mail.csproj +++ b/Wino.Mail/Wino.Mail.csproj @@ -536,8 +536,8 @@ MSBuild:Compile - Designer MSBuild:Compile + Designer Designer From 8fb4735fc2cb7d52534697770fe5804352453969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sat, 31 Aug 2024 03:37:04 +0200 Subject: [PATCH 4/7] Handling hover action tap delegates. --- .../MailItemDisplayInformationControl.xaml.cs | 25 +++++++------------ Wino.Mail/Controls/WinoExpander.cs | 10 ++++++++ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs index 8d0cdd8c..5e104b0b 100644 --- a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs +++ b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using System.Linq; +using System.Numerics; using System.Windows.Input; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -14,6 +15,8 @@ namespace Wino.Controls { public ImagePreviewControl GetImagePreviewControl() => ContactImage; + public bool IsRunningHoverAction { get; set; } + public static readonly DependencyProperty DisplayModeProperty = DependencyProperty.Register(nameof(DisplayMode), typeof(MailListDisplayMode), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailListDisplayMode.Spacious)); public static readonly DependencyProperty ShowPreviewTextProperty = DependencyProperty.Register(nameof(ShowPreviewText), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); public static readonly DependencyProperty IsCustomFocusedProperty = DependencyProperty.Register(nameof(IsCustomFocused), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); @@ -28,7 +31,7 @@ namespace Wino.Controls public static readonly DependencyProperty IsHoverActionsEnabledProperty = DependencyProperty.Register(nameof(IsHoverActionsEnabled), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); public static readonly DependencyProperty Prefer24HourTimeFormatProperty = DependencyProperty.Register(nameof(Prefer24HourTimeFormat), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); public static readonly DependencyProperty IsThreadExpanderVisibleProperty = DependencyProperty.Register(nameof(IsThreadExpanderVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); - public static readonly DependencyProperty IsThreadExpandedProperty = DependencyProperty.Register(nameof(IsThreadExpanded), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false, new PropertyChangedCallback(OnIsExpandedChanged))); + public static readonly DependencyProperty IsThreadExpandedProperty = DependencyProperty.Register(nameof(IsThreadExpanded), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); public bool IsThreadExpanded { @@ -138,20 +141,6 @@ namespace Wino.Controls RootContainerVisualWrapper.SizeChanged += (s, e) => leftBackgroundVisual.Size = e.NewSize.ToVector2(); } - private static void OnIsExpandedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) - { - if (obj is MailItemDisplayInformationControl control) - { - control.AdjustRotation(); - } - } - - private void AdjustRotation() - { - - // ExpanderChevronGrid.Rotation = IsThreadExpanded ? 45 : 0; - } - private void ControlPointerEntered(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e) { if (IsHoverActionsEnabled) @@ -170,12 +159,16 @@ namespace Wino.Controls private void ExecuteHoverAction(MailOperation operation) { + IsRunningHoverAction = true; + MailOperationPreperationRequest package = null; if (MailItem is MailCopy mailCopy) package = new MailOperationPreperationRequest(operation, mailCopy, toggleExecution: true); else if (MailItem is ThreadMailItemViewModel threadMailItemViewModel) package = new MailOperationPreperationRequest(operation, threadMailItemViewModel.GetMailCopies(), toggleExecution: true); + else if (MailItem is ThreadMailItem threadMailItem) + package = new MailOperationPreperationRequest(operation, threadMailItem.ThreadItems.Cast().Select(a => a.MailCopy), toggleExecution: true); if (package == null) return; diff --git a/Wino.Mail/Controls/WinoExpander.cs b/Wino.Mail/Controls/WinoExpander.cs index cf24b5a8..c286ee0e 100644 --- a/Wino.Mail/Controls/WinoExpander.cs +++ b/Wino.Mail/Controls/WinoExpander.cs @@ -73,6 +73,16 @@ namespace Wino.Controls private void HeaderTapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) { + // Tapped is delegated from executing hover action like flag or delete. + // No need to toggle the expander. + + if (Header is MailItemDisplayInformationControl itemDisplayInformationControl && + itemDisplayInformationControl.IsRunningHoverAction) + { + itemDisplayInformationControl.IsRunningHoverAction = false; + return; + } + IsExpanded = !IsExpanded; } From ee6249bb179486c2f0d96ef9eececd1181a3e4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sat, 31 Aug 2024 15:08:43 +0200 Subject: [PATCH 5/7] Selecting first mail when thread is expanded. --- Wino.Mail/Controls/Advanced/WinoListView.cs | 44 +++++++++++++++++++-- Wino.Mail/Extensions/UtilExtensions.cs | 3 +- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Wino.Mail/Controls/Advanced/WinoListView.cs b/Wino.Mail/Controls/Advanced/WinoListView.cs index c3289800..85e135a9 100644 --- a/Wino.Mail/Controls/Advanced/WinoListView.cs +++ b/Wino.Mail/Controls/Advanced/WinoListView.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using System.Windows.Input; using CommunityToolkit.Mvvm.Messaging; using MoreLinq; @@ -47,6 +48,13 @@ namespace Wino.Controls.Advanced set { SetValue(LoadMoreCommandProperty, value); } } + public bool IsThreadScrollingEnabled + { + get { return (bool)GetValue(IsThreadScrollingEnabledProperty); } + set { SetValue(IsThreadScrollingEnabledProperty, value); } + } + + public static readonly DependencyProperty IsThreadScrollingEnabledProperty = DependencyProperty.Register(nameof(IsThreadScrollingEnabled), typeof(bool), typeof(WinoListView), new PropertyMetadata(false)); public static readonly DependencyProperty LoadMoreCommandProperty = DependencyProperty.Register(nameof(LoadMoreCommand), typeof(ICommand), typeof(WinoListView), new PropertyMetadata(null)); public static readonly DependencyProperty IsThreadListViewProperty = DependencyProperty.Register(nameof(IsThreadListView), typeof(bool), typeof(WinoListView), new PropertyMetadata(false, new PropertyChangedCallback(OnIsThreadViewChanged))); public static readonly DependencyProperty ItemDeletedCommandProperty = DependencyProperty.Register(nameof(ItemDeletedCommand), typeof(ICommand), typeof(WinoListView), new PropertyMetadata(null)); @@ -316,10 +324,19 @@ namespace Wino.Controls.Advanced } else if (addedItem is ThreadMailItemViewModel threadMailItemViewModel) { - // threadMailItemViewModel.IsThreadExpanded = true; + if (IsThreadScrollingEnabled) + { + if (internalScrollviewer != null && ContainerFromItem(threadMailItemViewModel) is FrameworkElement threadFrameworkElement) + { + internalScrollviewer.ScrollToElement(threadFrameworkElement, true, true, bringToTopOrLeft: true); + } + } - // Don't select thread containers. - // SelectedItems.Remove(addedItem); + // Try to select first item. + if (GetThreadInternalListView(threadMailItemViewModel) is WinoListView internalListView) + { + internalListView.SelectFirstItem(); + } } } } @@ -355,6 +372,27 @@ namespace Wino.Controls.Advanced } } + public async void SelectFirstItem() + { + if (Items.Count > 0) + { + if (Items[0] is MailItemViewModel firstMailItemViewModel) + { + // Make sure the invisible container is realized. + await Task.Delay(250); + + if (ContainerFromItem(firstMailItemViewModel) is ListViewItem firstItemContainer) + { + firstItemContainer.IsSelected = true; + } + + firstMailItemViewModel.IsSelected = true; + + // WeakReferenceMessenger.Default.Send(new MailItemSelectedEvent(firstMailItemViewModel)); + } + } + } + private WinoListView GetThreadInternalListView(ThreadMailItemViewModel threadMailItemViewModel) { var itemContainer = ContainerFromItem(threadMailItemViewModel); diff --git a/Wino.Mail/Extensions/UtilExtensions.cs b/Wino.Mail/Extensions/UtilExtensions.cs index bfbea266..50367afc 100644 --- a/Wino.Mail/Extensions/UtilExtensions.cs +++ b/Wino.Mail/Extensions/UtilExtensions.cs @@ -93,7 +93,8 @@ namespace Wino.Extensions if (isVerticalScrolling) { - scrollViewer.ChangeView(null, position.Y, zoomFactor, !smoothScrolling); + // Accomodate for additional header. + scrollViewer.ChangeView(null, Math.Max(0, position.Y - 48), zoomFactor, !smoothScrolling); } else { From 155df59b1d8b16f3537a6beda2b5c5c543f0035c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sat, 31 Aug 2024 16:11:11 +0200 Subject: [PATCH 6/7] Increase pre-defined size to fit mail icon changes. --- Wino.Mail/Controls/MailItemDisplayInformationControl.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml index d93700a5..307b111a 100644 --- a/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml +++ b/Wino.Mail/Controls/MailItemDisplayInformationControl.xaml @@ -262,7 +262,7 @@ - + @@ -274,7 +274,7 @@ - + From e612f2c28104c2454a30a2734946f7247bdef681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sat, 31 Aug 2024 16:11:19 +0200 Subject: [PATCH 7/7] Remove redundant code. --- Wino.Mail/Controls/Advanced/WinoListView.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Wino.Mail/Controls/Advanced/WinoListView.cs b/Wino.Mail/Controls/Advanced/WinoListView.cs index 00f21870..bd8e4d56 100644 --- a/Wino.Mail/Controls/Advanced/WinoListView.cs +++ b/Wino.Mail/Controls/Advanced/WinoListView.cs @@ -358,18 +358,6 @@ namespace Wino.Controls.Advanced }); } } - else - { - if (SelectionMode == ListViewSelectionMode.Extended && SelectedItems.Count == 1) - { - // Tell main list view to unselect all his items. - - //if (SelectedItems[0] is MailItemViewModel selectedMailItemViewModel) - //{ - // WeakReferenceMessenger.Default.Send(new ResetSingleMailItemSelectionEvent(selectedMailItemViewModel)); - //} - } - } } public async void SelectFirstItem() @@ -387,8 +375,6 @@ namespace Wino.Controls.Advanced } firstMailItemViewModel.IsSelected = true; - - // WeakReferenceMessenger.Default.Send(new MailItemSelectedEvent(firstMailItemViewModel)); } } }